diff --git a/.DS_Store b/.DS_Store index 90ea33c6..f4f05c71 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/.env.example b/.env.example new file mode 100644 index 00000000..02eca612 --- /dev/null +++ b/.env.example @@ -0,0 +1,269 @@ +SERVER_TYPE=http +SERVER_PORT=8080 +# Server URL - Set your application url +SERVER_URL=http://localhost:8080 + +SENTRY_DSN= + +# Cors - * for all or set separate by commas - ex.: 'yourdomain1.com, yourdomain2.com' +CORS_ORIGIN=* +CORS_METHODS=GET,POST,PUT,DELETE +CORS_CREDENTIALS=true + +# Determine the logs to be displayed +LOG_LEVEL=ERROR,WARN,DEBUG,INFO,LOG,VERBOSE,DARK,WEBHOOKS,WEBSOCKET +LOG_COLOR=true +# Log Baileys - "fatal" | "error" | "warn" | "info" | "debug" | "trace" +LOG_BAILEYS=error + +# Set the maximum number of listeners that can be registered for an event +EVENT_EMITTER_MAX_LISTENERS=50 + +# Determine how long the instance should be deleted from memory in case of no connection. +# Default time: 5 minutes +# If you don't even want an expiration, enter the value false +DEL_INSTANCE=false + +# Provider: postgresql | mysql +DATABASE_PROVIDER=postgresql +DATABASE_CONNECTION_URI='postgresql://user:pass@postgres:5432/evolution?schema=public' +# Client name for the database connection +# It is used to separate an API installation from another that uses the same database. +DATABASE_CONNECTION_CLIENT_NAME=evolution_exchange + +# Choose the data you want to save in the application's database +DATABASE_SAVE_DATA_INSTANCE=true +DATABASE_SAVE_DATA_NEW_MESSAGE=true +DATABASE_SAVE_MESSAGE_UPDATE=true +DATABASE_SAVE_DATA_CONTACTS=true +DATABASE_SAVE_DATA_CHATS=true +DATABASE_SAVE_DATA_LABELS=true +DATABASE_SAVE_DATA_HISTORIC=true +DATABASE_SAVE_IS_ON_WHATSAPP=true +DATABASE_SAVE_IS_ON_WHATSAPP_DAYS=7 +DATABASE_DELETE_MESSAGE=true + +# RabbitMQ - Environment variables +RABBITMQ_ENABLED=false +RABBITMQ_URI=amqp://localhost +RABBITMQ_EXCHANGE_NAME=evolution +# Global events - By enabling this variable, events from all instances are sent in the same event queue. +RABBITMQ_GLOBAL_ENABLED=false +# Prefix key to queue name +RABBITMQ_PREFIX_KEY=evolution +# Choose the events you want to send to RabbitMQ +RABBITMQ_EVENTS_APPLICATION_STARTUP=false +RABBITMQ_EVENTS_INSTANCE_CREATE=false +RABBITMQ_EVENTS_INSTANCE_DELETE=false +RABBITMQ_EVENTS_QRCODE_UPDATED=false +RABBITMQ_EVENTS_MESSAGES_SET=false +RABBITMQ_EVENTS_MESSAGES_UPSERT=false +RABBITMQ_EVENTS_MESSAGES_EDITED=false +RABBITMQ_EVENTS_MESSAGES_UPDATE=false +RABBITMQ_EVENTS_MESSAGES_DELETE=false +RABBITMQ_EVENTS_SEND_MESSAGE=false +RABBITMQ_EVENTS_CONTACTS_SET=false +RABBITMQ_EVENTS_CONTACTS_UPSERT=false +RABBITMQ_EVENTS_CONTACTS_UPDATE=false +RABBITMQ_EVENTS_PRESENCE_UPDATE=false +RABBITMQ_EVENTS_CHATS_SET=false +RABBITMQ_EVENTS_CHATS_UPSERT=false +RABBITMQ_EVENTS_CHATS_UPDATE=false +RABBITMQ_EVENTS_CHATS_DELETE=false +RABBITMQ_EVENTS_GROUPS_UPSERT=false +RABBITMQ_EVENTS_GROUP_UPDATE=false +RABBITMQ_EVENTS_GROUP_PARTICIPANTS_UPDATE=false +RABBITMQ_EVENTS_CONNECTION_UPDATE=false +RABBITMQ_EVENTS_REMOVE_INSTANCE=false +RABBITMQ_EVENTS_LOGOUT_INSTANCE=false +RABBITMQ_EVENTS_CALL=false +RABBITMQ_EVENTS_TYPEBOT_START=false +RABBITMQ_EVENTS_TYPEBOT_CHANGE_STATUS=false + +# SQS - Environment variables +SQS_ENABLED=false +SQS_ACCESS_KEY_ID= +SQS_SECRET_ACCESS_KEY= +SQS_ACCOUNT_ID= +SQS_REGION= + +# Websocket - Environment variables +WEBSOCKET_ENABLED=false +WEBSOCKET_GLOBAL_EVENTS=false + +# Pusher - Environment variables +PUSHER_ENABLED=false +PUSHER_GLOBAL_ENABLED=false +PUSHER_GLOBAL_APP_ID= +PUSHER_GLOBAL_KEY= +PUSHER_GLOBAL_SECRET= +PUSHER_GLOBAL_CLUSTER= +PUSHER_GLOBAL_USE_TLS=true +# Choose the events you want to send to Pusher +PUSHER_EVENTS_APPLICATION_STARTUP=true +PUSHER_EVENTS_QRCODE_UPDATED=true +PUSHER_EVENTS_MESSAGES_SET=true +PUSHER_EVENTS_MESSAGES_UPSERT=true +PUSHER_EVENTS_MESSAGES_EDITED=true +PUSHER_EVENTS_MESSAGES_UPDATE=true +PUSHER_EVENTS_MESSAGES_DELETE=true +PUSHER_EVENTS_SEND_MESSAGE=true +PUSHER_EVENTS_CONTACTS_SET=true +PUSHER_EVENTS_CONTACTS_UPSERT=true +PUSHER_EVENTS_CONTACTS_UPDATE=true +PUSHER_EVENTS_PRESENCE_UPDATE=true +PUSHER_EVENTS_CHATS_SET=true +PUSHER_EVENTS_CHATS_UPSERT=true +PUSHER_EVENTS_CHATS_UPDATE=true +PUSHER_EVENTS_CHATS_DELETE=true +PUSHER_EVENTS_GROUPS_UPSERT=true +PUSHER_EVENTS_GROUPS_UPDATE=true +PUSHER_EVENTS_GROUP_PARTICIPANTS_UPDATE=true +PUSHER_EVENTS_CONNECTION_UPDATE=true +PUSHER_EVENTS_LABELS_EDIT=true +PUSHER_EVENTS_LABELS_ASSOCIATION=true +PUSHER_EVENTS_CALL=true +PUSHER_EVENTS_TYPEBOT_START=false +PUSHER_EVENTS_TYPEBOT_CHANGE_STATUS=false + +# WhatsApp Business API - Environment variables +# Token used to validate the webhook on the Facebook APP +WA_BUSINESS_TOKEN_WEBHOOK=evolution +WA_BUSINESS_URL=https://graph.facebook.com +WA_BUSINESS_VERSION=v20.0 +WA_BUSINESS_LANGUAGE=en_US + +# Global Webhook Settings +# Each instance's Webhook URL and events will be requested at the time it is created +WEBHOOK_GLOBAL_ENABLED=false +# Define a global webhook that will listen for enabled events from all instances +WEBHOOK_GLOBAL_URL='' +# With this option activated, you work with a url per webhook event, respecting the global url and the name of each event +WEBHOOK_GLOBAL_WEBHOOK_BY_EVENTS=false +# Set the events you want to hear +WEBHOOK_EVENTS_APPLICATION_STARTUP=false +WEBHOOK_EVENTS_QRCODE_UPDATED=true +WEBHOOK_EVENTS_MESSAGES_SET=true +WEBHOOK_EVENTS_MESSAGES_UPSERT=true +WEBHOOK_EVENTS_MESSAGES_EDITED=true +WEBHOOK_EVENTS_MESSAGES_UPDATE=true +WEBHOOK_EVENTS_MESSAGES_DELETE=true +WEBHOOK_EVENTS_SEND_MESSAGE=true +WEBHOOK_EVENTS_CONTACTS_SET=true +WEBHOOK_EVENTS_CONTACTS_UPSERT=true +WEBHOOK_EVENTS_CONTACTS_UPDATE=true +WEBHOOK_EVENTS_PRESENCE_UPDATE=true +WEBHOOK_EVENTS_CHATS_SET=true +WEBHOOK_EVENTS_CHATS_UPSERT=true +WEBHOOK_EVENTS_CHATS_UPDATE=true +WEBHOOK_EVENTS_CHATS_DELETE=true +WEBHOOK_EVENTS_GROUPS_UPSERT=true +WEBHOOK_EVENTS_GROUPS_UPDATE=true +WEBHOOK_EVENTS_GROUP_PARTICIPANTS_UPDATE=true +WEBHOOK_EVENTS_CONNECTION_UPDATE=true +WEBHOOK_EVENTS_REMOVE_INSTANCE=false +WEBHOOK_EVENTS_LOGOUT_INSTANCE=false +WEBHOOK_EVENTS_LABELS_EDIT=true +WEBHOOK_EVENTS_LABELS_ASSOCIATION=true +WEBHOOK_EVENTS_CALL=true +# This events is used with Typebot +WEBHOOK_EVENTS_TYPEBOT_START=false +WEBHOOK_EVENTS_TYPEBOT_CHANGE_STATUS=false +# This event is used to send errors +WEBHOOK_EVENTS_ERRORS=false +WEBHOOK_EVENTS_ERRORS_WEBHOOK= + +# Name that will be displayed on smartphone connection +CONFIG_SESSION_PHONE_CLIENT=Evolution API +# Browser Name = Chrome | Firefox | Edge | Opera | Safari +CONFIG_SESSION_PHONE_NAME=Chrome + +# Whatsapp Web version for baileys channel +# https://web.whatsapp.com/check-update?version=0&platform=web +CONFIG_SESSION_PHONE_VERSION=2.3000.1015901307 + +# Set qrcode display limit +QRCODE_LIMIT=30 +# Color of the QRCode on base64 +QRCODE_COLOR='#175197' + +# Typebot - Environment variables +TYPEBOT_ENABLED=false +# old | latest +TYPEBOT_API_VERSION=latest + +# Chatwoot - Environment variables +CHATWOOT_ENABLED=false +# If you leave this option as false, when deleting the message for everyone on WhatsApp, it will not be deleted on Chatwoot. +CHATWOOT_MESSAGE_READ=true +# If you leave this option as true, when sending a message in Chatwoot, the client's last message will be marked as read on WhatsApp. +CHATWOOT_MESSAGE_DELETE=true +# If you leave this option as true, a contact will be created on Chatwoot to provide the QR Code and update messages about the instance. +CHATWOOT_BOT_CONTACT=true +# This db connection is used to import messages from whatsapp to chatwoot database +CHATWOOT_IMPORT_DATABASE_CONNECTION_URI=postgresql://user:passwprd@host:5432/chatwoot?sslmode=disable +CHATWOOT_IMPORT_PLACEHOLDER_MEDIA_MESSAGE=true + +# OpenAI - Environment variables +OPENAI_ENABLED=false + +# Dify - Environment variables +DIFY_ENABLED=false + +# Cache - Environment variables +# Redis Cache enabled +CACHE_REDIS_ENABLED=true +CACHE_REDIS_URI=redis://localhost:6379/6 +CACHE_REDIS_TTL=604800 +# Prefix serves to differentiate data from one installation to another that are using the same redis +CACHE_REDIS_PREFIX_KEY=evolution +# Enabling this variable will save the connection information in Redis and not in the database. +CACHE_REDIS_SAVE_INSTANCES=false +# Local Cache enabled +CACHE_LOCAL_ENABLED=false + +# Amazon S3 - Environment variables +S3_ENABLED=false +S3_ACCESS_KEY= +S3_SECRET_KEY= +S3_BUCKET=evolution +S3_PORT=443 +S3_ENDPOINT=s3.domain.com +S3_REGION=eu-west-3 +S3_USE_SSL=true + +# AMAZON S3 - Environment variables +# S3_ENABLED=true +# S3_BUCKET=bucket_name +# S3_ACCESS_KEY=access_key_id +# S3_SECRET_KEY=secret_access_key +# S3_ENDPOINT=s3.amazonaws.com # region: s3.eu-west-3.amazonaws.com +# S3_REGION=eu-west-3 + +# MINIO Use SSL - Environment variables +# S3_ENABLED=true +# S3_ACCESS_KEY=access_key_id +# S3_SECRET_KEY=secret_access_key +# S3_BUCKET=bucket_name +# S3_PORT=443 +# S3_ENDPOINT=s3.domain.com +# S3_USE_SSL=true +# S3_REGION=eu-south + +# Evolution Audio Converter - Environment variables - https://github.com/EvolutionAPI/evolution-audio-converter +# API_AUDIO_CONVERTER=http://localhost:4040/process-audio +# API_AUDIO_CONVERTER_KEY=429683C4C977415CAAFCCE10F7D57E11 + +# Define a global apikey to access all instances. +# OBS: This key must be inserted in the request header to create an instance. +AUTHENTICATION_API_KEY=429683C4C977415CAAFCCE10F7D57E11 +# If you leave this option as true, the instances will be exposed in the fetch instances endpoint. +AUTHENTICATION_EXPOSE_IN_FETCH_INSTANCES=true +LANGUAGE=en + +# Define a global proxy to be used if the instance does not have one +# PROXY_HOST= +# PROXY_PORT=80 +# PROXY_PROTOCOL=http +# PROXY_USERNAME= +# PROXY_PASSWORD= \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js index f805da92..b77e37db 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,50 +1,46 @@ module.exports = { parser: '@typescript-eslint/parser', parserOptions: { - sourceType: 'CommonJS', + project: 'tsconfig.json', + tsconfigRootDir: __dirname, + sourceType: 'module', + warnOnUnsupportedTypeScriptVersion: false, + EXPERIMENTAL_useSourceOfProjectReferenceRedirect: true, }, - plugins: [ - '@typescript-eslint', - 'simple-import-sort', - 'import' - ], - extends: [ - 'eslint:recommended', - 'plugin:@typescript-eslint/recommended', - 'plugin:prettier/recommended' - ], + plugins: ['@typescript-eslint', 'simple-import-sort', 'import'], + extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended'], globals: { - Atomics: 'readonly', - SharedArrayBuffer: 'readonly', + Atomics: 'readonly', + SharedArrayBuffer: 'readonly', }, root: true, env: { - node: true, - jest: true, + node: true, + jest: true, }, ignorePatterns: ['.eslintrc.js'], rules: { - '@typescript-eslint/interface-name-prefix': 'off', - '@typescript-eslint/explicit-function-return-type': 'off', - '@typescript-eslint/explicit-module-boundary-types': 'off', - '@typescript-eslint/no-explicit-any': 'off', - '@typescript-eslint/no-empty-function': 'off', - '@typescript-eslint/no-non-null-assertion': 'off', - '@typescript-eslint/no-unused-vars': 'error', - 'import/first': 'error', - 'import/no-duplicates': 'error', - 'simple-import-sort/imports': 'error', - 'simple-import-sort/exports': 'error', - '@typescript-eslint/ban-types': [ - 'error', - { - extendDefaults: true, - types: { - '{}': false, - Object: false, - }, + '@typescript-eslint/interface-name-prefix': 'off', + '@typescript-eslint/explicit-function-return-type': 'off', + '@typescript-eslint/explicit-module-boundary-types': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-empty-function': 'off', + '@typescript-eslint/no-non-null-assertion': 'off', + '@typescript-eslint/no-unused-vars': 'error', + 'import/first': 'error', + 'import/no-duplicates': 'error', + 'simple-import-sort/imports': 'error', + 'simple-import-sort/exports': 'error', + '@typescript-eslint/ban-types': [ + 'error', + { + extendDefaults: true, + types: { + '{}': false, + Object: false, }, - ], - 'prettier/prettier': ['error', { endOfLine: 'auto' }], + }, + ], + 'prettier/prettier': ['error', { endOfLine: 'auto' }], }, -}; \ No newline at end of file +}; diff --git a/.github/workflows/check_code_quality.yml b/.github/workflows/check_code_quality.yml new file mode 100644 index 00000000..07bffd7a --- /dev/null +++ b/.github/workflows/check_code_quality.yml @@ -0,0 +1,28 @@ +name: Check Code Quality + +on: [pull_request] + +jobs: + check-lint-and-build: + runs-on: ubuntu-latest + timeout-minutes: 10 + + steps: + - uses: actions/checkout@v2 + + - name: Install Node + uses: actions/setup-node@v1 + with: + node-version: 20.x + + - name: Install packages + run: npm install + + - name: Check linting + run: npm run lint:check + + - name: Check build + run: npm run db:generate + + - name: Check build + run: npm run build \ No newline at end of file diff --git a/.github/workflows/publish_docker_image_latest.yml b/.github/workflows/publish_docker_image_latest.yml new file mode 100644 index 00000000..641dc5e0 --- /dev/null +++ b/.github/workflows/publish_docker_image_latest.yml @@ -0,0 +1,48 @@ +name: Build Docker image + +on: + push: + branches: + - main + +jobs: + build_deploy: + name: Build and Deploy + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: atendai/evolution-api + tags: latest + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Build and push + id: docker_build + uses: docker/build-push-action@v5 + with: + platforms: linux/amd64,linux/arm64 + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + + - name: Image digest + run: echo ${{ steps.docker_build.outputs.digest }} diff --git a/.gitignore b/.gitignore index ecba09fb..a8226ede 100644 --- a/.gitignore +++ b/.gitignore @@ -18,11 +18,9 @@ lerna-debug.log* /docker-compose-data /docker-data -docker-compose.yaml - # Package /yarn.lock -/package-lock.json +/pnpm-lock.yaml # IDEs .vscode/* @@ -31,9 +29,7 @@ docker-compose.yaml !.vscode/launch.json !.vscode/extensions.json .nova/* - -# Prisma -/prisma/migrations +.idea/* # Project related /instances/* @@ -48,3 +44,5 @@ docker-compose.yaml .DS_Store *.DS_Store .tool-versions + +/prisma/migrations/* diff --git a/CHANGELOG.md b/CHANGELOG.md index 06379d80..2d316041 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,364 @@ +# 2.2.3 (2025-02-03 11:52) + +### Fixed + +* Fix cache in local file system +* Update Baileys Version + +# 2.2.2 (2025-01-31 06:55) + +### Features + +* Added prefix key to queue name in RabbitMQ + +### Fixed + +* Update Baileys Version + +# 2.2.1 (2025-01-22 14:37) + +### Features + +* Retry system for send webhooks +* Message filtering to support timestamp range queries +* Chats filtering to support timestamp range queries + +### Fixed + +* Correction of webhook global +* Fixed send audio with whatsapp cloud api +* Refactor on fetch chats +* Refactor on Evolution Channel + +# 2.2.0 (2024-10-18 10:00) + +### Features + +* Fake Call function +* Send List with Baileys +* Send Buttons with Baileys +* Added unreadMessages to chats +* Pusher event integration +* Add support for splitMessages and timePerChar in Integrations +* Audio Converter via API +* Send PTV messages with Baileys + +### Fixed + +* Fixed prefilledVariables in startTypebot +* Fix duplicate file upload +* Mark as read from me and groups +* Fetch chats query +* Ads messages in chatwoot +* Add indexes to improve performance in Evolution +* Add logical or permanent message deletion based on env config +* Add support for fetching multiple instances by key +* Update instance.controller.ts to filter by instanceName +* Receive template button reply message + +# 2.1.2 (2024-10-06 10:09) + +### Features + +* Sync lost messages on chatwoot +* Set the maximum number of listeners that can be registered for events +* Now is possible send medias with form-data + +### Fixed + +* Fetch status message +* Adjusts in migrations +* Update pushName in chatwoot +* Validate message before sending chatwoot +* Adds the message status to the return of the "prepareMessage" function +* Fixed openai setting when send a message with chatwoot +* Fix buildkey function in hSet and hDelete +* Fix mexico number +* Update baileys version +* Update in Baileys version that fixes timeout when updating profile picture +* Adjusts for fix timeout error on send status message +* Chatwoot verbose logs +* Adjusts on prisma connections +* License terms updated +* Fixed send message to group without no cache (local or redis) +* Fixed startTypebot with startSession = true +* Fixed issue of always creating a new label when saving chatwoot +* Fixed getBase64FromMediaMessage with convertToMp4 +* Fixed bug when send message when don't have mentionsEveryOne on payload +* Does not search message without chatwoot Message Id for reply +* Fixed bot fallback not working on integrations + +# 2.1.1 (2024-09-22 10:31) + +### Features + +* Define a global proxy to be used if the instance does not have one +* Save is on whatsapp on the database +* Add headers to the instance's webhook registration +* Debounce message break is now "\n" instead of white space +* Single view messages are now supported in chatwoot +* Chatbots can now send any type of media + +### Fixed + +* Validate if cache exists before accessing it +* Missing autoCreate chatwoot in instance create +* Fixed bugs in the frontend, on the event screens +* Fixed use chatwoot with evolution channel +* Fix chatwoot reply quote with Cloud API +* Use exchange name from .env on RabbitMQ +* Fixed chatwoot screen +* It is now possible to send images via the Evolution Channel +* Removed "version" from docker-compose as it is obsolete (https://dev.to/ajeetraina/do-we-still-use-version-in-compose-3inp) +* Fixed typebot ignoreJids being used only from default settings +* Fixed Chatwoot inbox creation on save +* Changed axios timeout for manager requests for 30s +* Update in Baileys version that fixes timeout when updating profile picture +* Fixed issue when sending links in markdown by chatbots like Dify +* Fixed issue with chatbots not respecting settings + +# 2.1.0 (2024-08-26 15:33) + +### Features + +* Improved layout manager +* Translation in manager: English, Portuguese, Spanish and French +* Evolution Bot Integration +* Option to disable chatwoot bot contact with CHATWOOT_BOT_CONTACT +* Added flowise integration +* Added evolution channel on instance create +* Change in license to Apache-2.0 +* Mark All in events + +### Fixed + +* Refactor integrations structure for modular system +* Fixed dify agent integration +* Update Baileys Version +* Fixed proxy config in manager +* Fixed send messages in groups +* S3 saving media sent from me +* Fixed duplication bot when use startTypebot + +### Break Changes + +* Payloads for events changed (create Instance and set events). Check postman to understand + +# 2.0.10 (2024-08-16 16:23) + +### Features + +* OpenAI send images when markdown +* Dify send images when markdown +* Sentry implemented + +### Fixed + +* Fix on get profilePicture +* Added S3_REGION on minio settings + +# 2.0.9 (2024-08-15 12:31) + +### Features + +* Added ignoreJids in chatwoot settings +* Dify now identifies images +* Openai now identifies images + +### Fixed + +* Path mapping & deps fix & bundler changed to tsup +* Improve database scripts to retrieve the provider from env file +* Update contacts database with unique index +* Save chat name +* Correction of media as attachments in chatwoot when using a Meta API Instance and not Baileys +* Update Baileys version 6.7.6 +* Deprecate buttons and list in new Baileys version +* Changed labels to be unique on the same instance +* Remove instance from redis even if using database +* Unified integration session system so they don't overlap +* Temporary fix for pictureUrl bug in groups +* Fix on migrations + +# 2.0.9-rc (2024-08-09 18:00) + +### Features + +* Added general session button in typebot, dify and openai in manager +* Added compatibility with mysql through prisma + +### Fixed + +* Import contacts with image in chatwoot +* Fix conversationId when is dify agent +* Fixed loading of selects in the manager +* Add restart button to sessions screen +* Adjustments to docker files +* StopBotFromMe working with chatwoot + +# 2.0.8-rc (2024-08-08 20:23) + +### Features + +* Variables passed to the input in dify +* OwnerJid passed to typebot +* Function for openai assistant added + +### Fixed + +* Adjusts in telemetry + +# 2.0.7-rc (2024-08-03 14:04) + +### Fixed + +* BusinessId added on create instances in manager +* Adjusts in restart instance +* Resolve issue with connecting to instance +* Session is now individual per instance and remoteJid +* Credentials verify on manager login +* Added description column on typebot, dify and openai +* Fixed dify agent integration + +# 2.0.6-rc (2024-08-02 19:23) + +### Features + +* Get models for OpenAI + +### Fixed + +* fetchInstances with clientName parameter +* fixed update typebot, openai and dify + +# 2.0.5-rc (2024-08-01 18:01) + +### Features + +* Speech to Text with Openai + +### Fixed + +* ClientName on infos +* Instance screen scroll bar in manager + +# 2.0.4-rc (2024-07-30 14:13) + +### Features + +* New manager v2.0 +* Dify integration + +### Fixed + +* Update Baileys Version +* Adjusts for new manager +* Corrected openai trigger validation +* Corrected typebot trigger validation + +# 2.0.3-beta (2024-07-29 09:03) + +### Features + +* Webhook url by submitted template to send status updates +* Sending template approval status webhook + +### Fixed + +* Equations and adjustments for the new manager +* Adjust TriggerType for OpenAI and Typebot integrations +* Fixed Typebot start call with active session + +# 2.0.2-beta (2024-07-18 21:33) + +### Feature + +* Open AI implemented + +### Fixed + +* Fixed the function of saving or not saving data in the database +* Resolve not find name +* Removed DEL_TEMP_INSTANCES as it is not being used +* Fixed global exchange name +* Add apiKey and serverUrl to prefilledVariables in typebot service +* Correction in start typebot, if it doesn't exist, create it + +# 2.0.1-beta (2024-07-17 17:01) + +### Fixed + +* Resolved issue with Chatwoot not receiving messages sent by Typebot + +# 2.0.0-beta (2024-07-14 17:00) + +### Feature + +* Added prisma orm, connection to postgres and mysql +* Added chatwoot integration activation +* Added typebot integration activation +* Now you can register several typebots with triggers +* Media sent to typebot now goes as a template string, example: imageMessage|MESSAGE_ID +* Organization configuration and logo in chatwoot bot contact +* Added debounce time for typebot messages +* Tagging in chatwoot contact by instance +* Add support for managing WhatsApp templates via official API +* Fixes and implementation of regex and fallback in typebot +* Ignore jids configuration added to typebot (will be used for both groups and contacts) +* Minio and S3 integration +* When S3 integration enabled, the media sent to typebot now goes as a template string, example: imageMessage|MEDIA_URL + +### Fixed + +* Removed excessive verbose logs +* Optimization in instance registration +* Now in typebot we wait until the terminal block to accept the user's message, if it arrives before the block is sent, it is ignored +* Correction of audio sending, now we can speed it up and have the audio wireframe +* Reply with media message on Chatwoot +* improvements in sending status and groups +* Correction in response returns from buttons, lists and templates +* EvolutionAPI/Baileys implemented + +### Break changes + +* jwt authentication removed +* Connection to mongodb removed +* Standardized all request bodies to use camelCase +* Change in webhook information from owner to instanceId +* Changed the .env file configuration, removed the yml version and added .env to the repository root +* Removed the mobile type connection with Baileys +* Simplified payloads and endpoints +* Improved Typebot + - Now you can register several typebots + - Start configuration by trigger or for all + - Session search by typebot or remoteJid + - KeepOpen configuration (keeps the session even when the bot ends, to run once per contact) + - StopBotFromMe configuration, allows me to stop the bot if I send a chat message. +* Changed the way the goal webhook is configured + +# 1.8.2 (2024-07-03 13:50) + +### Fixed + +* Corretion in globall rabbitmq queue name +* Improvement in the use of mongodb database for credentials +* Fixed base64 in webhook for documentWithCaption +* Fixed Generate pairing code + +# 1.8.1 (2024-06-08 21:32) + +### Feature + +* New method of saving sessions to a file using worker, made in partnership with [codechat](https://github.com/code-chat-br/whatsapp-api) + +### Fixed + +* Correction of variables breaking lines in typebot + +### Fixed + +* Correction of variables breaking lines in typebot + # 1.8.0 (2024-05-27 16:10) ### Feature @@ -7,12 +368,14 @@ * Build in docker for linux/amd64, linux/arm64 platforms ### Fixed + * Correction in message formatting when generated by AI as markdown in typebot * Security fix in fetch instance with client key when not connected to mongodb # 1.7.5 (2024-05-21 08:50) ### Fixed + * Add merge_brazil_contacts function to solve nine digit in brazilian numbers * Optimize ChatwootService method for updating contact * Fix swagger auth @@ -24,6 +387,7 @@ # 1.7.4 (2024-04-28 09:46) ### Fixed + * Adjusts in proxy on fetchAgent * Recovering messages lost with redis cache * Log when init redis cache service @@ -34,6 +398,7 @@ # 1.7.3 (2024-04-18 12:07) ### Fixed + * Revert fix audio encoding * Recovering messages lost with redis cache * Adjusts in redis for save instances diff --git a/Docker/.env.example b/Docker/.env.example deleted file mode 100644 index e735d8de..00000000 --- a/Docker/.env.example +++ /dev/null @@ -1,177 +0,0 @@ -# Server URL - Set your application url -SERVER_URL=http://localhost:8080 - -# Cors - * for all or set separate by commas - ex.: 'yourdomain1.com, yourdomain2.com' -CORS_ORIGIN=* -CORS_METHODS=POST,GET,PUT,DELETE -CORS_CREDENTIALS=true - -# Determine the logs to be displayed -LOG_LEVEL=ERROR,WARN,DEBUG,INFO,LOG,VERBOSE,DARK,WEBHOOKS -LOG_COLOR=true -# Log Baileys - "fatal" | "error" | "warn" | "info" | "debug" | "trace" -LOG_BAILEYS=error - -# Determine how long the instance should be deleted from memory in case of no connection. -# Default time: 5 minutes -# If you don't even want an expiration, enter the value false -DEL_INSTANCE=false -DEL_TEMP_INSTANCES=true # Delete instances with status closed on start - -# Temporary data storage -STORE_MESSAGES=true -STORE_MESSAGE_UP=true -STORE_CONTACTS=true -STORE_CHATS=true - -# Set Store Interval in Seconds (7200 = 2h) -CLEAN_STORE_CLEANING_INTERVAL=7200 -CLEAN_STORE_MESSAGES=true -CLEAN_STORE_MESSAGE_UP=true -CLEAN_STORE_CONTACTS=true -CLEAN_STORE_CHATS=true - -# Permanent data storage -DATABASE_ENABLED=false -DATABASE_CONNECTION_URI=mongodb://root:root@mongodb:27017/?authSource=admin & -readPreference=primary & -ssl=false & -directConnection=true -DATABASE_CONNECTION_DB_PREFIX_NAME=evdocker - -# Choose the data you want to save in the application's database or store -DATABASE_SAVE_DATA_INSTANCE=false -DATABASE_SAVE_DATA_NEW_MESSAGE=false -DATABASE_SAVE_MESSAGE_UPDATE=false -DATABASE_SAVE_DATA_CONTACTS=false -DATABASE_SAVE_DATA_CHATS=false - -RABBITMQ_ENABLED=false -RABBITMQ_URI=amqp://guest:guest@rabbitmq:5672 -RABBITMQ_EXCHANGE_NAME=evolution_exchange -RABBITMQ_GLOBAL_ENABLED=false -RABBITMQ_EVENTS_APPLICATION_STARTUP=false -RABBITMQ_EVENTS_QRCODE_UPDATED=true -RABBITMQ_EVENTS_MESSAGES_SET=true -RABBITMQ_EVENTS_MESSAGES_UPSERT=true -RABBITMQ_EVENTS_MESSAGES_UPDATE=true -RABBITMQ_EVENTS_MESSAGES_DELETE=true -RABBITMQ_EVENTS_SEND_MESSAGE=true -RABBITMQ_EVENTS_CONTACTS_SET=true -RABBITMQ_EVENTS_CONTACTS_UPSERT=true -RABBITMQ_EVENTS_CONTACTS_UPDATE=true -RABBITMQ_EVENTS_PRESENCE_UPDATE=true -RABBITMQ_EVENTS_CHATS_SET=true -RABBITMQ_EVENTS_CHATS_UPSERT=true -RABBITMQ_EVENTS_CHATS_UPDATE=true -RABBITMQ_EVENTS_CHATS_DELETE=true -RABBITMQ_EVENTS_GROUPS_UPSERT=true -RABBITMQ_EVENTS_GROUPS_UPDATE=true -RABBITMQ_EVENTS_GROUP_PARTICIPANTS_UPDATE=true -RABBITMQ_EVENTS_CONNECTION_UPDATE=true -RABBITMQ_EVENTS_LABELS_EDIT=true -RABBITMQ_EVENTS_LABELS_ASSOCIATION=true -RABBITMQ_EVENTS_CALL=true -RABBITMQ_EVENTS_TYPEBOT_START=false -RABBITMQ_EVENTS_TYPEBOT_CHANGE_STATUS=false - -WEBSOCKET_ENABLED=false -WEBSOCKET_GLOBAL_EVENTS=false - -WA_BUSINESS_TOKEN_WEBHOOK=evolution -WA_BUSINESS_URL=https://graph.facebook.com -WA_BUSINESS_VERSION=v18.0 -WA_BUSINESS_LANGUAGE=pt_BR - -SQS_ENABLED=false -SQS_ACCESS_KEY_ID= -SQS_SECRET_ACCESS_KEY= -SQS_ACCOUNT_ID= -SQS_REGION= - -# Global Webhook Settings -# Each instance's Webhook URL and events will be requested at the time it is created -## Define a global webhook that will listen for enabled events from all instances -WEBHOOK_GLOBAL_URL='' -WEBHOOK_GLOBAL_ENABLED=false -# With this option activated, you work with a url per webhook event, respecting the global url and the name of each event -WEBHOOK_GLOBAL_WEBHOOK_BY_EVENTS=false -## Set the events you want to hear -WEBHOOK_EVENTS_APPLICATION_STARTUP=false -WEBHOOK_EVENTS_QRCODE_UPDATED=true -WEBHOOK_EVENTS_MESSAGES_SET=true -WEBHOOK_EVENTS_MESSAGES_UPSERT=true -WEBHOOK_EVENTS_MESSAGES_UPDATE=true -WEBHOOK_EVENTS_MESSAGES_DELETE=true -WEBHOOK_EVENTS_SEND_MESSAGE=true -WEBHOOK_EVENTS_CONTACTS_SET=true -WEBHOOK_EVENTS_CONTACTS_UPSERT=true -WEBHOOK_EVENTS_CONTACTS_UPDATE=true -WEBHOOK_EVENTS_PRESENCE_UPDATE=true -WEBHOOK_EVENTS_CHATS_SET=true -WEBHOOK_EVENTS_CHATS_UPSERT=true -WEBHOOK_EVENTS_CHATS_UPDATE=true -WEBHOOK_EVENTS_CHATS_DELETE=true -WEBHOOK_EVENTS_GROUPS_UPSERT=true -WEBHOOK_EVENTS_GROUPS_UPDATE=true -WEBHOOK_EVENTS_GROUP_PARTICIPANTS_UPDATE=true -WEBHOOK_EVENTS_CONNECTION_UPDATE=true -WEBHOOK_EVENTS_LABELS_EDIT=true -WEBHOOK_EVENTS_LABELS_ASSOCIATION=true -WEBHOOK_EVENTS_CALL=true -# This event fires every time a new token is requested via the refresh route -WEBHOOK_EVENTS_NEW_JWT_TOKEN=false -# This events is used with Typebot -WEBHOOK_EVENTS_TYPEBOT_START=false -WEBHOOK_EVENTS_TYPEBOT_CHANGE_STATUS=false -# This event is used with Chama AI -WEBHOOK_EVENTS_CHAMA_AI_ACTION=false -# This event is used to send errors -WEBHOOK_EVENTS_ERRORS=false -WEBHOOK_EVENTS_ERRORS_WEBHOOK= - -# Name that will be displayed on smartphone connection -CONFIG_SESSION_PHONE_CLIENT=EvolutionAPI -# Browser Name = Chrome | Firefox | Edge | Opera | Safari -CONFIG_SESSION_PHONE_NAME=Chrome - -# Set qrcode display limit -QRCODE_LIMIT=30 -QRCODE_COLOR=#198754 - -# old | latest -TYPEBOT_API_VERSION=latest -TYPEBOT_KEEP_OPEN=false - -#Chatwoot -# If you leave this option as false, when deleting the message for everyone on WhatsApp, it will not be deleted on Chatwoot. -CHATWOOT_MESSAGE_DELETE=false # false | true -# If you leave this option as true, when sending a message in Chatwoot, the client's last message will be marked as read on WhatsApp. -CHATWOOT_MESSAGE_READ=false # false | true -# This db connection is used to import messages from whatsapp to chatwoot database -CHATWOOT_IMPORT_DATABASE_CONNECTION_URI=postgres://user:password@hostname:port/dbname?sslmode=disable -CHATWOOT_IMPORT_DATABASE_PLACEHOLDER_MEDIA_MESSAGE=true - -CACHE_REDIS_ENABLED=false -CACHE_REDIS_URI=redis://redis:6379 -CACHE_REDIS_PREFIX_KEY=evolution -CACHE_REDIS_TTL=604800 -CACHE_REDIS_SAVE_INSTANCES=false -CACHE_LOCAL_ENABLED=false -CACHE_LOCAL_TTL=604800 - -# Defines an authentication type for the api -# We recommend using the apikey because it will allow you to use a custom token, -# if you use jwt, a random token will be generated and may be expired and you will have to generate a new token -# jwt or 'apikey' -AUTHENTICATION_TYPE=apikey -## Define a global apikey to access all instances. -### OBS: This key must be inserted in the request header to create an instance. -AUTHENTICATION_API_KEY=B6D711FCDE4D4FD5936544120E713976 -AUTHENTICATION_EXPOSE_IN_FETCH_INSTANCES=true -## Set the secret key to encrypt and decrypt your token and its expiration time -# seconds - 3600s ===1h | zero (0) - never expires -AUTHENTICATION_JWT_EXPIRIN_IN=0 -AUTHENTICATION_JWT_SECRET='L=0YWt]b2w[WF>#>:&E`' - -LANGUAGE=en # pt-BR, en diff --git a/Docker/docker-compose.yaml b/Docker/docker-compose.yaml deleted file mode 100644 index 4a2af41b..00000000 --- a/Docker/docker-compose.yaml +++ /dev/null @@ -1,22 +0,0 @@ -version: '3.3' - -services: - - api: - container_name: evolution_api - image: atendai/evolution-api - restart: always - ports: - - 8080:8080 - volumes: - - evolution_instances:/evolution/instances - - evolution_store:/evolution/store - env_file: - - .env - command: ['node', './dist/src/main.js'] - expose: - - 8080 - -volumes: - evolution_instances: - evolution_store: diff --git a/Docker/evolution-api-all-services/.env.example b/Docker/evolution-api-all-services/.env.example deleted file mode 100644 index d08fee49..00000000 --- a/Docker/evolution-api-all-services/.env.example +++ /dev/null @@ -1,119 +0,0 @@ -# Server URL - Set your application url -SERVER_URL='http://localhost:8080' - -# Cors - * for all or set separate by commas - ex.: 'yourdomain1.com, yourdomain2.com' -CORS_ORIGIN='*' -CORS_METHODS='POST,GET,PUT,DELETE' -CORS_CREDENTIALS=true - -# Determine the logs to be displayed -LOG_LEVEL='ERROR,WARN,DEBUG,INFO,LOG,VERBOSE,DARK,WEBHOOKS' -LOG_COLOR=true -# Log Baileys - "fatal" | "error" | "warn" | "info" | "debug" | "trace" -LOG_BAILEYS=error - -# Determine how long the instance should be deleted from memory in case of no connection. -# Default time: 5 minutes -# If you don't even want an expiration, enter the value false -DEL_INSTANCE=false -DEL_TEMP_INSTANCES=true # Delete instances with status closed on start - -# Temporary data storage -STORE_MESSAGES=true -STORE_MESSAGE_UP=true -STORE_CONTACTS=true -STORE_CHATS=true - -# Set Store Interval in Seconds (7200 = 2h) -CLEAN_STORE_CLEANING_INTERVAL=7200 -CLEAN_STORE_MESSAGES=true -CLEAN_STORE_MESSAGE_UP=true -CLEAN_STORE_CONTACTS=true -CLEAN_STORE_CHATS=true - -# Permanent data storage -DATABASE_ENABLED=true -DATABASE_CONNECTION_URI=mongodb://root:root@mongodb:27017/?authSource=admin & -readPreference=primary & -ssl=false & -directConnection=true -DATABASE_CONNECTION_DB_PREFIX_NAME=evolution - -# Choose the data you want to save in the application's database or store -DATABASE_SAVE_DATA_INSTANCE=false -DATABASE_SAVE_DATA_NEW_MESSAGE=false -DATABASE_SAVE_MESSAGE_UPDATE=false -DATABASE_SAVE_DATA_CONTACTS=false -DATABASE_SAVE_DATA_CHATS=false - -# Global Webhook Settings -# Each instance's Webhook URL and events will be requested at the time it is created -## Define a global webhook that will listen for enabled events from all instances -WEBHOOK_GLOBAL_URL='' -WEBHOOK_GLOBAL_ENABLED=false -# With this option activated, you work with a url per webhook event, respecting the global url and the name of each event -WEBHOOK_GLOBAL_WEBHOOK_BY_EVENTS=false -## Set the events you want to hear -WEBHOOK_EVENTS_APPLICATION_STARTUP=false -WEBHOOK_EVENTS_QRCODE_UPDATED=true -WEBHOOK_EVENTS_MESSAGES_SET=true -WEBHOOK_EVENTS_MESSAGES_UPSERT=true -WEBHOOK_EVENTS_MESSAGES_UPDATE=true -WEBHOOK_EVENTS_MESSAGES_DELETE=true -WEBHOOK_EVENTS_SEND_MESSAGE=true -WEBHOOK_EVENTS_CONTACTS_SET=true -WEBHOOK_EVENTS_CONTACTS_UPSERT=true -WEBHOOK_EVENTS_CONTACTS_UPDATE=true -WEBHOOK_EVENTS_PRESENCE_UPDATE=true -WEBHOOK_EVENTS_CHATS_SET=true -WEBHOOK_EVENTS_CHATS_UPSERT=true -WEBHOOK_EVENTS_CHATS_UPDATE=true -WEBHOOK_EVENTS_CHATS_DELETE=true -WEBHOOK_EVENTS_GROUPS_UPSERT=true -WEBHOOK_EVENTS_GROUPS_UPDATE=true -WEBHOOK_EVENTS_GROUP_PARTICIPANTS_UPDATE=true -WEBHOOK_EVENTS_CONNECTION_UPDATE=true -WEBHOOK_EVENTS_LABELS_EDIT=true -WEBHOOK_EVENTS_LABELS_ASSOCIATION=true -# This event fires every time a new token is requested via the refresh route -WEBHOOK_EVENTS_NEW_JWT_TOKEN=false - -# Name that will be displayed on smartphone connection -CONFIG_SESSION_PHONE_CLIENT='Evolution API' -# Browser Name = chrome | firefox | edge | opera | safari -CONFIG_SESSION_PHONE_NAME=chrome - -# Set qrcode display limit -QRCODE_LIMIT=30 - -CACHE_REDIS_ENABLED=false -CACHE_REDIS_URI=redis://redis:6379 -CACHE_REDIS_PREFIX_KEY=evolution -CACHE_REDIS_TTL=604800 -CACHE_REDIS_SAVE_INSTANCES=false -CACHE_LOCAL_ENABLED=false -CACHE_LOCAL_TTL=604800 - -# Defines an authentication type for the api -# We recommend using the apikey because it will allow you to use a custom token, -# if you use jwt, a random token will be generated and may be expired and you will have to generate a new token -# jwt or 'apikey' -AUTHENTICATION_TYPE='apikey' -## Define a global apikey to access all instances. -### OBS: This key must be inserted in the request header to create an instance. -AUTHENTICATION_API_KEY='B6D711FCDE4D4FD5936544120E713976' -AUTHENTICATION_EXPOSE_IN_FETCH_INSTANCES=true -## Set the secret key to encrypt and decrypt your token and its expiration time -# seconds - 3600s ===1h | zero (0) - never expires -AUTHENTICATION_JWT_EXPIRIN_IN=0 -AUTHENTICATION_JWT_SECRET='L0YWtjb2w554WFqPG' -# Set the instance name and webhook url to create an instance in init the application -# With this option activated, you work with a url per webhook event, respecting the local url and the name of each event -# container or server -AUTHENTICATION_INSTANCE_MODE=server -# if you are using container mode, set the container name and the webhook url to default instance -AUTHENTICATION_INSTANCE_NAME=evolution -AUTHENTICATION_INSTANCE_WEBHOOK_URL='' -AUTHENTICATION_INSTANCE_CHATWOOT_ACCOUNT_ID=1 -AUTHENTICATION_INSTANCE_CHATWOOT_TOKEN=123456 -AUTHENTICATION_INSTANCE_CHATWOOT_URL='' diff --git a/Docker/evolution-api-all-services/docker-compose.yaml b/Docker/evolution-api-all-services/docker-compose.yaml deleted file mode 100644 index 5f936cd1..00000000 --- a/Docker/evolution-api-all-services/docker-compose.yaml +++ /dev/null @@ -1,91 +0,0 @@ -version: '3.3' - -services: - - mongodb: - container_name: mongodb - image: mongo - restart: on-failure - ports: - - 27017:27017 - environment: - - MONGO_INITDB_ROOT_USERNAME=root - - MONGO_INITDB_ROOT_PASSWORD=root - - PUID=1000 - - PGID=1000 - volumes: - - evolution_mongodb_data:/data/db - - evolution_mongodb_configdb:/data/configdb - expose: - - 27017 - - mongo-express: - container_name: mongodb-express - image: mongo-express - restart: on-failure - ports: - - 8081:8081 - depends_on: - - mongodb - environment: - ME_CONFIG_BASICAUTH_USERNAME: root - ME_CONFIG_BASICAUTH_PASSWORD: root - ME_CONFIG_MONGODB_SERVER: mongodb - ME_CONFIG_MONGODB_ADMINUSERNAME: root - ME_CONFIG_MONGODB_ADMINPASSWORD: root - links: - - mongodb - - redis: - container_name: redis - image: redis:latest - restart: on-failure - ports: - - 6379:6379 - command: > - redis-server - --port 6379 - --appendonly yes - volumes: - - evolution_redis:/data - - rebrow: - container_name: rebrow - image: marian/rebrow - restart: on-failure - depends_on: - - redis - ports: - - 5001:5001 - links: - - redis - - api: - container_name: evolution_api - image: atendai/evolution-api - restart: always - depends_on: - - mongodb - - redis - ports: - - 8080:8080 - volumes: - - evolution_instances:/evolution/instances - - evolution_store:/evolution/store - env_file: - - .env - command: ['node', './dist/src/main.js'] - expose: - - 8080 - -volumes: - evolution_mongodb_data: - evolution_mongodb_configdb: - evolution_redis: - evolution_instances: - evolution_store: - -networks: - evolution-net: - external: true - diff --git a/Docker/minio/docker-compose.yaml b/Docker/minio/docker-compose.yaml new file mode 100644 index 00000000..8791627a --- /dev/null +++ b/Docker/minio/docker-compose.yaml @@ -0,0 +1,31 @@ +version: '3.3' + +services: + minio: + container_name: minio + image: quay.io/minio/minio + networks: + - evolution-net + command: server /data --console-address ":9001" + restart: always + ports: + - 5432:5432 + environment: + - MINIO_ROOT_USER=USER + - MINIO_ROOT_PASSWORD=PASSWORD + - MINIO_BROWSER_REDIRECT_URL=http:/localhost:9001 + - MINIO_SERVER_URL=http://localhost:9000 + volumes: + - minio_data:/data + expose: + - 9000 + - 9001 + +volumes: + minio_data: + + +networks: + evolution-net: + name: evolution-net + driver: bridge diff --git a/Docker/mongodb/docker-compose.yaml b/Docker/mongodb/docker-compose.yaml deleted file mode 100644 index 01220c54..00000000 --- a/Docker/mongodb/docker-compose.yaml +++ /dev/null @@ -1,42 +0,0 @@ -version: '3.3' - -services: - mongodb: - container_name: mongodb - image: mongo - restart: always - ports: - - 27017:27017 - environment: - - MONGO_INITDB_ROOT_USERNAME=root - - MONGO_INITDB_ROOT_PASSWORD=root - - PUID=1000 - - PGID=1000 - volumes: - - evolution_mongodb_data:/data/db - - evolution_mongodb_configdb:/data/configdb - expose: - - 27017 - - mongo-express: - image: mongo-express - environment: - ME_CONFIG_BASICAUTH_USERNAME: root - ME_CONFIG_BASICAUTH_PASSWORD: root - ME_CONFIG_MONGODB_SERVER: mongodb - ME_CONFIG_MONGODB_ADMINUSERNAME: root - ME_CONFIG_MONGODB_ADMINPASSWORD: root - ports: - - 8081:8081 - links: - - mongodb - -volumes: - evolution_mongodb_data: - evolution_mongodb_configdb: - - -networks: - evolution-net: - name: evolution-net - driver: bridge diff --git a/Docker/mysql/docker-compose.yaml b/Docker/mysql/docker-compose.yaml new file mode 100644 index 00000000..2e213878 --- /dev/null +++ b/Docker/mysql/docker-compose.yaml @@ -0,0 +1,27 @@ +version: '3.3' + +services: + mysql: + container_name: mysql + image: percona/percona-server:8.0 + networks: + - evolution-net + restart: always + ports: + - 3306:3306 + environment: + - MYSQL_ROOT_PASSWORD=root + - TZ=America/Bahia + volumes: + - mysql_data:/var/lib/mysql + expose: + - 3306 + +volumes: + mysql_data: + + +networks: + evolution-net: + name: evolution-net + driver: bridge diff --git a/Docker/postgres/docker-compose.yaml b/Docker/postgres/docker-compose.yaml new file mode 100644 index 00000000..bf07a461 --- /dev/null +++ b/Docker/postgres/docker-compose.yaml @@ -0,0 +1,42 @@ +version: '3.3' + +services: + postgres: + container_name: postgres + image: postgres:15 + networks: + - evolution-net + command: ["postgres", "-c", "max_connections=1000"] + restart: always + ports: + - 5432:5432 + environment: + - POSTGRES_PASSWORD=PASSWORD + volumes: + - postgres_data:/var/lib/postgresql/data + expose: + - 5432 + + pgadmin: + image: dpage/pgadmin4:latest + networks: + - evolution-net + environment: + - PGADMIN_DEFAULT_EMAIL=EMAIL + - PGADMIN_DEFAULT_PASSWORD=PASSWORD + volumes: + - pgadmin_data:/var/lib/pgadmin + ports: + - 4000:80 + links: + - postgres + +volumes: + postgres_data: + pgadmin_data: + + +networks: + evolution-net: + name: evolution-net + driver: bridge diff --git a/Docker/rabbitmq/docker-compose.yaml b/Docker/rabbitmq/docker-compose.yaml new file mode 100644 index 00000000..b8c1ed6a --- /dev/null +++ b/Docker/rabbitmq/docker-compose.yaml @@ -0,0 +1,25 @@ +version: '3.3' + +services: + rabbitmq: + container_name: rabbitmq + image: rabbitmq:management + environment: + - RABBITMQ_ERLANG_COOKIE=33H2CdkzF5WrnJ4ud6nkUdRTKXvbCHeFjvVL71p + - RABBITMQ_DEFAULT_VHOST=default + - RABBITMQ_DEFAULT_USER=USER + - RABBITMQ_DEFAULT_PASS=PASSWORD + volumes: + - rabbitmq_data:/var/lib/rabbitmq/ + ports: + - 5672:5672 + - 15672:15672 + +volumes: + rabbitmq_data: + + +networks: + evolution-net: + name: evolution-net + driver: bridge diff --git a/Docker/redis/docker-compose.yaml b/Docker/redis/docker-compose.yaml index 297b11db..a9b4cf67 100644 --- a/Docker/redis/docker-compose.yaml +++ b/Docker/redis/docker-compose.yaml @@ -3,6 +3,8 @@ version: '3.3' services: redis: image: redis:latest + networks: + - evolution-net container_name: redis command: > redis-server --port 6379 --appendonly yes diff --git a/Docker/scripts/deploy_database.sh b/Docker/scripts/deploy_database.sh new file mode 100755 index 00000000..fde46d12 --- /dev/null +++ b/Docker/scripts/deploy_database.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +source ./Docker/scripts/env_functions.sh + +if [ "$DOCKER_ENV" != "true" ]; then + export_env_vars +fi + +if [[ "$DATABASE_PROVIDER" == "postgresql" || "$DATABASE_PROVIDER" == "mysql" ]]; then + export DATABASE_URL + echo "Deploying migrations for $DATABASE_PROVIDER" + echo "Database URL: $DATABASE_URL" + # rm -rf ./prisma/migrations + # cp -r ./prisma/$DATABASE_PROVIDER-migrations ./prisma/migrations + npm run db:deploy + if [ $? -ne 0 ]; then + echo "Migration failed" + exit 1 + else + echo "Migration succeeded" + fi + npm run db:generate + if [ $? -ne 0 ]; then + echo "Prisma generate failed" + exit 1 + else + echo "Prisma generate succeeded" + fi +else + echo "Error: Database provider $DATABASE_PROVIDER invalid." + exit 1 +fi diff --git a/Docker/scripts/env_functions.sh b/Docker/scripts/env_functions.sh new file mode 100755 index 00000000..c2720e90 --- /dev/null +++ b/Docker/scripts/env_functions.sh @@ -0,0 +1,18 @@ +export_env_vars() { + if [ -f .env ]; then + while IFS='=' read -r key value; do + if [[ -z "$key" || "$key" =~ ^\s*# || -z "$value" ]]; then + continue + fi + + key=$(echo "$key" | tr -d '[:space:]') + value=$(echo "$value" | tr -d '[:space:]') + value=$(echo "$value" | tr -d "'" | tr -d "\"") + + export "$key=$value" + done < .env + else + echo ".env file not found" + exit 1 + fi +} diff --git a/Docker/scripts/generate_database.sh b/Docker/scripts/generate_database.sh new file mode 100644 index 00000000..892682ef --- /dev/null +++ b/Docker/scripts/generate_database.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +source ./Docker/scripts/env_functions.sh + +if [ "$DOCKER_ENV" != "true" ]; then + export_env_vars +fi + +if [[ "$DATABASE_PROVIDER" == "postgresql" || "$DATABASE_PROVIDER" == "mysql" ]]; then + export DATABASE_URL + echo "Generating database for $DATABASE_PROVIDER" + echo "Database URL: $DATABASE_URL" + npm run db:generate + if [ $? -ne 0 ]; then + echo "Prisma generate failed" + exit 1 + else + echo "Prisma generate succeeded" + fi +else + echo "Error: Database provider $DATABASE_PROVIDER invalid." + exit 1 +fi diff --git a/Docker/swarm/evolution_api_v2.yaml b/Docker/swarm/evolution_api_v2.yaml new file mode 100644 index 00000000..41c2daa2 --- /dev/null +++ b/Docker/swarm/evolution_api_v2.yaml @@ -0,0 +1,145 @@ +version: "3.7" + +services: + evolution_v2: + image: atendai/evolution-api:v2.1.2 + volumes: + - evolution_instances:/evolution/instances + networks: + - network_public + environment: + - SERVER_URL=https://evo2.site.com + - DEL_INSTANCE=false + - DATABASE_PROVIDER=postgresql + - DATABASE_CONNECTION_URI=postgresql://postgres:SENHA@postgres:5432/evolution + - DATABASE_SAVE_DATA_INSTANCE=true + - DATABASE_SAVE_DATA_NEW_MESSAGE=true + - DATABASE_SAVE_MESSAGE_UPDATE=true + - DATABASE_SAVE_DATA_CONTACTS=true + - DATABASE_SAVE_DATA_CHATS=true + - DATABASE_SAVE_DATA_LABELS=true + - DATABASE_SAVE_DATA_HISTORIC=true + - DATABASE_CONNECTION_CLIENT_NAME=evolution_v2 + - RABBITMQ_ENABLED=false + - RABBITMQ_URI=amqp://admin:admin@rabbitmq:5672/default + - RABBITMQ_EXCHANGE_NAME=evolution_v2 + - RABBITMQ_GLOBAL_ENABLED=false + - RABBITMQ_EVENTS_APPLICATION_STARTUP=false + - RABBITMQ_EVENTS_INSTANCE_CREATE=false + - RABBITMQ_EVENTS_INSTANCE_DELETE=false + - RABBITMQ_EVENTS_QRCODE_UPDATED=false + - RABBITMQ_EVENTS_MESSAGES_SET=false + - RABBITMQ_EVENTS_MESSAGES_UPSERT=true + - RABBITMQ_EVENTS_MESSAGES_EDITED=false + - RABBITMQ_EVENTS_MESSAGES_UPDATE=false + - RABBITMQ_EVENTS_MESSAGES_DELETE=false + - RABBITMQ_EVENTS_SEND_MESSAGE=false + - RABBITMQ_EVENTS_CONTACTS_SET=false + - RABBITMQ_EVENTS_CONTACTS_UPSERT=false + - RABBITMQ_EVENTS_CONTACTS_UPDATE=false + - RABBITMQ_EVENTS_PRESENCE_UPDATE=false + - RABBITMQ_EVENTS_CHATS_SET=false + - RABBITMQ_EVENTS_CHATS_UPSERT=false + - RABBITMQ_EVENTS_CHATS_UPDATE=false + - RABBITMQ_EVENTS_CHATS_DELETE=false + - RABBITMQ_EVENTS_GROUPS_UPSERT=false + - RABBITMQ_EVENTS_GROUP_UPDATE=false + - RABBITMQ_EVENTS_GROUP_PARTICIPANTS_UPDATE=false + - RABBITMQ_EVENTS_CONNECTION_UPDATE=true + - RABBITMQ_EVENTS_CALL=false + - RABBITMQ_EVENTS_TYPEBOT_START=false + - RABBITMQ_EVENTS_TYPEBOT_CHANGE_STATUS=false + - SQS_ENABLED=false + - SQS_ACCESS_KEY_ID= + - SQS_SECRET_ACCESS_KEY= + - SQS_ACCOUNT_ID= + - SQS_REGION= + - WEBSOCKET_ENABLED=false + - WEBSOCKET_GLOBAL_EVENTS=false + - WA_BUSINESS_TOKEN_WEBHOOK=evolution + - WA_BUSINESS_URL=https://graph.facebook.com + - WA_BUSINESS_VERSION=v20.0 + - WA_BUSINESS_LANGUAGE=pt_BR + - WEBHOOK_GLOBAL_URL='' + - WEBHOOK_GLOBAL_ENABLED=false + - WEBHOOK_GLOBAL_WEBHOOK_BY_EVENTS=false + - WEBHOOK_EVENTS_APPLICATION_STARTUP=false + - WEBHOOK_EVENTS_QRCODE_UPDATED=true + - WEBHOOK_EVENTS_MESSAGES_SET=true + - WEBHOOK_EVENTS_MESSAGES_UPSERT=true + - WEBHOOK_EVENTS_MESSAGES_EDITED=true + - WEBHOOK_EVENTS_MESSAGES_UPDATE=true + - WEBHOOK_EVENTS_MESSAGES_DELETE=true + - WEBHOOK_EVENTS_SEND_MESSAGE=true + - WEBHOOK_EVENTS_CONTACTS_SET=true + - WEBHOOK_EVENTS_CONTACTS_UPSERT=true + - WEBHOOK_EVENTS_CONTACTS_UPDATE=true + - WEBHOOK_EVENTS_PRESENCE_UPDATE=true + - WEBHOOK_EVENTS_CHATS_SET=true + - WEBHOOK_EVENTS_CHATS_UPSERT=true + - WEBHOOK_EVENTS_CHATS_UPDATE=true + - WEBHOOK_EVENTS_CHATS_DELETE=true + - WEBHOOK_EVENTS_GROUPS_UPSERT=true + - WEBHOOK_EVENTS_GROUPS_UPDATE=true + - WEBHOOK_EVENTS_GROUP_PARTICIPANTS_UPDATE=true + - WEBHOOK_EVENTS_CONNECTION_UPDATE=true + - WEBHOOK_EVENTS_LABELS_EDIT=true + - WEBHOOK_EVENTS_LABELS_ASSOCIATION=true + - WEBHOOK_EVENTS_CALL=true + - WEBHOOK_EVENTS_TYPEBOT_START=false + - WEBHOOK_EVENTS_TYPEBOT_CHANGE_STATUS=false + - WEBHOOK_EVENTS_ERRORS=false + - WEBHOOK_EVENTS_ERRORS_WEBHOOK= + - CONFIG_SESSION_PHONE_CLIENT=Evolution API V2 + - CONFIG_SESSION_PHONE_NAME=Chrome + - CONFIG_SESSION_PHONE_VERSION=2.3000.1015901307 + - QRCODE_LIMIT=30 + - OPENAI_ENABLED=true + - DIFY_ENABLED=true + - TYPEBOT_ENABLED=true + - TYPEBOT_API_VERSION=latest + - CHATWOOT_ENABLED=true + - CHATWOOT_MESSAGE_READ=true + - CHATWOOT_MESSAGE_DELETE=true + - CHATWOOT_IMPORT_DATABASE_CONNECTION_URI=postgresql://postgres:PASSWORD@postgres:5432/chatwoot?sslmode=disable + - CHATWOOT_IMPORT_PLACEHOLDER_MEDIA_MESSAGE=true + - CACHE_REDIS_ENABLED=true + - CACHE_REDIS_URI=redis://evo_redis:6379/1 + - CACHE_REDIS_PREFIX_KEY=evolution_v2 + - CACHE_REDIS_SAVE_INSTANCES=false + - CACHE_LOCAL_ENABLED=false + - S3_ENABLED=true + - S3_ACCESS_KEY= + - S3_SECRET_KEY= + - S3_BUCKET=evolution + - S3_PORT=443 + - S3_ENDPOINT=files.site.com + - S3_USE_SSL=true + - AUTHENTICATION_API_KEY=429683C4C977415CAAFCCE10F7D57E11 + - AUTHENTICATION_EXPOSE_IN_FETCH_INSTANCES=true + - LANGUAGE=en + deploy: + mode: replicated + replicas: 1 + placement: + constraints: + - node.hostname == evolution-manager + labels: + - traefik.enable=true + - traefik.http.routers.evolution_v2.rule=Host(`evo2.site.com`) + - traefik.http.routers.evolution_v2.entrypoints=websecure + - traefik.http.routers.evolution_v2.tls.certresolver=letsencryptresolver + - traefik.http.routers.evolution_v2.priority=1 + - traefik.http.routers.evolution_v2.service=evolution_v2 + - traefik.http.services.evolution_v2.loadbalancer.server.port=8080 + - traefik.http.services.evolution_v2.loadbalancer.passHostHeader=true + +volumes: + evolution_instances: + external: true + name: evolution_v2_data + +networks: + network_public: + external: true + name: network_public diff --git a/Dockerfile b/Dockerfile index 9db93aeb..ca61b39a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,182 +1,58 @@ -FROM node:20.7.0-alpine AS builder +FROM node:20-alpine AS builder -LABEL version="1.8.0" description="Api to control whatsapp features through http requests." +RUN apk update && \ + apk add git ffmpeg wget curl bash openssl + +LABEL version="2.2.3" description="Api to control whatsapp features through http requests." LABEL maintainer="Davidson Gomes" git="https://github.com/DavidsonGomes" -LABEL contact="contato@agenciadgcode.com" - -RUN apk update && apk upgrade && \ - apk add --no-cache git tzdata ffmpeg wget curl +LABEL contact="contato@atendai.com" WORKDIR /evolution -COPY ./package.json . +COPY ./package.json ./tsconfig.json ./ RUN npm install -COPY . . +COPY ./src ./src +COPY ./public ./public +COPY ./prisma ./prisma +COPY ./manager ./manager +COPY ./.env.example ./.env +COPY ./runWithProvider.js ./ +COPY ./tsup.config.ts ./ + +COPY ./Docker ./Docker + +RUN chmod +x ./Docker/scripts/* && dos2unix ./Docker/scripts/* + +RUN ./Docker/scripts/generate_database.sh RUN npm run build -FROM node:20.7.0-alpine AS final +FROM node:20-alpine AS final + +RUN apk update && \ + apk add tzdata ffmpeg bash openssl ENV TZ=America/Sao_Paulo -ENV DOCKER_ENV=true - -ENV SERVER_TYPE=http -ENV SERVER_PORT=8080 -ENV SERVER_URL=http://localhost:8080 - -ENV CORS_ORIGIN=* -ENV CORS_METHODS=POST,GET,PUT,DELETE -ENV CORS_CREDENTIALS=true - -ENV LOG_LEVEL=ERROR,WARN,DEBUG,INFO,LOG,VERBOSE,DARK,WEBHOOKS -ENV LOG_COLOR=true -ENV LOG_BAILEYS=error - -ENV DEL_INSTANCE=false -ENV DEL_TEMP_INSTANCES=true - -ENV STORE_MESSAGES=true -ENV STORE_MESSAGE_UP=true -ENV STORE_CONTACTS=true -ENV STORE_CHATS=true - -ENV CLEAN_STORE_CLEANING_INTERVAL=7200 -ENV CLEAN_STORE_MESSAGES=true -ENV CLEAN_STORE_MESSAGE_UP=true -ENV CLEAN_STORE_CONTACTS=true -ENV CLEAN_STORE_CHATS=true - -ENV DATABASE_ENABLED=false -ENV DATABASE_CONNECTION_URI=mongodb://root:root@mongodb:27017/?authSource=admin&readPreference=primary&ssl=false&directConnection=true -ENV DATABASE_CONNECTION_DB_PREFIX_NAME=evolution - -ENV DATABASE_SAVE_DATA_INSTANCE=false -ENV DATABASE_SAVE_DATA_NEW_MESSAGE=false -ENV DATABASE_SAVE_MESSAGE_UPDATE=false -ENV DATABASE_SAVE_DATA_CONTACTS=false -ENV DATABASE_SAVE_DATA_CHATS=false - -ENV RABBITMQ_ENABLED=false -ENV RABBITMQ_URI=amqp://guest:guest@rabbitmq:5672 -ENV RABBITMQ_EXCHANGE_NAME=evolution_exchange -ENV RABBITMQ_GLOBAL_ENABLED=false -ENV RABBITMQ_EVENTS_APPLICATION_STARTUP=false -ENV RABBITMQ_EVENTS_INSTANCE_CREATE=false -ENV RABBITMQ_EVENTS_INSTANCE_DELETE=false -ENV RABBITMQ_EVENTS_QRCODE_UPDATED=true -ENV RABBITMQ_EVENTS_MESSAGES_SET=true -ENV RABBITMQ_EVENTS_MESSAGES_UPSERT=true -ENV RABBITMQ_EVENTS_MESSAGES_UPDATE=true -ENV RABBITMQ_EVENTS_MESSAGES_DELETE=true -ENV RABBITMQ_EVENTS_SEND_MESSAGE=true -ENV RABBITMQ_EVENTS_CONTACTS_SET=true -ENV RABBITMQ_EVENTS_CONTACTS_UPSERT=true -ENV RABBITMQ_EVENTS_CONTACTS_UPDATE=true -ENV RABBITMQ_EVENTS_PRESENCE_UPDATE=true -ENV RABBITMQ_EVENTS_CHATS_SET=true -ENV RABBITMQ_EVENTS_CHATS_UPSERT=true -ENV RABBITMQ_EVENTS_CHATS_UPDATE=true -ENV RABBITMQ_EVENTS_CHATS_DELETE=true -ENV RABBITMQ_EVENTS_GROUPS_UPSERT=true -ENV RABBITMQ_EVENTS_GROUPS_UPDATE=true -ENV RABBITMQ_EVENTS_GROUP_PARTICIPANTS_UPDATE=true -ENV RABBITMQ_EVENTS_CONNECTION_UPDATE=true -ENV RABBITMQ_EVENTS_LABELS_EDIT=true -ENV RABBITMQ_EVENTS_LABELS_ASSOCIATION=true -ENV RABBITMQ_EVENTS_CALL=true -ENV RABBITMQ_EVENTS_TYPEBOT_START=false -ENV RABBITMQ_EVENTS_TYPEBOT_CHANGE_STATUS=false - -ENV WEBSOCKET_ENABLED=false -ENV WEBSOCKET_GLOBAL_EVENTS=false - -ENV WA_BUSINESS_TOKEN_WEBHOOK=evolution -ENV WA_BUSINESS_URL=https://graph.facebook.com -ENV WA_BUSINESS_VERSION=v18.0 -ENV WA_BUSINESS_LANGUAGE=pt_BR - -ENV SQS_ENABLED=false -ENV SQS_ACCESS_KEY_ID= -ENV SQS_SECRET_ACCESS_KEY= -ENV SQS_ACCOUNT_ID= -ENV SQS_REGION= - -ENV WEBHOOK_GLOBAL_URL= -ENV WEBHOOK_GLOBAL_ENABLED=false - -ENV WEBHOOK_GLOBAL_WEBHOOK_BY_EVENTS=false - -ENV WEBHOOK_EVENTS_APPLICATION_STARTUP=false -ENV WEBHOOK_EVENTS_INSTANCE_CREATE=false -ENV WEBHOOK_EVENTS_INSTANCE_DELETE=false -ENV WEBHOOK_EVENTS_QRCODE_UPDATED=true -ENV WEBHOOK_EVENTS_MESSAGES_SET=true -ENV WEBHOOK_EVENTS_MESSAGES_UPSERT=true -ENV WEBHOOK_EVENTS_MESSAGES_UPDATE=true -ENV WEBHOOK_EVENTS_MESSAGES_DELETE=true -ENV WEBHOOK_EVENTS_SEND_MESSAGE=true -ENV WEBHOOK_EVENTS_CONTACTS_SET=true -ENV WEBHOOK_EVENTS_CONTACTS_UPSERT=true -ENV WEBHOOK_EVENTS_CONTACTS_UPDATE=true -ENV WEBHOOK_EVENTS_PRESENCE_UPDATE=true -ENV WEBHOOK_EVENTS_CHATS_SET=true -ENV WEBHOOK_EVENTS_CHATS_UPSERT=true -ENV WEBHOOK_EVENTS_CHATS_UPDATE=true -ENV WEBHOOK_EVENTS_CHATS_DELETE=true -ENV WEBHOOK_EVENTS_GROUPS_UPSERT=true -ENV WEBHOOK_EVENTS_GROUPS_UPDATE=true -ENV WEBHOOK_EVENTS_GROUP_PARTICIPANTS_UPDATE=true -ENV WEBHOOK_EVENTS_CONNECTION_UPDATE=true -ENV WEBHOOK_EVENTS_LABELS_EDIT=true -ENV WEBHOOK_EVENTS_LABELS_ASSOCIATION=true -ENV WEBHOOK_EVENTS_CALL=true - -ENV WEBHOOK_EVENTS_NEW_JWT_TOKEN=false - -ENV WEBHOOK_EVENTS_TYPEBOT_START=false -ENV WEBHOOK_EVENTS_TYPEBOT_CHANGE_STATUS=false - -ENV WEBHOOK_EVENTS_CHAMA_AI_ACTION=false - -ENV WEBHOOK_EVENTS_ERRORS=false -ENV WEBHOOK_EVENTS_ERRORS_WEBHOOK= - -ENV CONFIG_SESSION_PHONE_CLIENT=EvolutionAPI -ENV CONFIG_SESSION_PHONE_NAME=Chrome - -ENV QRCODE_LIMIT=30 -ENV QRCODE_COLOR=#198754 - -ENV TYPEBOT_API_VERSION=latest - -ENV CACHE_REDIS_ENABLED=false -ENV CACHE_REDIS_URI=redis://redis:6379 -ENV CACHE_REDIS_PREFIX_KEY=evolution -ENV CACHE_REDIS_TTL=604800 -ENV CACHE_REDIS_SAVE_INSTANCES=false -ENV CACHE_LOCAL_ENABLED=false -ENV CACHE_LOCAL_TTL=604800 - -ENV AUTHENTICATION_TYPE=apikey - -ENV AUTHENTICATION_API_KEY=B6D711FCDE4D4FD5936544120E713976 -ENV AUTHENTICATION_EXPOSE_IN_FETCH_INSTANCES=true - -ENV AUTHENTICATION_JWT_EXPIRIN_IN=0 -ENV AUTHENTICATION_JWT_SECRET='L=0YWt]b2w[WF>#>:&E`' - -ENV AUTHENTICATION_INSTANCE_MODE=server - -ENV AUTHENTICATION_INSTANCE_NAME=evolution -ENV AUTHENTICATION_INSTANCE_WEBHOOK_URL= -ENV AUTHENTICATION_INSTANCE_CHATWOOT_ACCOUNT_ID=1 -ENV AUTHENTICATION_INSTANCE_CHATWOOT_TOKEN=123456 -ENV AUTHENTICATION_INSTANCE_CHATWOOT_URL= WORKDIR /evolution -COPY --from=builder /evolution . +COPY --from=builder /evolution/package.json ./package.json +COPY --from=builder /evolution/package-lock.json ./package-lock.json -CMD [ "node", "./dist/src/main.js" ] +COPY --from=builder /evolution/node_modules ./node_modules +COPY --from=builder /evolution/dist ./dist +COPY --from=builder /evolution/prisma ./prisma +COPY --from=builder /evolution/manager ./manager +COPY --from=builder /evolution/public ./public +COPY --from=builder /evolution/.env ./.env +COPY --from=builder /evolution/Docker ./Docker +COPY --from=builder /evolution/runWithProvider.js ./runWithProvider.js +COPY --from=builder /evolution/tsup.config.ts ./tsup.config.ts + +ENV DOCKER_ENV=true + +EXPOSE 8080 + +ENTRYPOINT ["/bin/bash", "-c", ". ./Docker/scripts/deploy_database.sh && npm run start:prod" ] \ No newline at end of file diff --git a/Extras/appsmith/manager.json b/Extras/appsmith/manager.json deleted file mode 100644 index 94932864..00000000 --- a/Extras/appsmith/manager.json +++ /dev/null @@ -1 +0,0 @@ -{"clientSchemaVersion":1.0,"serverSchemaVersion":6.0,"exportedApplication":{"name":"manager","isPublic":true,"pages":[{"id":"Home","isDefault":true}],"publishedPages":[{"id":"Home","isDefault":true}],"viewMode":false,"appIsExample":false,"unreadCommentThreads":0.0,"clonedFromApplicationId":"64da025f98d1c41c0da60e90","color":"#F5D1D1","icon":"email","slug":"manager","unpublishedAppLayout":{"type":"FLUID"},"publishedAppLayout":{"type":"FLUID"},"unpublishedCustomJSLibs":[],"publishedCustomJSLibs":[],"evaluationVersion":2.0,"applicationVersion":2.0,"collapseInvisibleWidgets":true,"isManualUpdate":false,"deleted":false},"datasourceList":[],"customJSLibList":[],"pageList":[{"unpublishedPage":{"name":"Home","slug":"home","customSlug":"","layouts":[{"viewMode":false,"dsl":{"widgetName":"MainContainer","backgroundColor":"none","rightColumn":4896.0,"snapColumns":64.0,"detachFromLayout":true,"widgetId":"0","topRow":0.0,"bottomRow":470.0,"containerStyle":"none","snapRows":124.0,"parentRowSpace":1.0,"type":"CANVAS_WIDGET","canExtend":true,"version":83.0,"minHeight":1292.0,"dynamicTriggerPathList":[],"parentColumnSpace":1.0,"dynamicBindingPathList":[],"leftColumn":0.0,"children":[{"boxShadow":"{{appsmith.theme.boxShadow.appBoxShadow}}","borderColor":"#E0DEDE","isVisibleDownload":true,"iconSVG":"https://appcdn.appsmith.com/static/media/icon.24905525921dd6f5ff46d0dd843b9e12.svg","topRow":6.0,"isSortable":true,"type":"TABLE_WIDGET_V2","inlineEditingSaveOption":"ROW_LEVEL","animateLoading":true,"dynamicBindingPathList":[{"key":"tableData"},{"key":"primaryColumns.customColumn9.boxShadow"},{"key":"primaryColumns.customColumn9.borderRadius"},{"key":"primaryColumns.customColumn9.menuColor"},{"key":"primaryColumns.customColumn8.computedValue"},{"key":"primaryColumns.customColumn7.computedValue"},{"key":"primaryColumns.customColumn6.computedValue"},{"key":"primaryColumns.customColumn5.computedValue"},{"key":"primaryColumns.customColumn2.computedValue"},{"key":"primaryColumns.customColumn1.textColor"},{"key":"primaryColumns.customColumn1.cellBackground"},{"key":"primaryColumns.customColumn1.computedValue"},{"key":"primaryColumns.instance.computedValue"},{"key":"isVisible"},{"key":"accentColor"},{"key":"borderRadius"},{"key":"boxShadow"}],"needsHeightForContent":true,"leftColumn":14.0,"delimiter":",","defaultSelectedRowIndex":0.0,"showInlineEditingOptionDropdown":true,"accentColor":"{{appsmith.theme.colors.primaryColor}}","isVisibleFilters":true,"isVisible":"{{appsmith.store.api_key && appsmith.store.api_url ? true : false}}","enableClientSideSearch":true,"version":2.0,"totalRecordsCount":0.0,"isLoading":false,"childStylesheet":{"button":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"menuButton":{"menuColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"iconButton":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"editActions":{"saveButtonColor":"{{appsmith.theme.colors.primaryColor}}","saveBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","discardButtonColor":"{{appsmith.theme.colors.primaryColor}}","discardBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}"}},"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","columnUpdatedAt":1.690746223636E12,"defaultSelectedRowIndices":[0.0],"mobileBottomRow":32.0,"widgetName":"TableInstances","defaultPageSize":0.0,"columnOrder":["instance","customColumn5","customColumn1","customColumn2","customColumn6","customColumn7","customColumn8","customColumn9"],"dynamicPropertyPathList":[{"key":"primaryColumns.customColumn1.cellBackground"},{"key":"isVisible"}],"displayName":"Table","bottomRow":42.0,"columnWidthMap":{"customColumn3":92.0,"customColumn2":340.0,"customColumn5":254.0,"customColumn9":60.0},"parentRowSpace":10.0,"hideCard":false,"mobileRightColumn":36.0,"parentColumnSpace":20.078125,"dynamicTriggerPathList":[{"key":"primaryColumns.customColumn9.menuItems.menuItemjfzsd8g6yr.onClick"},{"key":"primaryColumns.customColumn9.menuItems.menuItem4sqork5nmt.onClick"},{"key":"primaryColumns.customColumn9.menuItems.menuItemig6ua4ixjx.onClick"},{"key":"primaryColumns.customColumn9.menuItems.menuItemx9oyhys8cj.onClick"},{"key":"primaryColumns.customColumn9.menuItems.menuItemxk5jvvwwef.onClick"},{"key":"primaryColumns.customColumn9.menuItems.menuItem16ysonwzrq.onClick"},{"key":"primaryColumns.customColumn9.menuItems.menuItembtatfbml4y.onClick"}],"borderWidth":"1","primaryColumns":{"instance":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":0.0,"width":150.0,"originalId":"instance","id":"instance","alias":"instance","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"Instance","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{TableInstances.processedTableData.map((currentRow, currentIndex) => ( currentRow.instance.instanceName))}}","sticky":"","validation":{}},"customColumn1":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":1.0,"width":150.0,"originalId":"customColumn1","id":"customColumn1","alias":"Status","horizontalAlignment":"CENTER","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":true,"label":"Status","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{TableInstances.processedTableData.map((currentRow, currentIndex) => ( currentRow.instance.status))}}","sticky":"","validation":{},"buttonStyle":"rgb(3, 179, 101)","labelColor":"#FFFFFF","cellBackground":"{{TableInstances.processedTableData.map((currentRow, currentIndex) => ( currentRow.instance.status === \"open\" ? \"#499B51\" : currentRow.instance.status === \"close\" ? \"#DD524C\" : \"#2770FC\"))}}","textColor":"{{TableInstances.processedTableData.map((currentRow, currentIndex) => ( (appsmith.theme.colors.backgroundColor)))}}"},"customColumn2":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":2.0,"width":150.0,"originalId":"customColumn2","id":"customColumn2","alias":"Apikey","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":true,"label":"Apikey","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{TableInstances.processedTableData.map((currentRow, currentIndex) => ( currentRow.instance.apikey))}}","sticky":"","validation":{},"buttonStyle":"rgb(3, 179, 101)","labelColor":"#FFFFFF"},"customColumn5":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":5.0,"width":150.0,"originalId":"customColumn5","id":"customColumn5","alias":"Owner","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":true,"label":"Owner","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{TableInstances.processedTableData.map((currentRow, currentIndex) => ( currentRow.instance.owner))}}","sticky":"","validation":{},"buttonStyle":"rgb(3, 179, 101)","labelColor":"#FFFFFF"},"customColumn6":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":6.0,"width":150.0,"originalId":"customColumn6","id":"customColumn6","alias":"profilePictureUrl","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":false,"isDerived":true,"label":"profilePictureUrl","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{TableInstances.processedTableData.map((currentRow, currentIndex) => ( currentRow.instance.profilePictureUrl))}}","sticky":"","validation":{},"buttonStyle":"rgb(3, 179, 101)","labelColor":"#FFFFFF"},"customColumn7":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":7.0,"width":150.0,"originalId":"customColumn7","id":"customColumn7","alias":"profileName","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":false,"isDerived":true,"label":"profileName","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{TableInstances.processedTableData.map((currentRow, currentIndex) => ( currentRow.instance.profileName))}}","sticky":"","validation":{},"buttonStyle":"rgb(3, 179, 101)","labelColor":"#FFFFFF"},"customColumn8":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":8.0,"width":150.0,"originalId":"customColumn8","id":"customColumn8","alias":"profileStatus","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":false,"isDerived":true,"label":"profileStatus","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{TableInstances.processedTableData.map((currentRow, currentIndex) => ( currentRow.instance.profileStatus))}}","sticky":"","validation":{},"buttonStyle":"rgb(3, 179, 101)","labelColor":"#FFFFFF"},"customColumn9":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":9.0,"width":150.0,"originalId":"customColumn9","id":"customColumn9","alias":"#","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"menuButton","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":true,"label":"#","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"","sticky":"","validation":{},"buttonStyle":"rgb(3, 179, 101)","labelColor":"#FFFFFF","menuColor":"{{TableInstances.processedTableData.map((currentRow, currentIndex) => ( (appsmith.theme.colors.primaryColor)))}}","borderRadius":"{{TableInstances.processedTableData.map((currentRow, currentIndex) => ( (appsmith.theme.borderRadius.appBorderRadius)))}}","boxShadow":"{{TableInstances.processedTableData.map((currentRow, currentIndex) => ( \"none\"))}}","customAlias":"","menuItemsSource":"STATIC","menuButtonLabel":" ","menuButtoniconName":"chevron-down","menuItems":{"menuItemjfzsd8g6yr":{"id":"menuItemjfzsd8g6yr","index":0.0,"label":"Webhook","widgetId":"vygcejtdun","isDisabled":false,"isVisible":true,"onClick":"{{Find_Webhook.run({\n //\"key\": \"value\",\n});\nshowModal('ModalWebhook');}}"},"menuItem4sqork5nmt":{"id":"menuItem4sqork5nmt","index":1.0,"label":"Settings","widgetId":"0hw8oqpwcj","isDisabled":false,"isVisible":true,"onClick":"{{Find_Settings.run();\nshowModal('ModalSettings');}}"},"menuItemx9oyhys8cj":{"id":"menuItemx9oyhys8cj","index":2.0,"label":"Websocket","widgetId":"j75a4k6ecq","isDisabled":false,"isVisible":true,"onClick":"{{Find_Websocket.run();\nshowModal('ModalWebsocket');}}"},"menuItemxk5jvvwwef":{"id":"menuItemxk5jvvwwef","index":3.0,"label":"Rabbitmq","widgetId":"3u94ov6qst","isDisabled":false,"isVisible":true,"onClick":"{{Find_Rabbitmq.run();\nshowModal('ModalRabbitmq');}}"},"menuItemig6ua4ixjx":{"id":"menuItemig6ua4ixjx","index":4.0,"label":"Chatwoot","widgetId":"fuq5dtgbqc","isDisabled":false,"isVisible":true,"onClick":"{{Find_Chatwoot.run()\nshowModal('ModalChatwoot');}}"},"menuItem16ysonwzrq":{"id":"menuItem16ysonwzrq","index":5.0,"label":"Set Typebot","widgetId":"fi9nb2bace","isDisabled":false,"isVisible":true,"onClick":"{{Find_Typebot.run()\nshowModal('ModalTypebot');}}"},"menuItembtatfbml4y":{"id":"menuItembtatfbml4y","index":6.0,"label":"TypeBot Set Session Status","widgetId":"7f6mg653ra","isDisabled":false,"isVisible":true,"onClick":"{{showModal('ModalTypebotChangeSessionStatu');}}"}}}},"key":"e3yxhhyeel","canFreezeColumn":true,"isDeprecated":false,"rightColumn":63.0,"textSize":"0.875rem","widgetId":"uupm7enu8u","minWidth":450.0,"tableData":"{{fetch_Instances.data}}","label":"Data","searchKey":"","parentId":"0","renderMode":"CANVAS","mobileTopRow":4.0,"horizontalAlignment":"LEFT","isVisibleSearch":true,"responsiveBehavior":"fill","mobileLeftColumn":2.0,"isVisiblePagination":true,"verticalAlignment":"CENTER"},{"resetFormOnClick":false,"boxShadow":"none","mobileBottomRow":5.0,"widgetName":"BtnNewInstance","onClick":"{{showModal('ModalInstance');}}","buttonColor":"rgb(3, 179, 101)","dynamicPropertyPathList":[{"key":"isVisible"}],"displayName":"Button","iconSVG":"/static/media/icon.7beb9123fb53027d9d6b778cdfe4caed.svg","searchTags":["click","submit"],"topRow":1.0,"bottomRow":5.0,"parentRowSpace":10.0,"type":"BUTTON_WIDGET","hideCard":false,"mobileRightColumn":8.0,"animateLoading":true,"parentColumnSpace":11.828125,"dynamicTriggerPathList":[{"key":"onClick"}],"leftColumn":7.0,"dynamicBindingPathList":[{"key":"isVisible"},{"key":"borderRadius"}],"text":"New Instance","isDisabled":false,"key":"crzwqv3pdr","isDeprecated":false,"rightColumn":19.0,"isDefaultClickDisabled":true,"iconName":"add","widgetId":"84ei9q1ugm","minWidth":120.0,"isVisible":"{{appsmith.store.api_key && appsmith.store.api_url ? true : false}}","recaptchaType":"V3","version":1.0,"parentId":"0","renderMode":"CANVAS","isLoading":false,"mobileTopRow":1.0,"responsiveBehavior":"hug","disabledWhenInvalid":false,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":0.0,"buttonVariant":"PRIMARY","iconAlign":"left","placement":"CENTER"},{"boxShadow":"none","mobileBottomRow":74.0,"widgetName":"ModalQrcode","isCanvas":true,"displayName":"Modal","iconSVG":"/static/media/icon.d2ab7de0666eaef853cc2d330f86887b.svg","searchTags":["dialog","popup","notification"],"topRow":50.0,"bottomRow":500.0,"parentRowSpace":10.0,"type":"MODAL_WIDGET","hideCard":false,"shouldScrollContents":true,"mobileRightColumn":45.0,"animateLoading":true,"parentColumnSpace":11.828125,"leftColumn":21.0,"dynamicBindingPathList":[{"key":"borderRadius"}],"children":[{"mobileBottomRow":240.0,"widgetName":"Canvas1","displayName":"Canvas","topRow":0.0,"bottomRow":450.0,"parentRowSpace":1.0,"type":"CANVAS_WIDGET","canExtend":true,"hideCard":true,"shouldScrollContents":false,"minHeight":240.0,"mobileRightColumn":283.875,"parentColumnSpace":1.0,"leftColumn":0.0,"dynamicBindingPathList":[],"children":[{"boxShadow":"none","mobileBottomRow":52.0,"widgetName":"ImageQrcode","displayName":"Image","iconSVG":"https://appcdn.appsmith.com/static/media/icon.30c8cbd442cce232b01ba2d434c53a53.svg","topRow":6.0,"bottomRow":43.0,"parentRowSpace":10.0,"type":"IMAGE_WIDGET","hideCard":false,"mobileRightColumn":55.0,"animateLoading":true,"parentColumnSpace":20.078125,"dynamicTriggerPathList":[],"imageShape":"RECTANGLE","leftColumn":2.0,"dynamicBindingPathList":[{"key":"borderRadius"},{"key":"image"}],"defaultImage":"https://manualnegocioonline.com.br/downloads/evolution-api-favicon2.png","key":"4chlj9l432","image":"{{Connect.data.base64}}","isDeprecated":false,"rightColumn":61.0,"objectFit":"contain","widgetId":"27dpgapd7q","isVisible":true,"version":1.0,"parentId":"we6j3r2byy","renderMode":"CANVAS","isLoading":false,"mobileTopRow":40.0,"maxZoomLevel":1.0,"enableDownload":false,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":43.0,"enableRotation":false},{"boxShadow":"none","mobileBottomRow":4.0,"widgetName":"IconButton1","onClick":"{{closeModal('ModalQrcode');\nfetch_Instances.run()}}","buttonColor":"{{appsmith.theme.colors.primaryColor}}","displayName":"Icon button","iconSVG":"/static/media/icon.80fc7466c0d7181ec0271de7fda795ec.svg","searchTags":["click","submit"],"topRow":0.0,"bottomRow":4.0,"type":"ICON_BUTTON_WIDGET","hideCard":false,"mobileRightColumn":64.0,"animateLoading":true,"dynamicTriggerPathList":[{"key":"onClick"}],"leftColumn":58.0,"dynamicBindingPathList":[{"key":"buttonColor"},{"key":"borderRadius"}],"iconSize":24.0,"isDisabled":false,"key":"pezy0hb491","isDeprecated":false,"rightColumn":64.0,"iconName":"cross","widgetId":"i1dw369dch","minWidth":50.0,"isVisible":true,"version":1.0,"parentId":"we6j3r2byy","renderMode":"CANVAS","isLoading":false,"mobileTopRow":0.0,"responsiveBehavior":"hug","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":58.0,"buttonVariant":"TERTIARY"},{"mobileBottomRow":5.0,"widgetName":"Text1","displayName":"Text","iconSVG":"/static/media/icon.c3b6033f570046f8c6288d911333a827.svg","searchTags":["typography","paragraph","label"],"topRow":1.0,"bottomRow":5.0,"type":"TEXT_WIDGET","hideCard":false,"mobileRightColumn":41.0,"animateLoading":true,"overflow":"NONE","fontFamily":"{{appsmith.theme.fontFamily.appFont}}","dynamicTriggerPathList":[],"leftColumn":1.0,"dynamicBindingPathList":[{"key":"fontFamily"}],"shouldTruncate":false,"truncateButtonColor":"{{appsmith.theme.colors.primaryColor}}","text":"Qrcode","key":"9s8f10sepn","isDeprecated":false,"rightColumn":41.0,"textAlign":"LEFT","dynamicHeight":"AUTO_HEIGHT","widgetId":"mg2cqsi9fn","minWidth":450.0,"isVisible":true,"fontStyle":"BOLD","textColor":"#231F20","version":1.0,"parentId":"we6j3r2byy","renderMode":"CANVAS","isLoading":false,"mobileTopRow":1.0,"responsiveBehavior":"fill","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":1.0,"maxDynamicHeight":9000.0,"fontSize":"1.25rem","minDynamicHeight":4.0}],"isDisabled":false,"key":"e8r23nd8j4","isDeprecated":false,"rightColumn":283.875,"detachFromLayout":true,"widgetId":"we6j3r2byy","minWidth":450.0,"isVisible":true,"version":1.0,"parentId":"ljwryrjhy7","renderMode":"CANVAS","isLoading":false,"mobileTopRow":0.0,"responsiveBehavior":"fill","mobileLeftColumn":0.0,"flexLayers":[]}],"key":"g8xx6ocuvi","height":450.0,"isDeprecated":false,"rightColumn":45.0,"detachFromLayout":true,"dynamicHeight":"AUTO_HEIGHT","widgetId":"ljwryrjhy7","canOutsideClickClose":true,"canEscapeKeyClose":true,"version":2.0,"parentId":"0","renderMode":"CANVAS","isLoading":false,"mobileTopRow":50.0,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":21.0,"maxDynamicHeight":9000.0,"width":456.0,"minDynamicHeight":24.0},{"resetFormOnClick":false,"boxShadow":"none","mobileBottomRow":5.0,"widgetName":"BtnConfig","onClick":"{{showModal('ModalConfig');}}","buttonColor":"#2563eb","dynamicPropertyPathList":[],"displayName":"Button","iconSVG":"/static/media/icon.7beb9123fb53027d9d6b778cdfe4caed.svg","searchTags":["click","submit"],"topRow":1.0,"bottomRow":5.0,"parentRowSpace":10.0,"type":"BUTTON_WIDGET","hideCard":false,"mobileRightColumn":30.0,"animateLoading":true,"parentColumnSpace":11.828125,"dynamicTriggerPathList":[{"key":"onClick"}],"leftColumn":1.0,"dynamicBindingPathList":[{"key":"borderRadius"}],"text":"Access","isDisabled":false,"key":"crzwqv3pdr","isDeprecated":false,"rightColumn":7.0,"isDefaultClickDisabled":true,"iconName":"user","widgetId":"uegjpy37i6","minWidth":120.0,"isVisible":true,"recaptchaType":"V3","version":1.0,"parentId":"0","renderMode":"CANVAS","isLoading":false,"mobileTopRow":1.0,"responsiveBehavior":"hug","disabledWhenInvalid":false,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":14.0,"buttonVariant":"PRIMARY","iconAlign":"left","placement":"CENTER"},{"boxShadow":"none","mobileBottomRow":73.0,"widgetName":"ModalConfig","isCanvas":true,"displayName":"Modal","iconSVG":"/static/media/icon.d2ab7de0666eaef853cc2d330f86887b.svg","searchTags":["dialog","popup","notification"],"topRow":49.0,"bottomRow":30.0,"parentRowSpace":10.0,"type":"MODAL_WIDGET","hideCard":false,"shouldScrollContents":true,"mobileRightColumn":25.0,"minHeight":300.0,"animateLoading":true,"parentColumnSpace":11.75,"leftColumn":1.0,"dynamicBindingPathList":[{"key":"borderRadius"}],"children":[{"mobileBottomRow":240.0,"widgetName":"Canvas2","displayName":"Canvas","topRow":0.0,"bottomRow":300.0,"parentRowSpace":1.0,"type":"CANVAS_WIDGET","canExtend":true,"hideCard":true,"shouldScrollContents":false,"minHeight":300.0,"mobileRightColumn":282.0,"parentColumnSpace":1.0,"leftColumn":0.0,"dynamicBindingPathList":[],"children":[{"boxShadow":"none","mobileBottomRow":84.0,"borderColor":"#E0DEDE","widgetName":"FormConfig","isCanvas":true,"displayName":"Form","iconSVG":"/static/media/icon.5d6d2ac5cb1aa68bcd9b14f11c56b44a.svg","searchTags":["group"],"topRow":0.0,"bottomRow":28.0,"parentRowSpace":10.0,"type":"FORM_WIDGET","hideCard":false,"shouldScrollContents":true,"mobileRightColumn":25.0,"animateLoading":true,"parentColumnSpace":11.828125,"dynamicTriggerPathList":[],"leftColumn":1.0,"dynamicBindingPathList":[],"children":[{"mobileBottomRow":400.0,"widgetName":"Canvas2Copy","displayName":"Canvas","topRow":0.0,"bottomRow":280.0,"parentRowSpace":1.0,"type":"CANVAS_WIDGET","canExtend":false,"hideCard":true,"minHeight":400.0,"mobileRightColumn":283.875,"parentColumnSpace":1.0,"leftColumn":0.0,"dynamicBindingPathList":[],"children":[{"mobileBottomRow":5.0,"widgetName":"Text2","displayName":"Text","iconSVG":"/static/media/icon.c3b6033f570046f8c6288d911333a827.svg","searchTags":["typography","paragraph","label"],"topRow":1.0,"bottomRow":5.0,"type":"TEXT_WIDGET","hideCard":false,"mobileRightColumn":25.5,"animateLoading":true,"overflow":"NONE","fontFamily":"{{appsmith.theme.fontFamily.appFont}}","dynamicTriggerPathList":[],"leftColumn":1.5,"dynamicBindingPathList":[{"key":"fontFamily"}],"shouldTruncate":false,"truncateButtonColor":"{{appsmith.theme.colors.primaryColor}}","text":"Access Credentials","key":"9s8f10sepn","isDeprecated":false,"rightColumn":25.5,"textAlign":"LEFT","dynamicHeight":"AUTO_HEIGHT","widgetId":"tps5rw2lk9","minWidth":450.0,"isVisible":true,"fontStyle":"BOLD","textColor":"#231F20","version":1.0,"parentId":"lrtvcpswru","renderMode":"CANVAS","isLoading":false,"mobileTopRow":1.0,"responsiveBehavior":"fill","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":1.5,"maxDynamicHeight":9000.0,"fontSize":"1.25rem","minDynamicHeight":4.0},{"resetFormOnClick":true,"boxShadow":"none","mobileBottomRow":37.0,"widgetName":"Button1","onClick":"{{storeValue('api_url', FormConfig.data.InputApiUrl);\nstoreValue('api_key', FormConfig.data.InputGlobalApiKey);\nfetch_Instances.run().then(() => {\n showAlert('successful login', 'success');\n}).catch(() => {\n showAlert('Could not load instances', 'error');\n});\ncloseModal('ModalConfig').then(() => {});}}","buttonColor":"{{appsmith.theme.colors.primaryColor}}","dynamicPropertyPathList":[{"key":"isDisabled"}],"displayName":"Button","iconSVG":"/static/media/icon.7beb9123fb53027d9d6b778cdfe4caed.svg","searchTags":["click","submit"],"topRow":22.0,"bottomRow":26.0,"type":"BUTTON_WIDGET","hideCard":false,"mobileRightColumn":62.0,"animateLoading":true,"dynamicTriggerPathList":[{"key":"onClick"}],"leftColumn":51.0,"dynamicBindingPathList":[{"key":"buttonColor"},{"key":"borderRadius"}],"text":"Login","isDisabled":"","key":"crzwqv3pdr","isDeprecated":false,"rightColumn":63.0,"isDefaultClickDisabled":true,"iconName":"log-in","widgetId":"gzxvnsxk0y","minWidth":120.0,"isVisible":true,"recaptchaType":"V3","version":1.0,"parentId":"lrtvcpswru","renderMode":"CANVAS","isLoading":false,"mobileTopRow":33.0,"responsiveBehavior":"hug","disabledWhenInvalid":true,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":46.0,"buttonVariant":"PRIMARY","iconAlign":"left","placement":"CENTER"},{"resetFormOnClick":true,"boxShadow":"none","mobileBottomRow":37.0,"widgetName":"Button1Copy","onClick":"{{removeValue('api_url');\nremoveValue('api_key').then(() => {\n showAlert('successful logout', 'success');\n});}}","buttonColor":"#dc2626","dynamicPropertyPathList":[{"key":"isDisabled"}],"displayName":"Button","iconSVG":"/static/media/icon.7beb9123fb53027d9d6b778cdfe4caed.svg","searchTags":["click","submit"],"topRow":21.0,"bottomRow":25.0,"type":"BUTTON_WIDGET","hideCard":false,"mobileRightColumn":62.0,"animateLoading":true,"dynamicTriggerPathList":[{"key":"onClick"}],"leftColumn":2.0,"dynamicBindingPathList":[{"key":"isDisabled"},{"key":"borderRadius"}],"text":"Logout","isDisabled":"{{!appsmith.store.api_key && !appsmith.store.api_url ? true : false}}","key":"crzwqv3pdr","isDeprecated":false,"rightColumn":14.0,"isDefaultClickDisabled":true,"iconName":"log-out","widgetId":"f2i8tsbgx1","minWidth":120.0,"isVisible":true,"recaptchaType":"V3","version":1.0,"parentId":"lrtvcpswru","renderMode":"CANVAS","isLoading":false,"mobileTopRow":33.0,"responsiveBehavior":"hug","disabledWhenInvalid":false,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":46.0,"buttonVariant":"PRIMARY","iconAlign":"left","placement":"CENTER"},{"boxShadow":"none","iconSVG":"/static/media/icon.d0ce957b6c4640f8a7418ce846ee200e.svg","topRow":6.0,"labelWidth":5.0,"type":"INPUT_WIDGET_V2","animateLoading":true,"resetOnSubmit":true,"leftColumn":2.0,"dynamicBindingPathList":[{"key":"defaultText"},{"key":"accentColor"},{"key":"borderRadius"}],"labelStyle":"","inputType":"TEXT","placeholderText":"","isDisabled":false,"isRequired":true,"dynamicHeight":"FIXED","accentColor":"{{appsmith.theme.colors.primaryColor}}","showStepArrows":false,"isVisible":true,"version":2.0,"isLoading":false,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileBottomRow":13.0,"widgetName":"InputApiUrl","displayName":"Input","searchTags":["form","text input","number","textarea"],"bottomRow":13.0,"parentRowSpace":10.0,"autoFocus":false,"hideCard":false,"mobileRightColumn":22.0,"parentColumnSpace":5.047119140625,"dynamicTriggerPathList":[],"labelPosition":"Top","key":"r1hfat3ouf","labelTextSize":"0.875rem","isDeprecated":false,"rightColumn":63.0,"widgetId":"spgryrb5ao","minWidth":450.0,"label":"API URL","parentId":"lrtvcpswru","labelAlignment":"left","renderMode":"CANVAS","mobileTopRow":6.0,"responsiveBehavior":"fill","mobileLeftColumn":2.0,"maxDynamicHeight":9000.0,"isSpellCheck":false,"iconAlign":"left","defaultText":"{{appsmith.store.api_url || ''}}","minDynamicHeight":4.0},{"boxShadow":"none","iconSVG":"/static/media/icon.d0ce957b6c4640f8a7418ce846ee200e.svg","topRow":14.0,"labelWidth":5.0,"type":"INPUT_WIDGET_V2","animateLoading":true,"resetOnSubmit":true,"leftColumn":2.0,"dynamicBindingPathList":[{"key":"defaultText"},{"key":"accentColor"},{"key":"borderRadius"}],"labelStyle":"","inputType":"PASSWORD","isDisabled":false,"isRequired":true,"dynamicHeight":"FIXED","accentColor":"{{appsmith.theme.colors.primaryColor}}","showStepArrows":false,"isVisible":true,"version":2.0,"isLoading":false,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileBottomRow":13.0,"widgetName":"InputGlobalApiKey","displayName":"Input","searchTags":["form","text input","number","textarea"],"bottomRow":21.0,"parentRowSpace":10.0,"autoFocus":false,"hideCard":false,"mobileRightColumn":22.0,"parentColumnSpace":5.047119140625,"dynamicTriggerPathList":[],"labelPosition":"Top","key":"r1hfat3ouf","labelTextSize":"0.875rem","isDeprecated":false,"rightColumn":63.0,"widgetId":"v2vedr13py","minWidth":450.0,"label":"GLOBAL API KEY","parentId":"lrtvcpswru","labelAlignment":"left","renderMode":"CANVAS","mobileTopRow":6.0,"responsiveBehavior":"fill","mobileLeftColumn":2.0,"maxDynamicHeight":9000.0,"shouldAllowAutofill":true,"iconAlign":"left","defaultText":"{{appsmith.store.api_key || ''}}","minDynamicHeight":4.0},{"boxShadow":"none","mobileBottomRow":4.0,"widgetName":"IconButton2","onClick":"{{closeModal('ModalConfig');}}","buttonColor":"{{appsmith.theme.colors.primaryColor}}","displayName":"Icon button","iconSVG":"/static/media/icon.80fc7466c0d7181ec0271de7fda795ec.svg","searchTags":["click","submit"],"topRow":0.0,"bottomRow":4.0,"parentRowSpace":10.0,"type":"ICON_BUTTON_WIDGET","hideCard":false,"mobileRightColumn":64.0,"animateLoading":true,"parentColumnSpace":9.072265625,"dynamicTriggerPathList":[{"key":"onClick"}],"leftColumn":60.0,"dynamicBindingPathList":[{"key":"buttonColor"},{"key":"borderRadius"}],"isDisabled":false,"key":"pezy0hb491","isDeprecated":false,"rightColumn":64.0,"iconName":"cross","widgetId":"oaouelmhi1","minWidth":50.0,"isVisible":true,"version":1.0,"parentId":"lrtvcpswru","renderMode":"CANVAS","isLoading":false,"mobileTopRow":0.0,"responsiveBehavior":"hug","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":60.0,"buttonVariant":"TERTIARY"}],"key":"e8r23nd8j4","isDeprecated":false,"rightColumn":283.875,"detachFromLayout":true,"widgetId":"lrtvcpswru","containerStyle":"none","minWidth":450.0,"isVisible":true,"version":1.0,"parentId":"h97rbttd5c","renderMode":"CANVAS","isLoading":false,"mobileTopRow":0.0,"responsiveBehavior":"fill","mobileLeftColumn":0.0,"flexLayers":[]}],"borderWidth":"0","positioning":"fixed","key":"dtzd07zsya","backgroundColor":"#FFFFFF","isDeprecated":false,"rightColumn":63.0,"dynamicHeight":"AUTO_HEIGHT","widgetId":"h97rbttd5c","minWidth":450.0,"isVisible":true,"parentId":"es5gsctogb","renderMode":"CANVAS","isLoading":false,"mobileTopRow":44.0,"responsiveBehavior":"fill","originalTopRow":0.0,"borderRadius":"0.375rem","mobileLeftColumn":1.0,"maxDynamicHeight":9000.0,"originalBottomRow":28.0,"minDynamicHeight":10.0}],"isDisabled":false,"key":"e8r23nd8j4","isDeprecated":false,"rightColumn":282.0,"detachFromLayout":true,"widgetId":"es5gsctogb","minWidth":450.0,"isVisible":true,"version":1.0,"parentId":"gneh33z88k","renderMode":"CANVAS","isLoading":false,"mobileTopRow":0.0,"responsiveBehavior":"fill","mobileLeftColumn":0.0,"flexLayers":[]}],"key":"g8xx6ocuvi","height":300.0,"isDeprecated":false,"rightColumn":25.0,"detachFromLayout":true,"dynamicHeight":"AUTO_HEIGHT","widgetId":"gneh33z88k","canOutsideClickClose":true,"canEscapeKeyClose":true,"version":2.0,"parentId":"0","renderMode":"CANVAS","isLoading":false,"mobileTopRow":49.0,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":1.0,"maxDynamicHeight":9000.0,"width":632.0,"minDynamicHeight":24.0},{"boxShadow":"none","mobileBottomRow":66.0,"widgetName":"ModalInstance","isCanvas":true,"displayName":"Modal","iconSVG":"/static/media/icon.d2ab7de0666eaef853cc2d330f86887b.svg","searchTags":["dialog","popup","notification"],"topRow":42.0,"bottomRow":1892.0,"parentRowSpace":10.0,"type":"MODAL_WIDGET","hideCard":false,"shouldScrollContents":true,"mobileRightColumn":37.0,"minHeight":1850.0,"animateLoading":true,"parentColumnSpace":11.828125,"leftColumn":13.0,"dynamicBindingPathList":[{"key":"borderRadius"}],"children":[{"mobileBottomRow":240.0,"widgetName":"Canvas3","displayName":"Canvas","topRow":0.0,"bottomRow":1850.0,"parentRowSpace":1.0,"type":"CANVAS_WIDGET","canExtend":true,"hideCard":true,"shouldScrollContents":false,"minHeight":1140.0,"mobileRightColumn":283.875,"parentColumnSpace":1.0,"leftColumn":0.0,"dynamicBindingPathList":[],"children":[{"boxShadow":"none","mobileBottomRow":4.0,"widgetName":"IconButton3Copy","onClick":"{{closeModal('ModalInstance');}}","buttonColor":"{{appsmith.theme.colors.primaryColor}}","displayName":"Icon button","iconSVG":"/static/media/icon.80fc7466c0d7181ec0271de7fda795ec.svg","searchTags":["click","submit"],"topRow":0.0,"bottomRow":4.0,"type":"ICON_BUTTON_WIDGET","hideCard":false,"mobileRightColumn":64.0,"animateLoading":true,"dynamicTriggerPathList":[{"key":"onClick"}],"leftColumn":57.0,"dynamicBindingPathList":[{"key":"buttonColor"},{"key":"borderRadius"}],"iconSize":24.0,"isDisabled":false,"key":"mr6bto7c8j","isDeprecated":false,"rightColumn":63.0,"iconName":"cross","widgetId":"xofakp4har","minWidth":50.0,"isVisible":true,"version":1.0,"parentId":"esgwuzqcwt","renderMode":"CANVAS","isLoading":false,"mobileTopRow":0.0,"responsiveBehavior":"hug","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":58.0,"buttonVariant":"TERTIARY"},{"boxShadow":"none","borderColor":"#E0DEDE","iconSVG":"/static/media/icon.efac588608711d232f1c6c8a2144d2dd.svg","onSubmit":"{{Create_Instance.run().then(() => {\n showAlert('Instance created successfully', 'success');\n}).catch(() => {\n showAlert('Error creating instance', 'error');\n});\nfetch_Instances.run();\ncloseModal('ModalInstance');}}","topRow":4.0,"type":"JSON_FORM_WIDGET","animateLoading":true,"leftColumn":0.0,"dynamicBindingPathList":[{"key":"borderRadius"},{"key":"resetButtonStyles.buttonColor"},{"key":"schema.__root_schema__.defaultValue"},{"key":"schema.__root_schema__.borderRadius"},{"key":"schema.__root_schema__.children.webhook.defaultValue"},{"key":"schema.__root_schema__.children.webhook.borderRadius"},{"key":"schema.__root_schema__.cellBorderRadius"},{"key":"schema.__root_schema__.children.instance.defaultValue"},{"key":"schema.__root_schema__.children.instance.borderRadius"},{"key":"schema.__root_schema__.children.instance.cellBorderRadius"},{"key":"schema.__root_schema__.children.instance.children.instanceName.defaultValue"},{"key":"schema.__root_schema__.children.instance.children.instanceName.accentColor"},{"key":"schema.__root_schema__.children.instance.children.instanceName.borderRadius"},{"key":"schema.__root_schema__.children.instance.children.token.defaultValue"},{"key":"schema.__root_schema__.children.instance.children.token.accentColor"},{"key":"schema.__root_schema__.children.instance.children.token.borderRadius"},{"key":"schema.__root_schema__.children.webhook.cellBorderRadius"},{"key":"schema.__root_schema__.children.webhook.children.webhook.defaultValue"},{"key":"schema.__root_schema__.children.webhook.children.webhook.accentColor"},{"key":"schema.__root_schema__.children.webhook.children.webhook.borderRadius"},{"key":"schema.__root_schema__.children.webhook.children.events.defaultValue"},{"key":"schema.__root_schema__.children.webhook.children.events.accentColor"},{"key":"schema.__root_schema__.children.webhook.children.events.borderRadius"},{"key":"schema.__root_schema__.children.webhook.children.webhook_by_events.defaultValue"},{"key":"schema.__root_schema__.children.webhook.children.webhook_by_events.accentColor"},{"key":"schema.__root_schema__.children.settings.defaultValue"},{"key":"schema.__root_schema__.children.settings.borderRadius"},{"key":"schema.__root_schema__.children.settings.cellBorderRadius"},{"key":"schema.__root_schema__.children.settings.children.reject_call.defaultValue"},{"key":"schema.__root_schema__.children.settings.children.reject_call.accentColor"},{"key":"schema.__root_schema__.children.settings.children.msg_call.defaultValue"},{"key":"schema.__root_schema__.children.settings.children.msg_call.accentColor"},{"key":"schema.__root_schema__.children.settings.children.msg_call.borderRadius"},{"key":"schema.__root_schema__.children.settings.children.groups_ignore.defaultValue"},{"key":"schema.__root_schema__.children.settings.children.groups_ignore.accentColor"},{"key":"schema.__root_schema__.children.settings.children.always_online.defaultValue"},{"key":"schema.__root_schema__.children.settings.children.always_online.accentColor"},{"key":"schema.__root_schema__.children.settings.children.read_messages.defaultValue"},{"key":"schema.__root_schema__.children.settings.children.read_messages.accentColor"},{"key":"schema.__root_schema__.children.settings.children.read_status.defaultValue"},{"key":"schema.__root_schema__.children.settings.children.read_status.accentColor"},{"key":"schema.__root_schema__.children.chatwoot.defaultValue"},{"key":"schema.__root_schema__.children.chatwoot.borderRadius"},{"key":"schema.__root_schema__.children.chatwoot.cellBorderRadius"},{"key":"schema.__root_schema__.children.chatwoot.children.chatwoot_account_id.defaultValue"},{"key":"schema.__root_schema__.children.chatwoot.children.chatwoot_account_id.accentColor"},{"key":"schema.__root_schema__.children.chatwoot.children.chatwoot_account_id.borderRadius"},{"key":"schema.__root_schema__.children.chatwoot.children.chatwoot_token.defaultValue"},{"key":"schema.__root_schema__.children.chatwoot.children.chatwoot_token.accentColor"},{"key":"schema.__root_schema__.children.chatwoot.children.chatwoot_token.borderRadius"},{"key":"schema.__root_schema__.children.chatwoot.children.chatwoot_url.defaultValue"},{"key":"schema.__root_schema__.children.chatwoot.children.chatwoot_url.accentColor"},{"key":"schema.__root_schema__.children.chatwoot.children.chatwoot_url.borderRadius"},{"key":"schema.__root_schema__.children.chatwoot.children.chatwoot_sign_msg.defaultValue"},{"key":"schema.__root_schema__.children.chatwoot.children.chatwoot_sign_msg.accentColor"},{"key":"schema.__root_schema__.children.chatwoot.children.chatwoot_reopen_conversation.defaultValue"},{"key":"schema.__root_schema__.children.chatwoot.children.chatwoot_reopen_conversation.accentColor"},{"key":"schema.__root_schema__.children.chatwoot.children.chatwoot_conversation_pending.defaultValue"},{"key":"schema.__root_schema__.children.chatwoot.children.chatwoot_conversation_pending.accentColor"},{"key":"schema.__root_schema__.children.instance.children.qrcode.defaultValue"},{"key":"schema.__root_schema__.children.instance.children.qrcode.accentColor"},{"key":"schema.__root_schema__.children.websocket.defaultValue"},{"key":"schema.__root_schema__.children.websocket.borderRadius"},{"key":"schema.__root_schema__.children.websocket.cellBorderRadius"},{"key":"schema.__root_schema__.children.websocket.children.websocket_enabled.defaultValue"},{"key":"schema.__root_schema__.children.websocket.children.websocket_enabled.accentColor"},{"key":"schema.__root_schema__.children.websocket.children.websocket_events.defaultValue"},{"key":"schema.__root_schema__.children.websocket.children.websocket_events.accentColor"},{"key":"schema.__root_schema__.children.websocket.children.websocket_events.borderRadius"},{"key":"schema.__root_schema__.children.rabbitmq.defaultValue"},{"key":"schema.__root_schema__.children.rabbitmq.borderRadius"},{"key":"schema.__root_schema__.children.rabbitmq.cellBorderRadius"},{"key":"schema.__root_schema__.children.rabbitmq.children.rabbitmq_enabled.defaultValue"},{"key":"schema.__root_schema__.children.rabbitmq.children.rabbitmq_enabled.accentColor"},{"key":"schema.__root_schema__.children.rabbitmq.children.rabbitmq_events.defaultValue"},{"key":"schema.__root_schema__.children.rabbitmq.children.rabbitmq_events.accentColor"},{"key":"schema.__root_schema__.children.rabbitmq.children.rabbitmq_events.borderRadius"}],"showReset":true,"dynamicHeight":"AUTO_HEIGHT","autoGenerateForm":true,"resetButtonStyles":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","buttonVariant":"SECONDARY","iconAlign":"left"},"isVisible":true,"version":1.0,"isLoading":false,"submitButtonLabel":"Create","childStylesheet":{"ARRAY":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","cellBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","cellBoxShadow":"none"},"OBJECT":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","cellBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","cellBoxShadow":"none"},"CHECKBOX":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}"},"CURRENCY_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"DATEPICKER":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"EMAIL_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTISELECT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTILINE_TEXT_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"NUMBER_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PASSWORD_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PHONE_NUMBER_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"RADIO_GROUP":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"SELECT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"SWITCH":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"TEXT_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"}},"disabledWhenInvalid":true,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","originalBottomRow":183.0,"useSourceData":false,"schema":{"__root_schema__":{"children":{"webhook":{"children":{"webhook":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.webhook.webhook))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Text Input","sourceData":"","isCustomField":false,"accessor":"webhook","identifier":"webhook","position":0.0,"originalIdentifier":"webhook","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Webhook"},"events":{"children":{},"dataType":"array","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.webhook.events))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Multiselect","sourceData":["APPLICATION_STARTUP","QRCODE_UPDATED","MESSAGES_SET","MESSAGES_UPSERT","MESSAGES_UPDATE","MESSAGES_DELETE","SEND_MESSAGE","CONTACTS_SET","CONTACTS_UPSERT","CONTACTS_UPDATE","PRESENCE_UPDATE","CHATS_SET","CHATS_UPSERT","CHATS_UPDATE","CHATS_DELETE","GROUPS_UPSERT","GROUP_UPDATE","GROUP_PARTICIPANTS_UPDATE","CONNECTION_UPDATE","CALL","NEW_JWT_TOKEN"],"isCustomField":false,"accessor":"events","identifier":"events","position":2.0,"originalIdentifier":"events","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","isDisabled":false,"isFilterable":false,"isRequired":false,"isVisible":true,"label":"Events","labelTextSize":"0.875rem","serverSideFiltering":false,"options":"[\n {\n \"label\": \"APPLICATION_STARTUP\",\n \"value\": \"APPLICATION_STARTUP\"\n },\n {\n \"label\": \"QRCODE_UPDATED\",\n \"value\": \"QRCODE_UPDATED\"\n },\n {\n \"label\": \"MESSAGES_SET\",\n \"value\": \"MESSAGES_SET\"\n },\n {\n \"label\": \"MESSAGES_UPSERT\",\n \"value\": \"MESSAGES_UPSERT\"\n },\n {\n \"label\": \"MESSAGES_UPDATE\",\n \"value\": \"MESSAGES_UPDATE\"\n },\n {\n \"label\": \"MESSAGES_DELETE\",\n \"value\": \"MESSAGES_DELETE\"\n },\n {\n \"label\": \"SEND_MESSAGE\",\n \"value\": \"SEND_MESSAGE\"\n },\n {\n \"label\": \"CONTACTS_SET\",\n \"value\": \"CONTACTS_SET\"\n },\n {\n \"label\": \"CONTACTS_UPSERT\",\n \"value\": \"CONTACTS_UPSERT\"\n },\n {\n \"label\": \"CONTACTS_UPDATE\",\n \"value\": \"CONTACTS_UPDATE\"\n },\n {\n \"label\": \"PRESENCE_UPDATE\",\n \"value\": \"PRESENCE_UPDATE\"\n },\n {\n \"label\": \"CHATS_SET\",\n \"value\": \"CHATS_SET\"\n },\n {\n \"label\": \"CHATS_UPSERT\",\n \"value\": \"CHATS_UPSERT\"\n },\n {\n \"label\": \"CHATS_UPDATE\",\n \"value\": \"CHATS_UPDATE\"\n },\n {\n \"label\": \"CHATS_DELETE\",\n \"value\": \"CHATS_DELETE\"\n },\n {\n \"label\": \"GROUPS_UPSERT\",\n \"value\": \"GROUPS_UPSERT\"\n },\n {\n \"label\": \"GROUP_UPDATE\",\n \"value\": \"GROUP_UPDATE\"\n },\n {\n \"label\": \"GROUP_PARTICIPANTS_UPDATE\",\n \"value\": \"GROUP_PARTICIPANTS_UPDATE\"\n },\n {\n \"label\": \"CONNECTION_UPDATE\",\n \"value\": \"CONNECTION_UPDATE\"\n },\n {\n \"label\": \"CALL\",\n \"value\": \"CALL\"\n },\n {\n \"label\": \"NEW_JWT_TOKEN\",\n \"value\": \"NEW_JWT_TOKEN\"\n }\n]"},"webhook_by_events":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.webhook.webhook_by_events))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Switch","sourceData":false,"isCustomField":false,"accessor":"webhook_by_events","identifier":"webhook_by_events","position":2.0,"originalIdentifier":"webhook_by_events","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Webhook By Events"}},"dataType":"object","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.webhook))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Object","sourceData":{},"isCustomField":false,"accessor":"webhook","identifier":"webhook","position":1.0,"originalIdentifier":"webhook","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","cellBorderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","cellBoxShadow":"none","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"1rem","label":"Webhook","labelStyle":"BOLD"},"instance":{"children":{"instanceName":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.instance.instanceName))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Text Input","sourceData":"","isCustomField":false,"accessor":"instanceName","identifier":"instanceName","position":0.0,"originalIdentifier":"instanceName","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Instance Name"},"token":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.instance.token))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Text Input","sourceData":"","isCustomField":false,"accessor":"token","identifier":"token","position":1.0,"originalIdentifier":"token","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Token"},"qrcode":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.instance.qrcode))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Switch","sourceData":false,"isCustomField":false,"accessor":"qrcode","identifier":"qrcode","position":2.0,"originalIdentifier":"qrcode","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Qrcode"}},"dataType":"object","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.instance))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Object","sourceData":{},"isCustomField":false,"accessor":"instance","identifier":"instance","position":0.0,"originalIdentifier":"instance","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","cellBorderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","cellBoxShadow":"none","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"1rem","label":"Instance","labelStyle":"BOLD"},"settings":{"children":{"reject_call":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.settings.reject_call))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Switch","sourceData":false,"isCustomField":false,"accessor":"reject_call","identifier":"reject_call","position":0.0,"originalIdentifier":"reject_call","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Reject Call"},"msg_call":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.settings.msg_call))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Text Input","sourceData":"","isCustomField":false,"accessor":"msg_call","identifier":"msg_call","position":1.0,"originalIdentifier":"msg_call","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Msg Call"},"groups_ignore":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.settings.groups_ignore))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Switch","sourceData":false,"isCustomField":false,"accessor":"groups_ignore","identifier":"groups_ignore","position":2.0,"originalIdentifier":"groups_ignore","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Groups Ignore"},"always_online":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.settings.always_online))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Switch","sourceData":false,"isCustomField":false,"accessor":"always_online","identifier":"always_online","position":3.0,"originalIdentifier":"always_online","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Always Online"},"read_messages":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.settings.read_messages))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Switch","sourceData":false,"isCustomField":false,"accessor":"read_messages","identifier":"read_messages","position":4.0,"originalIdentifier":"read_messages","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Read Messages"},"read_status":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.settings.read_status))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Switch","sourceData":false,"isCustomField":false,"accessor":"read_status","identifier":"read_status","position":5.0,"originalIdentifier":"read_status","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Read Status"}},"dataType":"object","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.settings))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Object","sourceData":{},"isCustomField":false,"accessor":"settings","identifier":"settings","position":2.0,"originalIdentifier":"settings","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","cellBorderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","cellBoxShadow":"none","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"1rem","label":"Settings","labelStyle":"BOLD"},"chatwoot":{"children":{"chatwoot_account_id":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.chatwoot.chatwoot_account_id))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Text Input","sourceData":"","isCustomField":false,"accessor":"chatwoot_account_id","identifier":"chatwoot_account_id","position":0.0,"originalIdentifier":"chatwoot_account_id","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Chatwoot Account Id"},"chatwoot_token":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.chatwoot.chatwoot_token))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Password Input","sourceData":"","isCustomField":false,"accessor":"chatwoot_token","identifier":"chatwoot_token","position":1.0,"originalIdentifier":"chatwoot_token","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Chatwoot Token","shouldAllowAutofill":true},"chatwoot_url":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.chatwoot.chatwoot_url))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Text Input","sourceData":"","isCustomField":false,"accessor":"chatwoot_url","identifier":"chatwoot_url","position":2.0,"originalIdentifier":"chatwoot_url","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Chatwoot Url"},"chatwoot_sign_msg":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.chatwoot.chatwoot_sign_msg))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Switch","sourceData":false,"isCustomField":false,"accessor":"chatwoot_sign_msg","identifier":"chatwoot_sign_msg","position":3.0,"originalIdentifier":"chatwoot_sign_msg","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Chatwoot Sign Msg"},"chatwoot_reopen_conversation":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.chatwoot.chatwoot_reopen_conversation))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Switch","sourceData":false,"isCustomField":false,"accessor":"chatwoot_reopen_conversation","identifier":"chatwoot_reopen_conversation","position":4.0,"originalIdentifier":"chatwoot_reopen_conversation","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Chatwoot Reopen Conversation"},"chatwoot_conversation_pending":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.chatwoot.chatwoot_conversation_pending))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Switch","sourceData":false,"isCustomField":false,"accessor":"chatwoot_conversation_pending","identifier":"chatwoot_conversation_pending","position":5.0,"originalIdentifier":"chatwoot_conversation_pending","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Chatwoot Conversation Pending"}},"dataType":"object","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.chatwoot))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Object","sourceData":{},"isCustomField":false,"accessor":"chatwoot","identifier":"chatwoot","position":5.0,"originalIdentifier":"chatwoot","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","cellBorderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","cellBoxShadow":"none","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"1rem","label":"Chatwoot","labelStyle":"BOLD"},"websocket":{"children":{"websocket_enabled":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.websocket.websocket_enabled))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Switch","sourceData":false,"isCustomField":false,"accessor":"websocket_enabled","identifier":"websocket_enabled","position":0.0,"originalIdentifier":"websocket_enabled","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Websocket Enabled"},"websocket_events":{"children":{},"dataType":"array","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.websocket.websocket_events))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Multiselect","sourceData":["APPLICATION_STARTUP","QRCODE_UPDATED","MESSAGES_SET","MESSAGES_UPSERT","MESSAGES_UPDATE","MESSAGES_DELETE","SEND_MESSAGE","CONTACTS_SET","CONTACTS_UPSERT","CONTACTS_UPDATE","PRESENCE_UPDATE","CHATS_SET","CHATS_UPSERT","CHATS_UPDATE","CHATS_DELETE","GROUPS_UPSERT","GROUP_UPDATE","GROUP_PARTICIPANTS_UPDATE","CONNECTION_UPDATE","CALL","NEW_JWT_TOKEN"],"isCustomField":false,"accessor":"websocket_events","identifier":"websocket_events","position":1.0,"originalIdentifier":"websocket_events","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","isDisabled":false,"isFilterable":false,"isRequired":false,"isVisible":true,"label":"Websocket Events","labelTextSize":"0.875rem","serverSideFiltering":false,"options":[{"label":"Blue","value":"BLUE"},{"label":"Green","value":"GREEN"},{"label":"Red","value":"RED"}]}},"dataType":"object","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.websocket))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Object","sourceData":{},"isCustomField":false,"accessor":"websocket","identifier":"websocket","position":3.0,"originalIdentifier":"websocket","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","cellBorderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","cellBoxShadow":"none","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"1rem","label":"Websocket","labelStyle":"BOLD"},"rabbitmq":{"children":{"rabbitmq_enabled":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.rabbitmq.rabbitmq_enabled))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Switch","sourceData":false,"isCustomField":false,"accessor":"rabbitmq_enabled","identifier":"rabbitmq_enabled","position":1.0,"originalIdentifier":"rabbitmq_enabled","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Rabbitmq Enabled"},"rabbitmq_events":{"children":{},"dataType":"array","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.rabbitmq.rabbitmq_events))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Multiselect","sourceData":["APPLICATION_STARTUP","QRCODE_UPDATED","MESSAGES_SET","MESSAGES_UPSERT","MESSAGES_UPDATE","MESSAGES_DELETE","SEND_MESSAGE","CONTACTS_SET","CONTACTS_UPSERT","CONTACTS_UPDATE","PRESENCE_UPDATE","CHATS_SET","CHATS_UPSERT","CHATS_UPDATE","CHATS_DELETE","GROUPS_UPSERT","GROUP_UPDATE","GROUP_PARTICIPANTS_UPDATE","CONNECTION_UPDATE","CALL","NEW_JWT_TOKEN"],"isCustomField":false,"accessor":"rabbitmq_events","identifier":"rabbitmq_events","position":1.0,"originalIdentifier":"rabbitmq_events","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","isDisabled":false,"isFilterable":false,"isRequired":false,"isVisible":true,"label":"Rabbitmq Events","labelTextSize":"0.875rem","serverSideFiltering":false,"options":[{"label":"Blue","value":"BLUE"},{"label":"Green","value":"GREEN"},{"label":"Red","value":"RED"}]}},"dataType":"object","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.rabbitmq))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Object","sourceData":{"websocket_enabled":false,"websocket_events":["APPLICATION_STARTUP","QRCODE_UPDATED","MESSAGES_SET","MESSAGES_UPSERT","MESSAGES_UPDATE","MESSAGES_DELETE","SEND_MESSAGE","CONTACTS_SET","CONTACTS_UPSERT","CONTACTS_UPDATE","PRESENCE_UPDATE","CHATS_SET","CHATS_UPSERT","CHATS_UPDATE","CHATS_DELETE","GROUPS_UPSERT","GROUP_UPDATE","GROUP_PARTICIPANTS_UPDATE","CONNECTION_UPDATE","CALL","NEW_JWT_TOKEN"]},"isCustomField":false,"accessor":"rabbitmq","identifier":"rabbitmq","position":4.0,"originalIdentifier":"rabbitmq","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","cellBorderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","cellBoxShadow":"none","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"1rem","label":"Rabbitmq","labelStyle":"BOLD"}},"dataType":"object","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Object","sourceData":{"instanceName":"","token":"","webhook":"","webhook_by_events":false,"events":["APPLICATION_STARTUP","QRCODE_UPDATED","MESSAGES_SET","MESSAGES_UPSERT","MESSAGES_UPDATE","MESSAGES_DELETE","SEND_MESSAGE","CONTACTS_SET","CONTACTS_UPSERT","CONTACTS_UPDATE","PRESENCE_UPDATE","CHATS_SET","CHATS_UPSERT","CHATS_UPDATE","CHATS_DELETE","GROUPS_UPSERT","GROUP_UPDATE","GROUP_PARTICIPANTS_UPDATE","CONNECTION_UPDATE","CALL","NEW_JWT_TOKEN"],"reject_call":false,"msg_call":"","groups_ignore":false,"always_online":false,"read_messages":false,"read_status":false,"chatwoot_account_id":"","chatwoot_token":"","chatwoot_url":"","chatwoot_sign_msg":false,"chatwoot_reopen_conversation":false,"chatwoot_conversation_pending":false},"isCustomField":false,"accessor":"__root_schema__","identifier":"__root_schema__","position":-1.0,"originalIdentifier":"__root_schema__","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","cellBorderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","cellBoxShadow":"none","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":""}},"mobileBottomRow":85.0,"widgetName":"FormInstance","submitButtonStyles":{"buttonColor":"rgb(3, 179, 101)","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","buttonVariant":"PRIMARY"},"dynamicPropertyPathList":[{"key":"schema.__root_schema__.children.webhook.children.webhook_by_events.defaultValue"},{"key":"schema.__root_schema__.children.settings.children.reject_call.defaultValue"},{"key":"schema.__root_schema__.children.settings.children.groups_ignore.defaultValue"},{"key":"schema.__root_schema__.children.settings.children.always_online.defaultValue"},{"key":"schema.__root_schema__.children.settings.children.read_messages.defaultValue"},{"key":"schema.__root_schema__.children.settings.children.read_status.defaultValue"},{"key":"schema.__root_schema__.children.chatwoot.children.chatwoot_sign_msg.defaultValue"},{"key":"schema.__root_schema__.children.chatwoot.children.chatwoot_reopen_conversation.defaultValue"},{"key":"schema.__root_schema__.children.chatwoot.children.chatwoot_conversation_pending.defaultValue"},{"key":"schema.__root_schema__.children.instance.children.qrcode.defaultValue"},{"key":"schema.__root_schema__.children.websocket.children.websocket_enabled.defaultValue"},{"key":"schema.__root_schema__.children.rabbitmq.children.rabbitmq_enabled.defaultValue"}],"displayName":"JSON Form","bottomRow":183.0,"fieldLimitExceeded":false,"parentRowSpace":10.0,"title":"New Instance","hideCard":false,"mobileRightColumn":22.0,"shouldScrollContents":true,"parentColumnSpace":17.9375,"dynamicTriggerPathList":[{"key":"onSubmit"}],"borderWidth":"0","sourceData":"{\n \"instance\": {\n\t\t\t\"instanceName\": \"\",\n \t\"token\": \"\",\n\t\t\t\"qrcode\": true\n\t\t},\n\t\t\"webhook\": {\n\t\t\t\"webhook\": \"\",\n\t\t\t\"events\": [\n\t\t\t\t\"APPLICATION_STARTUP\",\n\t\t\t\t\t\"QRCODE_UPDATED\",\n\t\t\t\t\t\"MESSAGES_SET\",\n\t\t\t\t\t\"MESSAGES_UPSERT\",\n\t\t\t\t\t\"MESSAGES_UPDATE\",\n\t\t\t\t\t\"MESSAGES_DELETE\",\n\t\t\t\t\t\"SEND_MESSAGE\",\n\t\t\t\t\t\"CONTACTS_SET\",\n\t\t\t\t\t\"CONTACTS_UPSERT\",\n\t\t\t\t\t\"CONTACTS_UPDATE\",\n\t\t\t\t\t\"PRESENCE_UPDATE\",\n\t\t\t\t\t\"CHATS_SET\",\n\t\t\t\t\t\"CHATS_UPSERT\",\n\t\t\t\t\t\"CHATS_UPDATE\",\n\t\t\t\t\t\"CHATS_DELETE\",\n\t\t\t\t\t\"GROUPS_UPSERT\",\n\t\t\t\t\t\"GROUP_UPDATE\",\n\t\t\t\t\t\"GROUP_PARTICIPANTS_UPDATE\",\n\t\t\t\t\t\"CONNECTION_UPDATE\",\n\t\t\t\t\t\"CALL\",\n\t\t\t\t\t\"NEW_JWT_TOKEN\"\n\t\t\t],\n\t\t\t\"webhook_by_events\": false\n\t\t},\n \"settings\": {\n\t\t\t\"reject_call\": false,\n\t\t\t\"msg_call\": \"\",\n\t\t\t\"groups_ignore\": false,\n\t\t\t\"always_online\": false,\n\t\t\t\"read_messages\": false,\n\t\t\t\"read_status\": false\n\t\t},\n\t\t\"websocket\": {\n\t\t\t\"websocket_enabled\": false,\n\t\t\t\"websocket_events\": [\n\t\t\t\t\"APPLICATION_STARTUP\",\n\t\t\t\t\t\"QRCODE_UPDATED\",\n\t\t\t\t\t\"MESSAGES_SET\",\n\t\t\t\t\t\"MESSAGES_UPSERT\",\n\t\t\t\t\t\"MESSAGES_UPDATE\",\n\t\t\t\t\t\"MESSAGES_DELETE\",\n\t\t\t\t\t\"SEND_MESSAGE\",\n\t\t\t\t\t\"CONTACTS_SET\",\n\t\t\t\t\t\"CONTACTS_UPSERT\",\n\t\t\t\t\t\"CONTACTS_UPDATE\",\n\t\t\t\t\t\"PRESENCE_UPDATE\",\n\t\t\t\t\t\"CHATS_SET\",\n\t\t\t\t\t\"CHATS_UPSERT\",\n\t\t\t\t\t\"CHATS_UPDATE\",\n\t\t\t\t\t\"CHATS_DELETE\",\n\t\t\t\t\t\"GROUPS_UPSERT\",\n\t\t\t\t\t\"GROUP_UPDATE\",\n\t\t\t\t\t\"GROUP_PARTICIPANTS_UPDATE\",\n\t\t\t\t\t\"CONNECTION_UPDATE\",\n\t\t\t\t\t\"CALL\",\n\t\t\t\t\t\"NEW_JWT_TOKEN\"\n\t\t\t]\n\t\t},\n\t\t\"rabbitmq\": {\n\t\t\t\"rabbitmq_enabled\": false,\n\t\t\t\"rabbitmq_events\": [\n\t\t\t\t\"APPLICATION_STARTUP\",\n\t\t\t\t\t\"QRCODE_UPDATED\",\n\t\t\t\t\t\"MESSAGES_SET\",\n\t\t\t\t\t\"MESSAGES_UPSERT\",\n\t\t\t\t\t\"MESSAGES_UPDATE\",\n\t\t\t\t\t\"MESSAGES_DELETE\",\n\t\t\t\t\t\"SEND_MESSAGE\",\n\t\t\t\t\t\"CONTACTS_SET\",\n\t\t\t\t\t\"CONTACTS_UPSERT\",\n\t\t\t\t\t\"CONTACTS_UPDATE\",\n\t\t\t\t\t\"PRESENCE_UPDATE\",\n\t\t\t\t\t\"CHATS_SET\",\n\t\t\t\t\t\"CHATS_UPSERT\",\n\t\t\t\t\t\"CHATS_UPDATE\",\n\t\t\t\t\t\"CHATS_DELETE\",\n\t\t\t\t\t\"GROUPS_UPSERT\",\n\t\t\t\t\t\"GROUP_UPDATE\",\n\t\t\t\t\t\"GROUP_PARTICIPANTS_UPDATE\",\n\t\t\t\t\t\"CONNECTION_UPDATE\",\n\t\t\t\t\t\"CALL\",\n\t\t\t\t\t\"NEW_JWT_TOKEN\"\n\t\t\t]\n\t\t},\n \"chatwoot\": {\n\t\t\t\"chatwoot_account_id\": \"\",\n\t\t\t\"chatwoot_token\": \"\",\n\t\t\t\"chatwoot_url\": \"\",\n\t\t\t\"chatwoot_sign_msg\": false,\n\t\t\t\"chatwoot_reopen_conversation\": false,\n\t\t\t\"chatwoot_conversation_pending\": false\n\t\t}\n}","resetButtonLabel":"Reset","key":"lgqqk5r1jk","backgroundColor":"#fff","isDeprecated":false,"rightColumn":63.0,"widgetId":"o0v8ypwnya","minWidth":450.0,"parentId":"esgwuzqcwt","renderMode":"CANVAS","mobileTopRow":44.0,"scrollContents":true,"responsiveBehavior":"fill","fixedFooter":true,"originalTopRow":4.0,"mobileLeftColumn":0.0,"maxDynamicHeight":9000.0,"minDynamicHeight":4.0}],"isDisabled":false,"key":"w17ra2a85u","isDeprecated":false,"rightColumn":283.875,"detachFromLayout":true,"widgetId":"esgwuzqcwt","minWidth":450.0,"isVisible":true,"version":1.0,"parentId":"rnttu90jzr","renderMode":"CANVAS","isLoading":false,"mobileTopRow":0.0,"responsiveBehavior":"fill","mobileLeftColumn":0.0,"flexLayers":[]}],"key":"bkvkzj4d20","height":1850.0,"isDeprecated":false,"rightColumn":37.0,"detachFromLayout":true,"dynamicHeight":"AUTO_HEIGHT","widgetId":"rnttu90jzr","canOutsideClickClose":true,"canEscapeKeyClose":true,"version":2.0,"parentId":"0","renderMode":"CANVAS","isLoading":false,"mobileTopRow":42.0,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":13.0,"maxDynamicHeight":9000.0,"width":628.0,"minDynamicHeight":24.0},{"resetFormOnClick":false,"boxShadow":"none","mobileBottomRow":5.0,"widgetName":"ButtonRefreshData","onClick":"{{fetch_Instances.run()}}","buttonColor":"#60a5fa","dynamicPropertyPathList":[{"key":"isVisible"}],"displayName":"Button","iconSVG":"/static/media/icon.7beb9123fb53027d9d6b778cdfe4caed.svg","searchTags":["click","submit"],"topRow":1.0,"bottomRow":5.0,"parentRowSpace":10.0,"type":"BUTTON_WIDGET","hideCard":false,"mobileRightColumn":35.0,"animateLoading":true,"parentColumnSpace":11.828125,"dynamicTriggerPathList":[{"key":"onClick"}],"leftColumn":19.0,"dynamicBindingPathList":[{"key":"isVisible"},{"key":"borderRadius"}],"text":"","isDisabled":false,"key":"k10nyfsas3","isDeprecated":false,"rightColumn":24.0,"isDefaultClickDisabled":true,"iconName":"refresh","widgetId":"dn1ehe3gvu","minWidth":120.0,"isVisible":"{{appsmith.store.api_key && appsmith.store.api_url ? true : false}}","recaptchaType":"V3","version":1.0,"parentId":"0","renderMode":"CANVAS","isLoading":false,"mobileTopRow":1.0,"responsiveBehavior":"hug","disabledWhenInvalid":false,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":19.0,"buttonVariant":"PRIMARY","iconAlign":"left","placement":"CENTER"},{"boxShadow":"none","mobileBottomRow":5.0,"widgetName":"ButtonGroup1","isCanvas":false,"dynamicPropertyPathList":[{"key":"isVisible"}],"displayName":"Button Group","iconSVG":"/static/media/icon.7c22979bacc83c8d84aedf56ea6c2022.svg","searchTags":["click","submit"],"topRow":1.0,"bottomRow":5.0,"parentRowSpace":10.0,"groupButtons":{"groupButton1":{"label":"Connect","iconName":"camera","id":"groupButton1","widgetId":"","buttonType":"SIMPLE","placement":"CENTER","isVisible":true,"isDisabled":false,"index":0.0,"menuItems":{},"buttonColor":"#16a34a","onClick":"{{Connect.run();\nfetch_Instances.run();\nshowModal('ModalQrcode');}}"},"groupButton2":{"label":"Restart","iconName":"reset","id":"groupButton2","buttonType":"SIMPLE","placement":"CENTER","widgetId":"","isVisible":true,"isDisabled":false,"index":1.0,"menuItems":{},"buttonColor":"#2563eb","onClick":"{{Restart.run().then(() => {\n showAlert('Instance restarted successfully', 'success');\n}).catch(() => {\n showAlert('Error restarting instance', 'error');\n});\nfetch_Instances.run();}}"},"groupButton3":{"label":"Logout","iconName":"log-in","id":"groupButton3","buttonType":"SIMPLE","placement":"CENTER","widgetId":"","isVisible":true,"isDisabled":false,"index":2.0,"menuItems":{"menuItem1":{"label":"First Option","backgroundColor":"#FFFFFF","id":"menuItem1","widgetId":"","onClick":"","isVisible":true,"isDisabled":false,"index":0.0},"menuItem2":{"label":"Second Option","backgroundColor":"#FFFFFF","id":"menuItem2","widgetId":"","onClick":"","isVisible":true,"isDisabled":false,"index":1.0},"menuItem3":{"label":"Delete","iconName":"trash","iconColor":"#FFFFFF","iconAlign":"right","textColor":"#FFFFFF","backgroundColor":"#DD4B34","id":"menuItem3","widgetId":"","onClick":"","isVisible":true,"isDisabled":false,"index":2.0}},"buttonColor":"#a16207","onClick":"{{Logout.run().then(() => {\n showAlert('Instance logout successfully', 'success');\n}).catch(() => {\n showAlert('Error logout instance', 'error');\n});\nfetch_Instances.run();}}"},"groupButtonmghcs8rd4g":{"id":"groupButtonmghcs8rd4g","index":3.0,"label":"Delete","menuItems":{},"buttonType":"SIMPLE","placement":"CENTER","widgetId":"v0qkg2pjo2","isDisabled":false,"isVisible":true,"buttonColor":"#ef4444","iconName":"cross","onClick":"{{Delete.run().then(() => {\n showAlert('Instance deleted successfully', 'success');\n}).catch(() => {\n showAlert('Error deleting instance', 'error');\n});\nfetch_Instances.run();}}"}},"type":"BUTTON_GROUP_WIDGET","hideCard":false,"mobileRightColumn":51.0,"animateLoading":true,"parentColumnSpace":11.828125,"dynamicTriggerPathList":[{"key":"groupButtons.groupButton1.onClick"},{"key":"groupButtons.groupButton2.onClick"},{"key":"groupButtons.groupButton3.onClick"},{"key":"groupButtons.groupButtonmghcs8rd4g.onClick"}],"leftColumn":27.0,"dynamicBindingPathList":[{"key":"isVisible"},{"key":"borderRadius"}],"isDisabled":false,"key":"za8m3k8x7w","orientation":"horizontal","isDeprecated":false,"rightColumn":63.0,"widgetId":"2s6fqi483g","minWidth":450.0,"isVisible":"{{appsmith.store.api_key && appsmith.store.api_url ? true : false}}","version":1.0,"parentId":"0","renderMode":"CANVAS","isLoading":false,"mobileTopRow":1.0,"responsiveBehavior":"fill","childStylesheet":{"button":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}"}},"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":27.0,"buttonVariant":"PRIMARY"},{"boxShadow":"none","mobileBottomRow":18.0,"widgetName":"ProfilePicture","dynamicPropertyPathList":[{"key":"isVisible"},{"key":"borderRadius"}],"displayName":"Image","iconSVG":"/static/media/icon.30c8cbd442cce232b01ba2d434c53a53.svg","topRow":6.0,"bottomRow":28.0,"parentRowSpace":10.0,"type":"IMAGE_WIDGET","hideCard":false,"mobileRightColumn":13.0,"animateLoading":true,"parentColumnSpace":11.828125,"dynamicTriggerPathList":[],"imageShape":"RECTANGLE","leftColumn":1.0,"dynamicBindingPathList":[{"key":"image"},{"key":"isVisible"}],"defaultImage":"https://th.bing.com/th/id/OIP.ruat7whad9-kcI8_1KH_tQHaGI?pid=ImgDet&rs=1","key":"bl30j21wwb","image":"{{TableInstances.selectedRow.profilePictureUrl}}","isDeprecated":false,"rightColumn":13.0,"objectFit":"contain","widgetId":"1sjznr31jo","isVisible":"{{appsmith.store.api_key && appsmith.store.api_url ? true : false}}","version":1.0,"parentId":"0","renderMode":"CANVAS","isLoading":false,"mobileTopRow":6.0,"maxZoomLevel":1.0,"enableDownload":false,"borderRadius":"0.335rem","mobileLeftColumn":1.0,"enableRotation":false},{"mobileBottomRow":22.0,"widgetName":"Text4","dynamicPropertyPathList":[{"key":"isVisible"}],"displayName":"Text","iconSVG":"/static/media/icon.c3b6033f570046f8c6288d911333a827.svg","searchTags":["typography","paragraph","label"],"topRow":36.0,"bottomRow":44.0,"parentRowSpace":10.0,"type":"TEXT_WIDGET","hideCard":false,"mobileRightColumn":11.0,"animateLoading":true,"overflow":"NONE","fontFamily":"{{appsmith.theme.fontFamily.appFont}}","parentColumnSpace":11.828125,"dynamicTriggerPathList":[],"leftColumn":1.0,"dynamicBindingPathList":[{"key":"text"},{"key":"isVisible"},{"key":"fontFamily"}],"shouldTruncate":false,"truncateButtonColor":"{{appsmith.theme.colors.primaryColor}}","text":"{{TableInstances.selectedRow.profileName || ''}}\n\n{{TableInstances.selectedRow.profileStatus || ''}}","key":"gqt8t28m33","isDeprecated":false,"rightColumn":13.0,"textAlign":"CENTER","dynamicHeight":"AUTO_HEIGHT","widgetId":"0c356c66hp","minWidth":450.0,"isVisible":"{{appsmith.store.api_key && appsmith.store.api_url ? true : false}}","fontStyle":"BOLD","textColor":"#231F20","version":1.0,"parentId":"0","renderMode":"CANVAS","isLoading":false,"mobileTopRow":18.0,"responsiveBehavior":"fill","originalTopRow":38.0,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":0.0,"maxDynamicHeight":9000.0,"originalBottomRow":44.0,"fontSize":"0.875rem","minDynamicHeight":4.0},{"mobileBottomRow":41.0,"widgetName":"Text5","dynamicPropertyPathList":[{"key":"isVisible"}],"displayName":"Text","iconSVG":"/static/media/icon.c3b6033f570046f8c6288d911333a827.svg","searchTags":["typography","paragraph","label"],"topRow":32.0,"bottomRow":36.0,"parentRowSpace":10.0,"type":"TEXT_WIDGET","hideCard":false,"mobileRightColumn":9.0,"animateLoading":true,"overflow":"NONE","fontFamily":"{{appsmith.theme.fontFamily.appFont}}","parentColumnSpace":11.75,"dynamicTriggerPathList":[],"leftColumn":1.0,"dynamicBindingPathList":[{"key":"text"},{"key":"isVisible"},{"key":"fontFamily"}],"shouldTruncate":false,"truncateButtonColor":"{{appsmith.theme.colors.primaryColor}}","text":"{{TableInstances.selectedRow.instance || ''}}","key":"gqt8t28m33","isDeprecated":false,"rightColumn":13.0,"textAlign":"CENTER","dynamicHeight":"AUTO_HEIGHT","widgetId":"5qg2iscn1l","minWidth":450.0,"isVisible":"{{appsmith.store.api_key && appsmith.store.api_url ? true : false}}","fontStyle":"BOLD","textColor":"#231F20","version":1.0,"parentId":"0","renderMode":"CANVAS","isLoading":false,"mobileTopRow":37.0,"responsiveBehavior":"fill","originalTopRow":32.0,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":0.0,"maxDynamicHeight":9000.0,"originalBottomRow":38.0,"fontSize":"1.25rem","minDynamicHeight":4.0},{"boxShadow":"none","mobileBottomRow":70.0,"widgetName":"ModalWebhook","isCanvas":true,"displayName":"Modal","iconSVG":"/static/media/icon.d2ab7de0666eaef853cc2d330f86887b.svg","searchTags":["dialog","popup","notification"],"topRow":46.0,"bottomRow":43.0,"parentRowSpace":10.0,"type":"MODAL_WIDGET","hideCard":false,"shouldScrollContents":true,"mobileRightColumn":35.0,"minHeight":430.0,"animateLoading":true,"parentColumnSpace":17.9375,"leftColumn":11.0,"dynamicBindingPathList":[{"key":"borderRadius"}],"children":[{"mobileBottomRow":240.0,"widgetName":"Canvas4","displayName":"Canvas","topRow":0.0,"bottomRow":430.0,"parentRowSpace":1.0,"type":"CANVAS_WIDGET","canExtend":true,"hideCard":true,"shouldScrollContents":false,"minHeight":240.0,"mobileRightColumn":430.5,"parentColumnSpace":1.0,"leftColumn":0.0,"dynamicBindingPathList":[],"children":[{"boxShadow":"none","borderColor":"#E0DEDE","iconSVG":"/static/media/icon.efac588608711d232f1c6c8a2144d2dd.svg","onSubmit":"{{Set_Webhook.run().then(() => {\n showAlert('Webhook updated successfully', 'success');\n}).catch(() => {\n showAlert('Error updating webhook', 'error');\n});\ncloseModal('ModalWebhook');}}","topRow":0.0,"type":"JSON_FORM_WIDGET","animateLoading":true,"leftColumn":0.0,"dynamicBindingPathList":[{"key":"borderRadius"},{"key":"submitButtonStyles.buttonColor"},{"key":"schema.__root_schema__.defaultValue"},{"key":"schema.__root_schema__.borderRadius"},{"key":"schema.__root_schema__.cellBorderRadius"},{"key":"sourceData"},{"key":"schema.__root_schema__.children.enabled.defaultValue"},{"key":"schema.__root_schema__.children.enabled.accentColor"},{"key":"schema.__root_schema__.children.url.defaultValue"},{"key":"schema.__root_schema__.children.url.accentColor"},{"key":"schema.__root_schema__.children.url.borderRadius"},{"key":"schema.__root_schema__.children.webhook_by_events.defaultValue"},{"key":"schema.__root_schema__.children.webhook_by_events.accentColor"},{"key":"schema.__root_schema__.children.events.defaultValue"},{"key":"schema.__root_schema__.children.events.accentColor"},{"key":"schema.__root_schema__.children.events.borderRadius"}],"showReset":false,"dynamicHeight":"AUTO_HEIGHT","autoGenerateForm":false,"resetButtonStyles":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","buttonVariant":"SECONDARY"},"isVisible":true,"version":1.0,"isLoading":false,"submitButtonLabel":"Save","childStylesheet":{"ARRAY":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","cellBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","cellBoxShadow":"none"},"OBJECT":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","cellBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","cellBoxShadow":"none"},"CHECKBOX":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}"},"CURRENCY_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"DATEPICKER":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"EMAIL_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTISELECT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTILINE_TEXT_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"NUMBER_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PASSWORD_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PHONE_NUMBER_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"RADIO_GROUP":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"SELECT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"SWITCH":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"TEXT_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"}},"disabledWhenInvalid":true,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","originalBottomRow":41.0,"useSourceData":false,"schema":{"__root_schema__":{"children":{"enabled":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.enabled))(FormWebhook.sourceData, FormWebhook.formData, FormWebhook.fieldState)}}","fieldType":"Switch","sourceData":false,"isCustomField":false,"accessor":"enabled","identifier":"enabled","position":0.0,"originalIdentifier":"enabled","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormWebhook.sourceData, FormWebhook.formData, FormWebhook.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Enabled"},"url":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.url))(FormWebhook.sourceData, FormWebhook.formData, FormWebhook.fieldState)}}","fieldType":"Text Input","sourceData":"","isCustomField":false,"accessor":"url","identifier":"url","position":1.0,"originalIdentifier":"url","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormWebhook.sourceData, FormWebhook.formData, FormWebhook.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormWebhook.sourceData, FormWebhook.formData, FormWebhook.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Url"},"webhook_by_events":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.webhook_by_events))(FormWebhook.sourceData, FormWebhook.formData, FormWebhook.fieldState)}}","fieldType":"Switch","sourceData":false,"isCustomField":false,"accessor":"webhook_by_events","identifier":"webhook_by_events","position":2.0,"originalIdentifier":"webhook_by_events","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormWebhook.sourceData, FormWebhook.formData, FormWebhook.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Webhook By Events"},"events":{"children":{},"dataType":"array","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.events))(FormWebhook.sourceData, FormWebhook.formData, FormWebhook.fieldState)}}","fieldType":"Multiselect","sourceData":[],"isCustomField":false,"accessor":"events","identifier":"events","position":3.0,"originalIdentifier":"events","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormWebhook.sourceData, FormWebhook.formData, FormWebhook.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormWebhook.sourceData, FormWebhook.formData, FormWebhook.fieldState)}}","boxShadow":"none","isDisabled":false,"isFilterable":false,"isRequired":false,"isVisible":true,"label":"Events","labelTextSize":"0.875rem","serverSideFiltering":false,"options":"[\n\n {\n \"label\": \"APPLICATION_STARTUP\",\n \"value\": \"APPLICATION_STARTUP\"\n },\n {\n \"label\": \"QRCODE_UPDATED\",\n \"value\": \"QRCODE_UPDATED\"\n },\n {\n \"label\": \"MESSAGES_SET\",\n \"value\": \"MESSAGES_SET\"\n },\n {\n \"label\": \"MESSAGES_UPSERT\",\n \"value\": \"MESSAGES_UPSERT\"\n },\n {\n \"label\": \"MESSAGES_UPDATE\",\n \"value\": \"MESSAGES_UPDATE\"\n },\n {\n \"label\": \"MESSAGES_DELETE\",\n \"value\": \"MESSAGES_DELETE\"\n },\n {\n \"label\": \"SEND_MESSAGE\",\n \"value\": \"SEND_MESSAGE\"\n },\n {\n \"label\": \"CONTACTS_SET\",\n \"value\": \"CONTACTS_SET\"\n },\n {\n \"label\": \"CONTACTS_UPSERT\",\n \"value\": \"CONTACTS_UPSERT\"\n },\n {\n \"label\": \"CONTACTS_UPDATE\",\n \"value\": \"CONTACTS_UPDATE\"\n },\n {\n \"label\": \"PRESENCE_UPDATE\",\n \"value\": \"PRESENCE_UPDATE\"\n },\n {\n \"label\": \"CHATS_SET\",\n \"value\": \"CHATS_SET\"\n },\n {\n \"label\": \"CHATS_UPSERT\",\n \"value\": \"CHATS_UPSERT\"\n },\n {\n \"label\": \"CHATS_UPDATE\",\n \"value\": \"CHATS_UPDATE\"\n },\n {\n \"label\": \"CHATS_DELETE\",\n \"value\": \"CHATS_DELETE\"\n },\n {\n \"label\": \"GROUPS_UPSERT\",\n \"value\": \"GROUPS_UPSERT\"\n },\n {\n \"label\": \"GROUP_UPDATE\",\n \"value\": \"GROUP_UPDATE\"\n },\n {\n \"label\": \"GROUP_PARTICIPANTS_UPDATE\",\n \"value\": \"GROUP_PARTICIPANTS_UPDATE\"\n },\n {\n \"label\": \"CONNECTION_UPDATE\",\n \"value\": \"CONNECTION_UPDATE\"\n },\n {\n \"label\": \"CALL\",\n \"value\": \"CALL\"\n },\n {\n \"label\": \"NEW_JWT_TOKEN\",\n \"value\": \"NEW_JWT_TOKEN\"\n }\n]"}},"dataType":"object","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData))(FormWebhook.sourceData, FormWebhook.formData, FormWebhook.fieldState)}}","fieldType":"Object","sourceData":{"enabled":false,"url":"","webhook_by_events":false,"events":[]},"isCustomField":false,"accessor":"__root_schema__","identifier":"__root_schema__","position":-1.0,"originalIdentifier":"__root_schema__","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormWebhook.sourceData, FormWebhook.formData, FormWebhook.fieldState)}}","boxShadow":"none","cellBorderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormWebhook.sourceData, FormWebhook.formData, FormWebhook.fieldState)}}","cellBoxShadow":"none","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":""}},"mobileBottomRow":41.0,"widgetName":"FormWebhook","submitButtonStyles":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","buttonVariant":"PRIMARY"},"dynamicPropertyPathList":[{"key":"schema.__root_schema__.children.webhook_by_events.defaultValue"},{"key":"schema.__root_schema__.children.enabled.defaultValue"},{"key":"schema.__root_schema__.children.url.defaultValue"}],"displayName":"JSON Form","bottomRow":41.0,"fieldLimitExceeded":false,"parentRowSpace":10.0,"title":"Webhook","hideCard":false,"mobileRightColumn":25.0,"parentColumnSpace":6.9375,"dynamicTriggerPathList":[{"key":"onSubmit"}],"borderWidth":"0","sourceData":"{\n\t\"enabled\": {{Find_Webhook.data.enabled || false}},\n\t\"url\": {{Find_Webhook.data.url}},\n \"webhook_by_events\": {{Find_Webhook.data.webhook_by_events}},\n \"events\": {{Find_Webhook.data.events || false}} \n}","resetButtonLabel":"Reset","key":"lgqqk5r1jk","backgroundColor":"#fff","isDeprecated":false,"rightColumn":63.0,"widgetId":"tb1ekur7fx","minWidth":450.0,"parentId":"mv02ta6pzr","renderMode":"CANVAS","mobileTopRow":0.0,"scrollContents":true,"responsiveBehavior":"fill","fixedFooter":true,"originalTopRow":0.0,"mobileLeftColumn":0.0,"maxDynamicHeight":9000.0,"minDynamicHeight":4.0}],"isDisabled":false,"key":"svq68rvpdn","isDeprecated":false,"rightColumn":430.5,"detachFromLayout":true,"widgetId":"mv02ta6pzr","minWidth":450.0,"isVisible":true,"version":1.0,"parentId":"0g8ql5hukz","renderMode":"CANVAS","isLoading":false,"mobileTopRow":0.0,"responsiveBehavior":"fill","mobileLeftColumn":0.0,"flexLayers":[]}],"key":"6x3z5yow7u","height":430.0,"isDeprecated":false,"rightColumn":35.0,"detachFromLayout":true,"dynamicHeight":"AUTO_HEIGHT","widgetId":"0g8ql5hukz","canOutsideClickClose":true,"canEscapeKeyClose":true,"version":2.0,"parentId":"0","renderMode":"CANVAS","isLoading":false,"mobileTopRow":46.0,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":11.0,"maxDynamicHeight":9000.0,"width":456.0,"minDynamicHeight":24.0},{"boxShadow":"none","mobileBottomRow":70.0,"widgetName":"ModalWebsocket","isCanvas":true,"displayName":"Modal","iconSVG":"/static/media/icon.d2ab7de0666eaef853cc2d330f86887b.svg","searchTags":["dialog","popup","notification"],"topRow":42.0,"bottomRow":40.0,"parentRowSpace":10.0,"type":"MODAL_WIDGET","hideCard":false,"shouldScrollContents":true,"mobileRightColumn":35.0,"minHeight":400.0,"animateLoading":true,"parentColumnSpace":17.9375,"leftColumn":11.0,"dynamicBindingPathList":[{"key":"borderRadius"}],"children":[{"mobileBottomRow":240.0,"widgetName":"Canvas4Copy1","displayName":"Canvas","topRow":0.0,"bottomRow":400.0,"parentRowSpace":1.0,"type":"CANVAS_WIDGET","canExtend":true,"hideCard":true,"shouldScrollContents":false,"minHeight":400.0,"mobileRightColumn":430.5,"parentColumnSpace":1.0,"leftColumn":0.0,"dynamicBindingPathList":[],"children":[{"boxShadow":"none","borderColor":"#E0DEDE","iconSVG":"/static/media/icon.efac588608711d232f1c6c8a2144d2dd.svg","onSubmit":"{{Set_Websocket.run().then(() => {\n showAlert('Websocket updated successfully', 'success');\n}).catch(() => {\n showAlert('Error updating websocket', 'error');\n});\ncloseModal('ModalWebsocket');}}","topRow":0.0,"type":"JSON_FORM_WIDGET","animateLoading":true,"leftColumn":0.0,"dynamicBindingPathList":[{"key":"borderRadius"},{"key":"submitButtonStyles.buttonColor"},{"key":"schema.__root_schema__.defaultValue"},{"key":"schema.__root_schema__.borderRadius"},{"key":"sourceData"},{"key":"schema.__root_schema__.children.enabled.defaultValue"},{"key":"schema.__root_schema__.children.enabled.accentColor"},{"key":"schema.__root_schema__.children.url.defaultValue"},{"key":"schema.__root_schema__.children.url.accentColor"},{"key":"schema.__root_schema__.children.url.borderRadius"},{"key":"schema.__root_schema__.children.events.defaultValue"},{"key":"schema.__root_schema__.children.events.accentColor"},{"key":"schema.__root_schema__.children.events.borderRadius"},{"key":"schema.__root_schema__.cellBorderRadius"}],"showReset":false,"dynamicHeight":"AUTO_HEIGHT","autoGenerateForm":false,"resetButtonStyles":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","buttonVariant":"SECONDARY"},"isVisible":true,"version":1.0,"isLoading":false,"submitButtonLabel":"Save","childStylesheet":{"ARRAY":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","cellBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","cellBoxShadow":"none"},"OBJECT":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","cellBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","cellBoxShadow":"none"},"CHECKBOX":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}"},"CURRENCY_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"DATEPICKER":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"EMAIL_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTISELECT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTILINE_TEXT_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"NUMBER_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PASSWORD_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PHONE_NUMBER_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"RADIO_GROUP":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"SELECT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"SWITCH":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"TEXT_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"}},"disabledWhenInvalid":true,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","originalBottomRow":38.0,"useSourceData":false,"schema":{"__root_schema__":{"children":{"enabled":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.enabled))(FormWebsocket.sourceData, FormWebsocket.formData, FormWebsocket.fieldState)}}","fieldType":"Switch","sourceData":true,"isCustomField":false,"accessor":"enabled","identifier":"enabled","position":0.0,"originalIdentifier":"enabled","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormWebsocket.sourceData, FormWebsocket.formData, FormWebsocket.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Enabled"},"url":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.url))(FormWebsocket.sourceData, FormWebsocket.formData, FormWebsocket.fieldState)}}","fieldType":"Text Input","sourceData":"https://teste.com","isCustomField":false,"accessor":"url","identifier":"url","position":1.0,"originalIdentifier":"url","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormWebsocket.sourceData, FormWebsocket.formData, FormWebsocket.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormWebsocket.sourceData, FormWebsocket.formData, FormWebsocket.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Url"},"events":{"children":{},"dataType":"array","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.events))(FormWebsocket.sourceData, FormWebsocket.formData, FormWebsocket.fieldState)}}","fieldType":"Multiselect","sourceData":["MESSAGES_UPSERT"],"isCustomField":false,"accessor":"events","identifier":"events","position":2.0,"originalIdentifier":"events","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormWebsocket.sourceData, FormWebsocket.formData, FormWebsocket.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormWebsocket.sourceData, FormWebsocket.formData, FormWebsocket.fieldState)}}","boxShadow":"none","isDisabled":false,"isFilterable":false,"isRequired":false,"isVisible":true,"label":"Events","labelTextSize":"0.875rem","serverSideFiltering":false,"options":"[\n\n {\n \"label\": \"APPLICATION_STARTUP\",\n \"value\": \"APPLICATION_STARTUP\"\n },\n {\n \"label\": \"QRCODE_UPDATED\",\n \"value\": \"QRCODE_UPDATED\"\n },\n {\n \"label\": \"MESSAGES_SET\",\n \"value\": \"MESSAGES_SET\"\n },\n {\n \"label\": \"MESSAGES_UPSERT\",\n \"value\": \"MESSAGES_UPSERT\"\n },\n {\n \"label\": \"MESSAGES_UPDATE\",\n \"value\": \"MESSAGES_UPDATE\"\n },\n {\n \"label\": \"MESSAGES_DELETE\",\n \"value\": \"MESSAGES_DELETE\"\n },\n {\n \"label\": \"SEND_MESSAGE\",\n \"value\": \"SEND_MESSAGE\"\n },\n {\n \"label\": \"CONTACTS_SET\",\n \"value\": \"CONTACTS_SET\"\n },\n {\n \"label\": \"CONTACTS_UPSERT\",\n \"value\": \"CONTACTS_UPSERT\"\n },\n {\n \"label\": \"CONTACTS_UPDATE\",\n \"value\": \"CONTACTS_UPDATE\"\n },\n {\n \"label\": \"PRESENCE_UPDATE\",\n \"value\": \"PRESENCE_UPDATE\"\n },\n {\n \"label\": \"CHATS_SET\",\n \"value\": \"CHATS_SET\"\n },\n {\n \"label\": \"CHATS_UPSERT\",\n \"value\": \"CHATS_UPSERT\"\n },\n {\n \"label\": \"CHATS_UPDATE\",\n \"value\": \"CHATS_UPDATE\"\n },\n {\n \"label\": \"CHATS_DELETE\",\n \"value\": \"CHATS_DELETE\"\n },\n {\n \"label\": \"GROUPS_UPSERT\",\n \"value\": \"GROUPS_UPSERT\"\n },\n {\n \"label\": \"GROUP_UPDATE\",\n \"value\": \"GROUP_UPDATE\"\n },\n {\n \"label\": \"GROUP_PARTICIPANTS_UPDATE\",\n \"value\": \"GROUP_PARTICIPANTS_UPDATE\"\n },\n {\n \"label\": \"CONNECTION_UPDATE\",\n \"value\": \"CONNECTION_UPDATE\"\n },\n {\n \"label\": \"CALL\",\n \"value\": \"CALL\"\n },\n {\n \"label\": \"NEW_JWT_TOKEN\",\n \"value\": \"NEW_JWT_TOKEN\"\n }\n]"}},"dataType":"object","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData))(FormWebsocket.sourceData, FormWebsocket.formData, FormWebsocket.fieldState)}}","fieldType":"Object","sourceData":{"enabled":true,"url":"https://teste.com","events":["MESSAGES_UPSERT"]},"isCustomField":false,"accessor":"__root_schema__","identifier":"__root_schema__","position":-1.0,"originalIdentifier":"__root_schema__","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormWebsocket.sourceData, FormWebsocket.formData, FormWebsocket.fieldState)}}","boxShadow":"none","cellBorderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormWebsocket.sourceData, FormWebsocket.formData, FormWebsocket.fieldState)}}","cellBoxShadow":"none","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":""}},"mobileBottomRow":41.0,"widgetName":"FormWebsocket","submitButtonStyles":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","buttonVariant":"PRIMARY"},"dynamicPropertyPathList":[{"key":"schema.__root_schema__.children.enabled.defaultValue"},{"key":"schema.__root_schema__.children.events.defaultValue"},{"key":"schema.__root_schema__.children.url.defaultValue"}],"displayName":"JSON Form","bottomRow":38.0,"fieldLimitExceeded":false,"parentRowSpace":10.0,"title":"Websocket","hideCard":false,"mobileRightColumn":25.0,"parentColumnSpace":6.9375,"dynamicTriggerPathList":[{"key":"onSubmit"}],"borderWidth":"0","sourceData":"{\n\t\"enabled\": {{Find_Websocket.data.enabled || false}},\n \"url\": {{Find_Websocket.data.url}},\n \"events\": {{Find_Websocket.data.events}}\n\t\t\n }","resetButtonLabel":"Reset","key":"lgqqk5r1jk","backgroundColor":"#fff","isDeprecated":false,"rightColumn":63.0,"widgetId":"masqwth5vo","minWidth":450.0,"parentId":"gzf4hjxdo8","renderMode":"CANVAS","mobileTopRow":0.0,"scrollContents":true,"responsiveBehavior":"fill","fixedFooter":true,"originalTopRow":0.0,"mobileLeftColumn":0.0,"maxDynamicHeight":9000.0,"minDynamicHeight":4.0}],"isDisabled":false,"key":"svq68rvpdn","isDeprecated":false,"rightColumn":430.5,"detachFromLayout":true,"widgetId":"gzf4hjxdo8","minWidth":450.0,"isVisible":true,"version":1.0,"parentId":"9twyngcwej","renderMode":"CANVAS","isLoading":false,"mobileTopRow":0.0,"responsiveBehavior":"fill","mobileLeftColumn":0.0,"flexLayers":[]}],"key":"6x3z5yow7u","height":400.0,"isDeprecated":false,"rightColumn":35.0,"detachFromLayout":true,"dynamicHeight":"AUTO_HEIGHT","widgetId":"9twyngcwej","canOutsideClickClose":true,"canEscapeKeyClose":true,"version":2.0,"parentId":"0","renderMode":"CANVAS","isLoading":false,"mobileTopRow":46.0,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":11.0,"maxDynamicHeight":9000.0,"width":456.0,"minDynamicHeight":24.0},{"boxShadow":"none","mobileBottomRow":70.0,"widgetName":"ModalRabbitmq","isCanvas":true,"displayName":"Modal","iconSVG":"/static/media/icon.d2ab7de0666eaef853cc2d330f86887b.svg","searchTags":["dialog","popup","notification"],"topRow":31.0,"bottomRow":32.0,"parentRowSpace":10.0,"type":"MODAL_WIDGET","hideCard":false,"shouldScrollContents":true,"mobileRightColumn":35.0,"minHeight":320.0,"animateLoading":true,"parentColumnSpace":17.9375,"leftColumn":11.0,"dynamicBindingPathList":[{"key":"borderRadius"}],"children":[{"mobileBottomRow":240.0,"widgetName":"Canvas4Copy1Copy","displayName":"Canvas","topRow":0.0,"bottomRow":320.0,"parentRowSpace":1.0,"type":"CANVAS_WIDGET","canExtend":true,"hideCard":true,"shouldScrollContents":false,"minHeight":240.0,"mobileRightColumn":430.5,"parentColumnSpace":1.0,"leftColumn":0.0,"dynamicBindingPathList":[],"children":[{"boxShadow":"none","borderColor":"#E0DEDE","iconSVG":"/static/media/icon.efac588608711d232f1c6c8a2144d2dd.svg","onSubmit":"{{Set_Rabbitmq.run().then(() => {\n showAlert('Rabbitmq updated successfully', 'success');\n}).catch(() => {\n showAlert('Error updating rabbitmq', 'error');\n});\ncloseModal('ModalRabbitmq');}}","topRow":0.0,"type":"JSON_FORM_WIDGET","animateLoading":true,"leftColumn":0.0,"dynamicBindingPathList":[{"key":"borderRadius"},{"key":"submitButtonStyles.buttonColor"},{"key":"sourceData"},{"key":"schema.__root_schema__.defaultValue"},{"key":"schema.__root_schema__.borderRadius"},{"key":"schema.__root_schema__.children.enabled.defaultValue"},{"key":"schema.__root_schema__.children.enabled.accentColor"},{"key":"schema.__root_schema__.children.events.defaultValue"},{"key":"schema.__root_schema__.children.events.accentColor"},{"key":"schema.__root_schema__.children.events.borderRadius"},{"key":"schema.__root_schema__.cellBorderRadius"}],"showReset":false,"dynamicHeight":"AUTO_HEIGHT","autoGenerateForm":false,"resetButtonStyles":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","buttonVariant":"SECONDARY"},"isVisible":true,"version":1.0,"isLoading":false,"submitButtonLabel":"Save","childStylesheet":{"ARRAY":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","cellBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","cellBoxShadow":"none"},"OBJECT":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","cellBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","cellBoxShadow":"none"},"CHECKBOX":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}"},"CURRENCY_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"DATEPICKER":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"EMAIL_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTISELECT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTILINE_TEXT_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"NUMBER_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PASSWORD_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PHONE_NUMBER_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"RADIO_GROUP":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"SELECT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"SWITCH":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"TEXT_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"}},"disabledWhenInvalid":true,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","originalBottomRow":30.0,"useSourceData":false,"schema":{"__root_schema__":{"children":{"enabled":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.enabled))(FormRabbitmq.sourceData, FormRabbitmq.formData, FormRabbitmq.fieldState)}}","fieldType":"Switch","sourceData":false,"isCustomField":false,"accessor":"enabled","identifier":"enabled","position":0.0,"originalIdentifier":"enabled","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormRabbitmq.sourceData, FormRabbitmq.formData, FormRabbitmq.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Enabled"},"events":{"children":{},"dataType":"array","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.events))(FormRabbitmq.sourceData, FormRabbitmq.formData, FormRabbitmq.fieldState)}}","fieldType":"Multiselect","sourceData":[],"isCustomField":false,"accessor":"events","identifier":"events","position":1.0,"originalIdentifier":"events","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormRabbitmq.sourceData, FormRabbitmq.formData, FormRabbitmq.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormRabbitmq.sourceData, FormRabbitmq.formData, FormRabbitmq.fieldState)}}","boxShadow":"none","isDisabled":false,"isFilterable":false,"isRequired":false,"isVisible":true,"label":"Events","labelTextSize":"0.875rem","serverSideFiltering":false,"options":"[\n\n {\n \"label\": \"APPLICATION_STARTUP\",\n \"value\": \"APPLICATION_STARTUP\"\n },\n {\n \"label\": \"QRCODE_UPDATED\",\n \"value\": \"QRCODE_UPDATED\"\n },\n {\n \"label\": \"MESSAGES_SET\",\n \"value\": \"MESSAGES_SET\"\n },\n {\n \"label\": \"MESSAGES_UPSERT\",\n \"value\": \"MESSAGES_UPSERT\"\n },\n {\n \"label\": \"MESSAGES_UPDATE\",\n \"value\": \"MESSAGES_UPDATE\"\n },\n {\n \"label\": \"MESSAGES_DELETE\",\n \"value\": \"MESSAGES_DELETE\"\n },\n {\n \"label\": \"SEND_MESSAGE\",\n \"value\": \"SEND_MESSAGE\"\n },\n {\n \"label\": \"CONTACTS_SET\",\n \"value\": \"CONTACTS_SET\"\n },\n {\n \"label\": \"CONTACTS_UPSERT\",\n \"value\": \"CONTACTS_UPSERT\"\n },\n {\n \"label\": \"CONTACTS_UPDATE\",\n \"value\": \"CONTACTS_UPDATE\"\n },\n {\n \"label\": \"PRESENCE_UPDATE\",\n \"value\": \"PRESENCE_UPDATE\"\n },\n {\n \"label\": \"CHATS_SET\",\n \"value\": \"CHATS_SET\"\n },\n {\n \"label\": \"CHATS_UPSERT\",\n \"value\": \"CHATS_UPSERT\"\n },\n {\n \"label\": \"CHATS_UPDATE\",\n \"value\": \"CHATS_UPDATE\"\n },\n {\n \"label\": \"CHATS_DELETE\",\n \"value\": \"CHATS_DELETE\"\n },\n {\n \"label\": \"GROUPS_UPSERT\",\n \"value\": \"GROUPS_UPSERT\"\n },\n {\n \"label\": \"GROUP_UPDATE\",\n \"value\": \"GROUP_UPDATE\"\n },\n {\n \"label\": \"GROUP_PARTICIPANTS_UPDATE\",\n \"value\": \"GROUP_PARTICIPANTS_UPDATE\"\n },\n {\n \"label\": \"CONNECTION_UPDATE\",\n \"value\": \"CONNECTION_UPDATE\"\n },\n {\n \"label\": \"CALL\",\n \"value\": \"CALL\"\n },\n {\n \"label\": \"NEW_JWT_TOKEN\",\n \"value\": \"NEW_JWT_TOKEN\"\n }\n]"}},"dataType":"object","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData))(FormRabbitmq.sourceData, FormRabbitmq.formData, FormRabbitmq.fieldState)}}","fieldType":"Object","sourceData":{"enabled":false,"events":[]},"isCustomField":false,"accessor":"__root_schema__","identifier":"__root_schema__","position":-1.0,"originalIdentifier":"__root_schema__","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormRabbitmq.sourceData, FormRabbitmq.formData, FormRabbitmq.fieldState)}}","boxShadow":"none","cellBorderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormRabbitmq.sourceData, FormRabbitmq.formData, FormRabbitmq.fieldState)}}","cellBoxShadow":"none","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":""}},"mobileBottomRow":41.0,"widgetName":"FormRabbitmq","submitButtonStyles":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","buttonVariant":"PRIMARY"},"dynamicPropertyPathList":[{"key":"schema.__root_schema__.children.events.defaultValue"},{"key":"schema.__root_schema__.children.enabled.defaultValue"}],"displayName":"JSON Form","bottomRow":30.0,"fieldLimitExceeded":false,"parentRowSpace":10.0,"title":"Rabbitmq","hideCard":false,"mobileRightColumn":25.0,"parentColumnSpace":6.9375,"dynamicTriggerPathList":[{"key":"onSubmit"}],"borderWidth":"0","sourceData":"{\n\t\"enabled\": {{Find_Rabbitmq.data.enabled || false}},\n \"events\": {{Find_Rabbitmq.data.events}}\n\t\t\n }","resetButtonLabel":"Reset","key":"lgqqk5r1jk","backgroundColor":"#fff","isDeprecated":false,"rightColumn":63.0,"widgetId":"gdkpog7ep5","minWidth":450.0,"parentId":"rkuaegvcin","renderMode":"CANVAS","mobileTopRow":0.0,"scrollContents":true,"responsiveBehavior":"fill","fixedFooter":true,"originalTopRow":0.0,"mobileLeftColumn":0.0,"maxDynamicHeight":9000.0,"minDynamicHeight":4.0}],"isDisabled":false,"key":"svq68rvpdn","isDeprecated":false,"rightColumn":430.5,"detachFromLayout":true,"widgetId":"rkuaegvcin","minWidth":450.0,"isVisible":true,"version":1.0,"parentId":"76vl08dr1n","renderMode":"CANVAS","isLoading":false,"mobileTopRow":0.0,"responsiveBehavior":"fill","mobileLeftColumn":0.0,"flexLayers":[]}],"key":"6x3z5yow7u","height":320.0,"isDeprecated":false,"rightColumn":35.0,"detachFromLayout":true,"dynamicHeight":"AUTO_HEIGHT","widgetId":"76vl08dr1n","canOutsideClickClose":true,"canEscapeKeyClose":true,"version":2.0,"parentId":"0","renderMode":"CANVAS","isLoading":false,"mobileTopRow":46.0,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":11.0,"maxDynamicHeight":9000.0,"width":456.0,"minDynamicHeight":24.0},{"boxShadow":"none","mobileBottomRow":70.0,"widgetName":"ModalSettings","isCanvas":true,"displayName":"Modal","iconSVG":"/static/media/icon.d2ab7de0666eaef853cc2d330f86887b.svg","searchTags":["dialog","popup","notification"],"topRow":46.0,"bottomRow":47.0,"parentRowSpace":10.0,"type":"MODAL_WIDGET","hideCard":false,"shouldScrollContents":true,"mobileRightColumn":35.0,"minHeight":470.0,"animateLoading":true,"parentColumnSpace":17.9375,"leftColumn":11.0,"dynamicBindingPathList":[{"key":"borderRadius"}],"children":[{"mobileBottomRow":240.0,"widgetName":"Canvas4Copy","displayName":"Canvas","topRow":0.0,"bottomRow":470.0,"parentRowSpace":1.0,"type":"CANVAS_WIDGET","canExtend":true,"hideCard":true,"shouldScrollContents":false,"minHeight":240.0,"mobileRightColumn":430.5,"parentColumnSpace":1.0,"leftColumn":0.0,"dynamicBindingPathList":[],"children":[{"boxShadow":"none","borderColor":"#E0DEDE","iconSVG":"/static/media/icon.efac588608711d232f1c6c8a2144d2dd.svg","onSubmit":"{{Set_Settings.run().then(() => {\n showAlert('Settings updated successfully', 'success');\n}).catch(() => {\n showAlert('Error updating Settings', 'error');\n});\ncloseModal('ModalSettings');}}","topRow":0.0,"type":"JSON_FORM_WIDGET","animateLoading":true,"leftColumn":1.0,"dynamicBindingPathList":[{"key":"schema.__root_schema__.children.read_status.accentColor"},{"key":"schema.__root_schema__.children.read_status.defaultValue"},{"key":"schema.__root_schema__.children.read_messages.accentColor"},{"key":"schema.__root_schema__.children.read_messages.defaultValue"},{"key":"schema.__root_schema__.children.always_online.accentColor"},{"key":"schema.__root_schema__.children.always_online.defaultValue"},{"key":"schema.__root_schema__.children.groups_ignore.accentColor"},{"key":"schema.__root_schema__.children.groups_ignore.defaultValue"},{"key":"schema.__root_schema__.children.msg_call.accentColor"},{"key":"schema.__root_schema__.children.msg_call.defaultValue"},{"key":"schema.__root_schema__.children.reject_call.accentColor"},{"key":"schema.__root_schema__.children.reject_call.defaultValue"},{"key":"borderRadius"},{"key":"sourceData"},{"key":"schema.__root_schema__.children.msg_call.borderRadius"},{"key":"submitButtonStyles.buttonColor"}],"showReset":false,"dynamicHeight":"AUTO_HEIGHT","autoGenerateForm":true,"resetButtonStyles":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","buttonVariant":"SECONDARY"},"isVisible":true,"version":1.0,"isLoading":false,"submitButtonLabel":"Save","childStylesheet":{"ARRAY":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","cellBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","cellBoxShadow":"none"},"OBJECT":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","cellBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","cellBoxShadow":"none"},"CHECKBOX":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}"},"CURRENCY_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"DATEPICKER":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"EMAIL_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTISELECT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTILINE_TEXT_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"NUMBER_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PASSWORD_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PHONE_NUMBER_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"RADIO_GROUP":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"SELECT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"SWITCH":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"TEXT_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"}},"disabledWhenInvalid":true,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","originalBottomRow":45.0,"useSourceData":false,"schema":{"__root_schema__":{"children":{"reject_call":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.reject_call))(FormSettings.sourceData, FormSettings.formData, FormSettings.fieldState)}}","fieldType":"Switch","sourceData":true,"isCustomField":false,"accessor":"reject_call","identifier":"reject_call","position":0.0,"originalIdentifier":"reject_call","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormSettings.sourceData, FormSettings.formData, FormSettings.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Reject Call"},"msg_call":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.msg_call))(FormSettings.sourceData, FormSettings.formData, FormSettings.fieldState)}}","fieldType":"Text Input","sourceData":"Não aceitamos chamadas!","isCustomField":false,"accessor":"msg_call","identifier":"msg_call","position":1.0,"originalIdentifier":"msg_call","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormSettings.sourceData, FormSettings.formData, FormSettings.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormSettings.sourceData, FormSettings.formData, FormSettings.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Msg Call"},"groups_ignore":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.groups_ignore))(FormSettings.sourceData, FormSettings.formData, FormSettings.fieldState)}}","fieldType":"Switch","sourceData":true,"isCustomField":false,"accessor":"groups_ignore","identifier":"groups_ignore","position":2.0,"originalIdentifier":"groups_ignore","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormSettings.sourceData, FormSettings.formData, FormSettings.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Groups Ignore"},"always_online":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.always_online))(FormSettings.sourceData, FormSettings.formData, FormSettings.fieldState)}}","fieldType":"Switch","sourceData":true,"isCustomField":false,"accessor":"always_online","identifier":"always_online","position":3.0,"originalIdentifier":"always_online","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormSettings.sourceData, FormSettings.formData, FormSettings.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Always Online"},"read_messages":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.read_messages))(FormSettings.sourceData, FormSettings.formData, FormSettings.fieldState)}}","fieldType":"Switch","sourceData":true,"isCustomField":false,"accessor":"read_messages","identifier":"read_messages","position":4.0,"originalIdentifier":"read_messages","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormSettings.sourceData, FormSettings.formData, FormSettings.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Read Messages"},"read_status":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.read_status))(FormSettings.sourceData, FormSettings.formData, FormSettings.fieldState)}}","fieldType":"Switch","sourceData":false,"isCustomField":false,"accessor":"read_status","identifier":"read_status","position":5.0,"originalIdentifier":"read_status","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormSettings.sourceData, FormSettings.formData, FormSettings.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Read Status"}},"dataType":"object","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData))(FormWebhook.sourceData, FormWebhook.formData, FormWebhook.fieldState)}}","fieldType":"Object","sourceData":{"name":"John","date_of_birth":"20/02/1990","employee_id":1001.0},"isCustomField":false,"accessor":"__root_schema__","identifier":"__root_schema__","position":-1.0,"originalIdentifier":"__root_schema__","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormWebhook.sourceData, FormWebhook.formData, FormWebhook.fieldState)}}","boxShadow":"none","cellBorderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormWebhook.sourceData, FormWebhook.formData, FormWebhook.fieldState)}}","cellBoxShadow":"none","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":""}},"mobileBottomRow":41.0,"widgetName":"FormSettings","submitButtonStyles":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","buttonVariant":"PRIMARY"},"dynamicPropertyPathList":[{"key":"schema.__root_schema__.children.reject_call.defaultValue"},{"key":"schema.__root_schema__.children.groups_ignore.defaultValue"},{"key":"schema.__root_schema__.children.always_online.defaultValue"},{"key":"schema.__root_schema__.children.read_messages.defaultValue"},{"key":"schema.__root_schema__.children.read_status.defaultValue"},{"key":"schema.__root_schema__.children.msg_call.defaultValue"}],"displayName":"JSON Form","bottomRow":45.0,"fieldLimitExceeded":false,"parentRowSpace":10.0,"title":"Settings","hideCard":false,"mobileRightColumn":25.0,"parentColumnSpace":6.9375,"dynamicTriggerPathList":[{"key":"onSubmit"}],"borderWidth":"0","sourceData":"{\n\t\"reject_call\": {{Find_Settings.data.reject_call || false}},\n \"msg_call\": {{Find_Settings.data.msg_call}},\n \"groups_ignore\": {{Find_Settings.data.groups_ignore || false}},\n \"always_online\": {{Find_Settings.data.always_online || false}},\n \"read_messages\": {{Find_Settings.data.read_messages || false}},\n \"read_status\": {{Find_Settings.data.read_status || false}}\n}","resetButtonLabel":"Reset","key":"lgqqk5r1jk","backgroundColor":"#fff","isDeprecated":false,"rightColumn":64.0,"widgetId":"3wajdobhry","minWidth":450.0,"parentId":"bj66ktxeor","renderMode":"CANVAS","mobileTopRow":0.0,"scrollContents":true,"responsiveBehavior":"fill","fixedFooter":true,"originalTopRow":0.0,"mobileLeftColumn":0.0,"maxDynamicHeight":9000.0,"minDynamicHeight":4.0}],"isDisabled":false,"key":"svq68rvpdn","isDeprecated":false,"rightColumn":430.5,"detachFromLayout":true,"widgetId":"bj66ktxeor","minWidth":450.0,"isVisible":true,"version":1.0,"parentId":"9pvl5efylb","renderMode":"CANVAS","isLoading":false,"mobileTopRow":0.0,"responsiveBehavior":"fill","mobileLeftColumn":0.0,"flexLayers":[]}],"key":"6x3z5yow7u","height":470.0,"isDeprecated":false,"rightColumn":35.0,"detachFromLayout":true,"dynamicHeight":"AUTO_HEIGHT","widgetId":"9pvl5efylb","canOutsideClickClose":true,"canEscapeKeyClose":true,"version":2.0,"parentId":"0","renderMode":"CANVAS","isLoading":false,"mobileTopRow":46.0,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":11.0,"maxDynamicHeight":9000.0,"width":456.0,"minDynamicHeight":24.0},{"boxShadow":"none","mobileBottomRow":70.0,"widgetName":"ModalChatwoot","isCanvas":true,"displayName":"Modal","iconSVG":"/static/media/icon.d2ab7de0666eaef853cc2d330f86887b.svg","searchTags":["dialog","popup","notification"],"topRow":50.0,"bottomRow":780.0,"parentRowSpace":10.0,"type":"MODAL_WIDGET","hideCard":false,"shouldScrollContents":true,"mobileRightColumn":35.0,"minHeight":730.0,"animateLoading":true,"parentColumnSpace":17.9375,"leftColumn":11.0,"dynamicBindingPathList":[{"key":"borderRadius"}],"children":[{"mobileBottomRow":240.0,"widgetName":"Canvas4CopyCopy","displayName":"Canvas","topRow":0.0,"bottomRow":730.0,"parentRowSpace":1.0,"type":"CANVAS_WIDGET","canExtend":true,"hideCard":true,"shouldScrollContents":false,"minHeight":730.0,"mobileRightColumn":430.5,"parentColumnSpace":1.0,"leftColumn":0.0,"dynamicBindingPathList":[],"children":[{"boxShadow":"none","borderColor":"#E0DEDE","iconSVG":"/static/media/icon.efac588608711d232f1c6c8a2144d2dd.svg","onSubmit":"{{Set_Chatwoot.run().then(() => {\n showAlert('Chatwoot updated successfully', 'success');\n}).catch(() => {\n showAlert('Error updating Chatwoot', 'error');\n});\ncloseModal('ModalChatwoot');}}","topRow":0.0,"type":"JSON_FORM_WIDGET","animateLoading":true,"leftColumn":0.0,"dynamicBindingPathList":[{"key":"schema.__root_schema__.children.conversation_pending.accentColor"},{"key":"schema.__root_schema__.children.conversation_pending.defaultValue"},{"key":"schema.__root_schema__.children.reopen_conversation.accentColor"},{"key":"schema.__root_schema__.children.reopen_conversation.defaultValue"},{"key":"schema.__root_schema__.children.sign_msg.accentColor"},{"key":"schema.__root_schema__.children.sign_msg.defaultValue"},{"key":"schema.__root_schema__.children.url.borderRadius"},{"key":"schema.__root_schema__.children.url.accentColor"},{"key":"schema.__root_schema__.children.url.defaultValue"},{"key":"schema.__root_schema__.children.token.borderRadius"},{"key":"schema.__root_schema__.children.token.accentColor"},{"key":"schema.__root_schema__.children.token.defaultValue"},{"key":"schema.__root_schema__.children.account_id.accentColor"},{"key":"schema.__root_schema__.children.account_id.defaultValue"},{"key":"schema.__root_schema__.children.enabled.accentColor"},{"key":"schema.__root_schema__.children.enabled.defaultValue"},{"key":"borderRadius"},{"key":"sourceData"},{"key":"schema.__root_schema__.children.account_id.borderRadius"},{"key":"schema.__root_schema__.children.webhook_url.defaultValue"},{"key":"schema.__root_schema__.children.webhook_url.accentColor"},{"key":"schema.__root_schema__.children.webhook_url.borderRadius"},{"key":"schema.__root_schema__.defaultValue"},{"key":"schema.__root_schema__.borderRadius"},{"key":"schema.__root_schema__.cellBorderRadius"},{"key":"schema.__root_schema__.children.name_inbox.defaultValue"},{"key":"schema.__root_schema__.children.name_inbox.borderRadius"},{"key":"schema.__root_schema__.children.name_inbox.accentColor"},{"key":"submitButtonStyles.buttonColor"}],"showReset":false,"dynamicHeight":"AUTO_HEIGHT","autoGenerateForm":true,"resetButtonStyles":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","buttonVariant":"SECONDARY"},"isVisible":true,"version":1.0,"isLoading":false,"submitButtonLabel":"Save","childStylesheet":{"ARRAY":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","cellBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","cellBoxShadow":"none"},"OBJECT":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","cellBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","cellBoxShadow":"none"},"CHECKBOX":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}"},"CURRENCY_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"DATEPICKER":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"EMAIL_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTISELECT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTILINE_TEXT_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"NUMBER_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PASSWORD_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PHONE_NUMBER_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"RADIO_GROUP":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"SELECT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"SWITCH":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"TEXT_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"}},"disabledWhenInvalid":true,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","originalBottomRow":71.0,"useSourceData":false,"schema":{"__root_schema__":{"children":{"enabled":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.enabled))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","fieldType":"Switch","sourceData":true,"isCustomField":false,"accessor":"enabled","identifier":"enabled","position":0.0,"originalIdentifier":"enabled","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Enabled"},"account_id":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.account_id))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","fieldType":"Text Input","sourceData":"1","isCustomField":false,"accessor":"account_id","identifier":"account_id","position":1.0,"originalIdentifier":"account_id","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Account Id"},"token":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.token))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","fieldType":"Password Input","sourceData":"uHquVJgCdkee8JPJm9YBkdH6","isCustomField":false,"accessor":"token","identifier":"token","position":2.0,"originalIdentifier":"token","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Token","shouldAllowAutofill":true},"url":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.url))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","fieldType":"Text Input","sourceData":"https://chatwoot.evolution.dgcode.com.br","isCustomField":false,"accessor":"url","identifier":"url","position":3.0,"originalIdentifier":"url","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Url"},"sign_msg":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.sign_msg))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","fieldType":"Switch","sourceData":false,"isCustomField":false,"accessor":"sign_msg","identifier":"sign_msg","position":4.0,"originalIdentifier":"sign_msg","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Sign Msg"},"reopen_conversation":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.reopen_conversation))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","fieldType":"Switch","sourceData":true,"isCustomField":false,"accessor":"reopen_conversation","identifier":"reopen_conversation","position":5.0,"originalIdentifier":"reopen_conversation","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Reopen Conversation"},"conversation_pending":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.conversation_pending))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","fieldType":"Switch","sourceData":false,"isCustomField":false,"accessor":"conversation_pending","identifier":"conversation_pending","position":6.0,"originalIdentifier":"conversation_pending","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Conversation Pending"},"webhook_url":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.webhook_url))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","fieldType":"Text Input","sourceData":"https://api.evolution.dgcode.com.br/chatwoot/webhook/evolution-cwId-4","isCustomField":false,"accessor":"webhook_url","identifier":"webhook_url","position":8.0,"originalIdentifier":"webhook_url","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":true,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Webhook Url"},"name_inbox":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.name_inbox))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","fieldType":"Text Input","sourceData":"evolution-cwId-4","isCustomField":false,"accessor":"name_inbox","identifier":"name_inbox","position":7.0,"originalIdentifier":"name_inbox","accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":true,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Name Inbox"}},"dataType":"object","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData))(FormWebhook.sourceData, FormWebhook.formData, FormWebhook.fieldState)}}","fieldType":"Object","sourceData":{"name":"John","date_of_birth":"20/02/1990","employee_id":1001.0},"isCustomField":false,"accessor":"__root_schema__","identifier":"__root_schema__","position":-1.0,"originalIdentifier":"__root_schema__","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormWebhook.sourceData, FormWebhook.formData, FormWebhook.fieldState)}}","boxShadow":"none","cellBorderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormWebhook.sourceData, FormWebhook.formData, FormWebhook.fieldState)}}","cellBoxShadow":"none","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":""}},"mobileBottomRow":41.0,"widgetName":"FormChatwoot","submitButtonStyles":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","buttonVariant":"PRIMARY"},"dynamicPropertyPathList":[{"key":"schema.__root_schema__.children.enabled.defaultValue"},{"key":"schema.__root_schema__.children.sign_msg.defaultValue"},{"key":"schema.__root_schema__.children.reopen_conversation.defaultValue"},{"key":"schema.__root_schema__.children.conversation_pending.defaultValue"},{"key":"schema.__root_schema__.children.account_id.defaultValue"},{"key":"schema.__root_schema__.children.webhook_url.defaultValue"}],"displayName":"JSON Form","bottomRow":71.0,"fieldLimitExceeded":false,"parentRowSpace":10.0,"title":"Chatwoot","hideCard":false,"mobileRightColumn":25.0,"parentColumnSpace":6.9375,"dynamicTriggerPathList":[{"key":"onSubmit"}],"borderWidth":"0","sourceData":"{\n\t\"enabled\": {{Find_Chatwoot.data.enabled || false}},\n\t\"account_id\": {{Find_Chatwoot.data.account_id}},\n \"token\": {{Find_Chatwoot.data.token}},\n \"url\": {{Find_Chatwoot.data.url}},\n \"sign_msg\": {{Find_Chatwoot.data.sign_msg || false}},\n \"reopen_conversation\": {{Find_Chatwoot.data.reopen_conversation || false}},\n \"conversation_pending\": {{Find_Chatwoot.data.conversation_pending || false}},\n\t\t\"name_inbox\": {{Find_Chatwoot.data.name_inbox}},\n\t\t\"webhook_url\": {{Find_Chatwoot.data.webhook_url}}\n}","resetButtonLabel":"Reset","key":"lgqqk5r1jk","backgroundColor":"#fff","isDeprecated":false,"rightColumn":63.0,"widgetId":"c5v1lwuyrk","minWidth":450.0,"parentId":"wqoo05rt9h","renderMode":"CANVAS","mobileTopRow":0.0,"scrollContents":true,"responsiveBehavior":"fill","fixedFooter":true,"originalTopRow":0.0,"mobileLeftColumn":0.0,"maxDynamicHeight":9000.0,"minDynamicHeight":4.0}],"isDisabled":false,"key":"svq68rvpdn","isDeprecated":false,"rightColumn":430.5,"detachFromLayout":true,"widgetId":"wqoo05rt9h","minWidth":450.0,"isVisible":true,"version":1.0,"parentId":"kekx3o71p4","renderMode":"CANVAS","isLoading":false,"mobileTopRow":0.0,"responsiveBehavior":"fill","mobileLeftColumn":0.0,"flexLayers":[]}],"key":"6x3z5yow7u","height":730.0,"isDeprecated":false,"rightColumn":35.0,"detachFromLayout":true,"dynamicHeight":"AUTO_HEIGHT","widgetId":"kekx3o71p4","canOutsideClickClose":true,"canEscapeKeyClose":true,"version":2.0,"parentId":"0","renderMode":"CANVAS","isLoading":false,"mobileTopRow":46.0,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":11.0,"maxDynamicHeight":9000.0,"width":692.0,"minDynamicHeight":24.0},{"boxShadow":"none","mobileBottomRow":70.0,"widgetName":"ModalTypebot","isCanvas":true,"displayName":"Modal","iconSVG":"/static/media/icon.d2ab7de0666eaef853cc2d330f86887b.svg","searchTags":["dialog","popup","notification"],"topRow":45.0,"bottomRow":775.0,"parentRowSpace":10.0,"type":"MODAL_WIDGET","hideCard":false,"shouldScrollContents":true,"mobileRightColumn":35.0,"minHeight":730.0,"animateLoading":true,"parentColumnSpace":17.9375,"leftColumn":11.0,"dynamicBindingPathList":[{"key":"borderRadius"}],"children":[{"mobileBottomRow":240.0,"widgetName":"Canvas4CopyCopyCopy","displayName":"Canvas","topRow":0.0,"bottomRow":730.0,"parentRowSpace":1.0,"type":"CANVAS_WIDGET","canExtend":true,"hideCard":true,"shouldScrollContents":false,"minHeight":730.0,"mobileRightColumn":430.5,"parentColumnSpace":1.0,"leftColumn":0.0,"dynamicBindingPathList":[],"children":[{"boxShadow":"none","borderColor":"#E0DEDE","iconSVG":"/static/media/icon.efac588608711d232f1c6c8a2144d2dd.svg","onSubmit":"{{Set_Typebot.run().then(() => {\n showAlert('Typebot updated successfully', 'success');\n}).catch(() => {\n showAlert('Error updating Typebot', 'error');\n});\ncloseModal('ModalTypebot');}}","topRow":1.0,"type":"JSON_FORM_WIDGET","animateLoading":true,"leftColumn":0.0,"dynamicBindingPathList":[{"key":"borderRadius"},{"key":"schema.__root_schema__.defaultValue"},{"key":"schema.__root_schema__.borderRadius"},{"key":"submitButtonStyles.buttonColor"},{"key":"schema.__root_schema__.cellBorderRadius"},{"key":"sourceData"},{"key":"schema.__root_schema__.children.enabled.defaultValue"},{"key":"schema.__root_schema__.children.enabled.accentColor"},{"key":"schema.__root_schema__.children.url.defaultValue"},{"key":"schema.__root_schema__.children.url.accentColor"},{"key":"schema.__root_schema__.children.url.borderRadius"},{"key":"schema.__root_schema__.children.typebot.defaultValue"},{"key":"schema.__root_schema__.children.typebot.accentColor"},{"key":"schema.__root_schema__.children.typebot.borderRadius"},{"key":"schema.__root_schema__.children.expire.defaultValue"},{"key":"schema.__root_schema__.children.expire.accentColor"},{"key":"schema.__root_schema__.children.expire.borderRadius"},{"key":"schema.__root_schema__.children.keyword_finish.defaultValue"},{"key":"schema.__root_schema__.children.keyword_finish.accentColor"},{"key":"schema.__root_schema__.children.keyword_finish.borderRadius"},{"key":"schema.__root_schema__.children.delay_message.defaultValue"},{"key":"schema.__root_schema__.children.delay_message.accentColor"},{"key":"schema.__root_schema__.children.delay_message.borderRadius"},{"key":"schema.__root_schema__.children.unknown_message.defaultValue"},{"key":"schema.__root_schema__.children.unknown_message.accentColor"},{"key":"schema.__root_schema__.children.unknown_message.borderRadius"},{"key":"schema.__root_schema__.children.listening_from_me.defaultValue"},{"key":"schema.__root_schema__.children.listening_from_me.accentColor"}],"showReset":false,"dynamicHeight":"AUTO_HEIGHT","autoGenerateForm":true,"resetButtonStyles":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","buttonVariant":"SECONDARY"},"isVisible":true,"version":1.0,"isLoading":false,"submitButtonLabel":"Save","childStylesheet":{"ARRAY":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","cellBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","cellBoxShadow":"none"},"OBJECT":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","cellBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","cellBoxShadow":"none"},"CHECKBOX":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}"},"CURRENCY_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"DATEPICKER":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"EMAIL_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTISELECT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTILINE_TEXT_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"NUMBER_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PASSWORD_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PHONE_NUMBER_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"RADIO_GROUP":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"SELECT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"SWITCH":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"TEXT_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"}},"disabledWhenInvalid":true,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","originalBottomRow":71.0,"useSourceData":false,"schema":{"__root_schema__":{"children":{"enabled":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.enabled))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","fieldType":"Switch","sourceData":true,"isCustomField":false,"accessor":"enabled","identifier":"enabled","position":0.0,"originalIdentifier":"enabled","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Enabled"},"url":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.url))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","fieldType":"Text Input","sourceData":"https://bot.typebot.com","isCustomField":false,"accessor":"url","identifier":"url","position":1.0,"originalIdentifier":"url","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Url"},"typebot":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.typebot))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","fieldType":"Text Input","sourceData":"felipe-final-sbkaa3s","isCustomField":false,"accessor":"typebot","identifier":"typebot","position":2.0,"originalIdentifier":"typebot","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Typebot"},"expire":{"children":{},"dataType":"number","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.expire))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","fieldType":"Number Input","sourceData":45.0,"isCustomField":false,"accessor":"expire","identifier":"expire","position":3.0,"originalIdentifier":"expire","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Expire"},"keyword_finish":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.keyword_finish))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","fieldType":"Text Input","sourceData":"#SAIR","isCustomField":false,"accessor":"keyword_finish","identifier":"keyword_finish","position":4.0,"originalIdentifier":"keyword_finish","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Keyword Finish"},"delay_message":{"children":{},"dataType":"number","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.delay_message))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","fieldType":"Number Input","sourceData":2000.0,"isCustomField":false,"accessor":"delay_message","identifier":"delay_message","position":5.0,"originalIdentifier":"delay_message","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Delay Message"},"unknown_message":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.unknown_message))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","fieldType":"Text Input","sourceData":"","isCustomField":false,"accessor":"unknown_message","identifier":"unknown_message","position":6.0,"originalIdentifier":"unknown_message","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Unknown Message"},"listening_from_me":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.listening_from_me))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","fieldType":"Switch","sourceData":false,"isCustomField":false,"accessor":"listening_from_me","identifier":"listening_from_me","position":7.0,"originalIdentifier":"listening_from_me","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Listening From Me"}},"dataType":"object","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","fieldType":"Object","sourceData":{"enabled":true,"url":"https://bot.typebot.com","typebot":"bot-typebot","expire":20.0,"keyword_finish":"#SAIR","delay_message":3000.0,"unknown_message":"Mensagem não reconhecida2"},"isCustomField":false,"accessor":"__root_schema__","identifier":"__root_schema__","position":-1.0,"originalIdentifier":"__root_schema__","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","boxShadow":"none","cellBorderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","cellBoxShadow":"none","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":""}},"mobileBottomRow":41.0,"widgetName":"FormTypebot","submitButtonStyles":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","buttonVariant":"PRIMARY"},"dynamicPropertyPathList":[{"key":"schema.__root_schema__.children.sign_msg.defaultValue"},{"key":"schema.__root_schema__.children.reopen_conversation.defaultValue"},{"key":"schema.__root_schema__.children.conversation_pending.defaultValue"},{"key":"schema.__root_schema__.children.account_id.defaultValue"},{"key":"schema.__root_schema__.children.webhook_url.defaultValue"},{"key":"schema.__root_schema__.children.enabled.defaultValue"},{"key":"schema.__root_schema__.children.listening_from_me.defaultValue"}],"displayName":"JSON Form","bottomRow":71.0,"fieldLimitExceeded":false,"parentRowSpace":10.0,"title":"Set Typebot","hideCard":false,"mobileRightColumn":25.0,"parentColumnSpace":6.9375,"dynamicTriggerPathList":[{"key":"onSubmit"}],"borderWidth":"0","sourceData":"{\n \"enabled\": {{Find_Typebot.data.enabled || false}},\n \"url\": {{Find_Typebot.data.url}},\n \"typebot\": {{Find_Typebot.data.typebot}},\n \"expire\": {{Find_Typebot.data.expire}},\n \"keyword_finish\": {{Find_Typebot.data.keyword_finish}},\n \"delay_message\": {{Find_Typebot.data.delay_message}},\n \"unknown_message\": {{Find_Typebot.data.unknown_message}},\n \"listening_from_me\": {{Find_Typebot.data.listening_from_me}}\n \n}","resetButtonLabel":"Reset","key":"lgqqk5r1jk","backgroundColor":"#fff","isDeprecated":false,"rightColumn":63.0,"widgetId":"fyu0oxvlx7","minWidth":450.0,"parentId":"bvxewkusbf","renderMode":"CANVAS","mobileTopRow":0.0,"scrollContents":true,"responsiveBehavior":"fill","fixedFooter":true,"originalTopRow":1.0,"mobileLeftColumn":0.0,"maxDynamicHeight":9000.0,"minDynamicHeight":4.0}],"isDisabled":false,"key":"svq68rvpdn","isDeprecated":false,"rightColumn":430.5,"detachFromLayout":true,"widgetId":"bvxewkusbf","minWidth":450.0,"isVisible":true,"version":1.0,"parentId":"4n3m0wo9tx","renderMode":"CANVAS","isLoading":false,"mobileTopRow":0.0,"responsiveBehavior":"fill","mobileLeftColumn":0.0,"flexLayers":[]}],"key":"6x3z5yow7u","height":730.0,"isDeprecated":false,"rightColumn":35.0,"detachFromLayout":true,"dynamicHeight":"AUTO_HEIGHT","widgetId":"4n3m0wo9tx","canOutsideClickClose":true,"canEscapeKeyClose":true,"version":2.0,"parentId":"0","renderMode":"CANVAS","isLoading":false,"mobileTopRow":46.0,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":11.0,"maxDynamicHeight":9000.0,"width":692.0,"minDynamicHeight":24.0},{"boxShadow":"none","mobileBottomRow":70.0,"widgetName":"ModalTypebotChangeSessionStatu","isCanvas":true,"displayName":"Modal","iconSVG":"/static/media/icon.d2ab7de0666eaef853cc2d330f86887b.svg","searchTags":["dialog","popup","notification"],"topRow":45.0,"bottomRow":415.0,"parentRowSpace":10.0,"type":"MODAL_WIDGET","hideCard":false,"shouldScrollContents":true,"mobileRightColumn":35.0,"minHeight":370.0,"animateLoading":true,"parentColumnSpace":17.9375,"leftColumn":11.0,"dynamicBindingPathList":[{"key":"borderRadius"}],"children":[{"mobileBottomRow":240.0,"widgetName":"Canvas4CopyCopyCopyCopy","displayName":"Canvas","topRow":0.0,"bottomRow":370.0,"parentRowSpace":1.0,"type":"CANVAS_WIDGET","canExtend":true,"hideCard":true,"shouldScrollContents":false,"minHeight":730.0,"mobileRightColumn":430.5,"parentColumnSpace":1.0,"leftColumn":0.0,"dynamicBindingPathList":[],"children":[{"boxShadow":"none","borderColor":"#E0DEDE","iconSVG":"/static/media/icon.efac588608711d232f1c6c8a2144d2dd.svg","onSubmit":"{{Set_TypebotChangeSessionStatus.run().then(() => {\n showAlert('Typebot Change Session updated successfully', 'success');\n}).catch(() => {\n showAlert('Error updating Session Typebot', 'error');\n});\ncloseModal('ModalTypebotChangeSessionStatu');}}","topRow":1.0,"type":"JSON_FORM_WIDGET","animateLoading":true,"leftColumn":0.0,"dynamicBindingPathList":[{"key":"borderRadius"},{"key":"schema.__root_schema__.defaultValue"},{"key":"schema.__root_schema__.borderRadius"},{"key":"submitButtonStyles.buttonColor"},{"key":"schema.__root_schema__.cellBorderRadius"},{"key":"schema.__root_schema__.children.remoteJid.defaultValue"},{"key":"schema.__root_schema__.children.remoteJid.accentColor"},{"key":"schema.__root_schema__.children.remoteJid.borderRadius"},{"key":"schema.__root_schema__.children.status.defaultValue"},{"key":"schema.__root_schema__.children.status.accentColor"},{"key":"schema.__root_schema__.children.status.borderRadius"}],"showReset":false,"dynamicHeight":"AUTO_HEIGHT","autoGenerateForm":true,"resetButtonStyles":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","buttonVariant":"SECONDARY"},"isVisible":true,"version":1.0,"isLoading":false,"submitButtonLabel":"Save","childStylesheet":{"ARRAY":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","cellBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","cellBoxShadow":"none"},"OBJECT":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","cellBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","cellBoxShadow":"none"},"CHECKBOX":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}"},"CURRENCY_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"DATEPICKER":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"EMAIL_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTISELECT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTILINE_TEXT_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"NUMBER_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PASSWORD_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PHONE_NUMBER_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"RADIO_GROUP":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"SELECT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"SWITCH":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"TEXT_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"}},"disabledWhenInvalid":true,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","originalBottomRow":35.0,"useSourceData":false,"schema":{"__root_schema__":{"children":{"remoteJid":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.remoteJid))(FormTypebotChangeSessionStatus.sourceData, FormTypebotChangeSessionStatus.formData, FormTypebotChangeSessionStatus.fieldState)}}","fieldType":"Text Input","sourceData":"","isCustomField":false,"accessor":"remoteJid","identifier":"remoteJid","position":0.0,"originalIdentifier":"remoteJid","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormTypebotChangeSessionStatus.sourceData, FormTypebotChangeSessionStatus.formData, FormTypebotChangeSessionStatus.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormTypebotChangeSessionStatus.sourceData, FormTypebotChangeSessionStatus.formData, FormTypebotChangeSessionStatus.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":true,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Remote Jid (WhatsApp. Ex: 5511968162699@s.whatsapp.net)"},"status":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.status))(FormTypebotChangeSessionStatus.sourceData, FormTypebotChangeSessionStatus.formData, FormTypebotChangeSessionStatus.fieldState)}}","fieldType":"Text Input","sourceData":"","isCustomField":false,"accessor":"status","identifier":"status","position":1.0,"originalIdentifier":"status","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormTypebotChangeSessionStatus.sourceData, FormTypebotChangeSessionStatus.formData, FormTypebotChangeSessionStatus.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormTypebotChangeSessionStatus.sourceData, FormTypebotChangeSessionStatus.formData, FormTypebotChangeSessionStatus.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Status (opened, paused or closed)"}},"dataType":"object","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","fieldType":"Object","sourceData":{"enabled":true,"url":"https://bot.typebot.com","typebot":"bot-typebot","expire":20.0,"keyword_finish":"#SAIR","delay_message":3000.0,"unknown_message":"Mensagem não reconhecida2"},"isCustomField":false,"accessor":"__root_schema__","identifier":"__root_schema__","position":-1.0,"originalIdentifier":"__root_schema__","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","boxShadow":"none","cellBorderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","cellBoxShadow":"none","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":""}},"mobileBottomRow":41.0,"widgetName":"FormTypebotChangeSessionStatus","submitButtonStyles":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","buttonVariant":"PRIMARY"},"dynamicPropertyPathList":[{"key":"schema.__root_schema__.children.sign_msg.defaultValue"},{"key":"schema.__root_schema__.children.reopen_conversation.defaultValue"},{"key":"schema.__root_schema__.children.conversation_pending.defaultValue"},{"key":"schema.__root_schema__.children.account_id.defaultValue"},{"key":"schema.__root_schema__.children.webhook_url.defaultValue"}],"displayName":"JSON Form","bottomRow":35.0,"fieldLimitExceeded":false,"parentRowSpace":10.0,"title":"Typebot Change Session Status","hideCard":false,"mobileRightColumn":25.0,"parentColumnSpace":6.9375,"dynamicTriggerPathList":[{"key":"onSubmit"}],"borderWidth":"0","sourceData":"{\n \"remoteJid\": \"@s.whatsapp.net\",\n \"status\": \"\"\n}","resetButtonLabel":"Reset","key":"lgqqk5r1jk","backgroundColor":"#fff","isDeprecated":false,"rightColumn":63.0,"widgetId":"28lli5jdvr","minWidth":450.0,"parentId":"8m0yhclt7g","renderMode":"CANVAS","mobileTopRow":0.0,"scrollContents":true,"responsiveBehavior":"fill","fixedFooter":true,"originalTopRow":1.0,"mobileLeftColumn":0.0,"maxDynamicHeight":9000.0,"minDynamicHeight":4.0}],"isDisabled":false,"key":"svq68rvpdn","isDeprecated":false,"rightColumn":430.5,"detachFromLayout":true,"widgetId":"8m0yhclt7g","minWidth":450.0,"isVisible":true,"version":1.0,"parentId":"84rj87eew6","renderMode":"CANVAS","isLoading":false,"mobileTopRow":0.0,"responsiveBehavior":"fill","mobileLeftColumn":0.0,"flexLayers":[]}],"key":"6x3z5yow7u","height":370.0,"isDeprecated":false,"rightColumn":35.0,"detachFromLayout":true,"dynamicHeight":"AUTO_HEIGHT","widgetId":"84rj87eew6","canOutsideClickClose":true,"canEscapeKeyClose":true,"version":2.0,"parentId":"0","renderMode":"CANVAS","isLoading":false,"mobileTopRow":46.0,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":11.0,"maxDynamicHeight":9000.0,"width":692.0,"minDynamicHeight":24.0},{"resetFormOnClick":false,"boxShadow":"none","mobileBottomRow":50.0,"widgetName":"Button2","onClick":"{{Fetch_Instance.run();\nFetch_PrivacySettings.run();\nshowModal('ModalProfile');}}","buttonColor":"#2770fc","dynamicPropertyPathList":[{"key":"isVisible"}],"displayName":"Button","iconSVG":"/static/media/icon.7beb9123fb53027d9d6b778cdfe4caed.svg","searchTags":["click","submit"],"topRow":28.0,"bottomRow":32.0,"parentRowSpace":10.0,"type":"BUTTON_WIDGET","hideCard":false,"mobileRightColumn":21.0,"animateLoading":true,"parentColumnSpace":17.9375,"dynamicTriggerPathList":[{"key":"onClick"}],"leftColumn":1.0,"dynamicBindingPathList":[{"key":"borderRadius"},{"key":"isVisible"}],"text":"Edit Profile","isDisabled":false,"key":"zhd9fobc1z","isDeprecated":false,"rightColumn":13.0,"isDefaultClickDisabled":true,"iconName":"edit","widgetId":"uh6430ysqy","minWidth":120.0,"isVisible":"{{appsmith.store.api_key && appsmith.store.api_url ? TableInstances.selectedRow.instance ? TableInstances.selectedRow.Status === 'open' ? true : false : false : false}}","recaptchaType":"V3","version":1.0,"parentId":"0","renderMode":"CANVAS","isLoading":false,"mobileTopRow":46.0,"responsiveBehavior":"hug","originalTopRow":51.0,"disabledWhenInvalid":false,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":5.0,"originalBottomRow":55.0,"buttonVariant":"PRIMARY","iconAlign":"left","placement":"CENTER"},{"boxShadow":"none","mobileBottomRow":59.0,"widgetName":"ModalProfile","isCanvas":true,"displayName":"Modal","iconSVG":"/static/media/icon.d2ab7de0666eaef853cc2d330f86887b.svg","searchTags":["dialog","popup","notification"],"topRow":35.0,"bottomRow":975.0,"parentRowSpace":10.0,"type":"MODAL_WIDGET","hideCard":false,"shouldScrollContents":true,"mobileRightColumn":35.0,"minHeight":940.0,"animateLoading":true,"parentColumnSpace":17.9375,"leftColumn":11.0,"dynamicBindingPathList":[{"key":"borderRadius"}],"children":[{"mobileBottomRow":240.0,"widgetName":"Canvas5","displayName":"Canvas","topRow":0.0,"bottomRow":940.0,"parentRowSpace":1.0,"type":"CANVAS_WIDGET","canExtend":true,"hideCard":true,"shouldScrollContents":false,"minHeight":240.0,"mobileRightColumn":430.5,"parentColumnSpace":1.0,"leftColumn":0.0,"dynamicBindingPathList":[],"children":[{"boxShadow":"none","borderColor":"#E0DEDE","iconSVG":"/static/media/icon.efac588608711d232f1c6c8a2144d2dd.svg","onSubmit":"{{Update_ProfileName.run().then(() => {\n showAlert('ProfileName successfully saved!', 'success');\n}).catch(() => {\n showAlert('Error updating ProfileName', 'error');\n});\nUpdate_ProfilePicture.run().then(() => {\n showAlert('ProfilePicture successfully saved!', 'success');\n}).catch(() => {\n showAlert('Error updating ProfilePicture', 'error');\n});\nUpdate_ProfileStatus.run().then(() => {\n showAlert('ProfileStatus successfully saved!', 'success');\n}).catch(() => {\n showAlert('Error updating ProfileStatus', 'error');\n});\nUpdate_PrivacySettings.run().then(() => {\n showAlert('PrivacySttings successfully saved!', 'success');\n}).catch(() => {\n showAlert('Error updating PrivacySttings', 'error');\n});\nfetch_Instances.run();\ncloseModal('ModalProfile');}}","topRow":0.0,"type":"JSON_FORM_WIDGET","animateLoading":true,"leftColumn":0.0,"dynamicBindingPathList":[{"key":"borderRadius"},{"key":"submitButtonStyles.buttonColor"},{"key":"submitButtonStyles.borderRadius"},{"key":"resetButtonStyles.buttonColor"},{"key":"resetButtonStyles.borderRadius"},{"key":"schema.__root_schema__.defaultValue"},{"key":"schema.__root_schema__.borderRadius"},{"key":"schema.__root_schema__.cellBorderRadius"},{"key":"schema.__root_schema__.children.profileName.defaultValue"},{"key":"schema.__root_schema__.children.profileName.accentColor"},{"key":"schema.__root_schema__.children.profileName.borderRadius"},{"key":"schema.__root_schema__.children.profileStatus.defaultValue"},{"key":"schema.__root_schema__.children.profileStatus.accentColor"},{"key":"schema.__root_schema__.children.profileStatus.borderRadius"},{"key":"schema.__root_schema__.children.profilePictureUrl.defaultValue"},{"key":"schema.__root_schema__.children.profilePictureUrl.borderRadius"},{"key":"sourceData"},{"key":"schema.__root_schema__.children.profilePictureUrl.accentColor"},{"key":"schema.__root_schema__.children.privacySettings.children.readreceipts.defaultValue"},{"key":"schema.__root_schema__.children.privacySettings.children.readreceipts.accentColor"},{"key":"schema.__root_schema__.children.privacySettings.children.readreceipts.borderRadius"},{"key":"schema.__root_schema__.children.privacySettings.children.profile.defaultValue"},{"key":"schema.__root_schema__.children.privacySettings.children.profile.accentColor"},{"key":"schema.__root_schema__.children.privacySettings.children.profile.borderRadius"},{"key":"schema.__root_schema__.children.privacySettings.children.status.defaultValue"},{"key":"schema.__root_schema__.children.privacySettings.children.status.accentColor"},{"key":"schema.__root_schema__.children.privacySettings.children.status.borderRadius"},{"key":"schema.__root_schema__.children.privacySettings.children.online.defaultValue"},{"key":"schema.__root_schema__.children.privacySettings.children.online.accentColor"},{"key":"schema.__root_schema__.children.privacySettings.children.online.borderRadius"},{"key":"schema.__root_schema__.children.privacySettings.children.last.defaultValue"},{"key":"schema.__root_schema__.children.privacySettings.children.last.accentColor"},{"key":"schema.__root_schema__.children.privacySettings.children.last.borderRadius"},{"key":"schema.__root_schema__.children.privacySettings.children.groupadd.defaultValue"},{"key":"schema.__root_schema__.children.privacySettings.children.groupadd.accentColor"},{"key":"schema.__root_schema__.children.privacySettings.children.groupadd.borderRadius"},{"key":"schema.__root_schema__.children.privacySettings.defaultValue"},{"key":"schema.__root_schema__.children.privacySettings.borderRadius"},{"key":"schema.__root_schema__.children.privacySettings.cellBorderRadius"}],"showReset":false,"dynamicHeight":"AUTO_HEIGHT","autoGenerateForm":true,"resetButtonStyles":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","buttonVariant":"SECONDARY"},"isVisible":true,"version":1.0,"isLoading":false,"submitButtonLabel":"Save","childStylesheet":{"ARRAY":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","cellBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","cellBoxShadow":"none"},"OBJECT":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","cellBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","cellBoxShadow":"none"},"CHECKBOX":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}"},"CURRENCY_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"DATEPICKER":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"EMAIL_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTISELECT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTILINE_TEXT_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"NUMBER_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PASSWORD_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PHONE_NUMBER_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"RADIO_GROUP":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"SELECT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"SWITCH":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"TEXT_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"}},"disabledWhenInvalid":true,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","originalBottomRow":92.0,"useSourceData":false,"schema":{"__root_schema__":{"children":{"profileName":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.profileName))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","fieldType":"Text Input","sourceData":"","isCustomField":false,"accessor":"profileName","identifier":"profileName","position":1.0,"originalIdentifier":"profileName","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Profile Name"},"profileStatus":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.profileStatus))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","fieldType":"Text Input","sourceData":"","isCustomField":false,"accessor":"profileStatus","identifier":"profileStatus","position":2.0,"originalIdentifier":"profileStatus","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Profile Status"},"profilePictureUrl":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.profilePictureUrl))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","fieldType":"Text Input","sourceData":"https://pps.whatsapp.net/v/t61.24694-24/359816109_329991892684302_7466658594467953893_n.jpg?ccb=11-4&oh=01_AdTpgc4O-xiZDr2v0OLu_jssxaw8dsws819srLMOzUwEnw&oe=64D3C41E","isCustomField":false,"accessor":"profilePictureUrl","identifier":"profilePictureUrl","position":0.0,"originalIdentifier":"profilePictureUrl","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Profile Picture Url"},"privacySettings":{"children":{"readreceipts":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.privacySettings.readreceipts))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","fieldType":"Select","sourceData":"all","isCustomField":false,"accessor":"readreceipts","identifier":"readreceipts","position":0.0,"originalIdentifier":"readreceipts","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","boxShadow":"none","isDisabled":false,"isFilterable":false,"isRequired":false,"isVisible":true,"label":"Readreceipts","labelTextSize":"0.875rem","serverSideFiltering":false,"options":"[\n {\n \"label\": \"all\",\n \"value\": \"all\"\n },\n {\n \"label\": \"none\",\n \"value\": \"none\"\n }\n]"},"profile":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.privacySettings.profile))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","fieldType":"Select","sourceData":"all","isCustomField":false,"accessor":"profile","identifier":"profile","position":1.0,"originalIdentifier":"profile","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","boxShadow":"none","isDisabled":false,"isFilterable":false,"isRequired":false,"isVisible":true,"label":"Profile","labelTextSize":"0.875rem","serverSideFiltering":false,"options":"[\n {\n \"label\": \"all\",\n \"value\": \"all\"\n },\n {\n \"label\": \"contacts\",\n \"value\": \"contacts\"\n },\n {\n \"label\": \"contact_blacklist\",\n \"value\": \"contact_blacklist\"\n },\n {\n \"label\": \"none\",\n \"value\": \"none\"\n }\n]"},"status":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.privacySettings.status))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","fieldType":"Select","sourceData":"contacts","isCustomField":false,"accessor":"status","identifier":"status","position":2.0,"originalIdentifier":"status","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","boxShadow":"none","isDisabled":false,"isFilterable":false,"isRequired":false,"isVisible":true,"label":"Status","labelTextSize":"0.875rem","serverSideFiltering":false,"options":"[\n {\n \"label\": \"all\",\n \"value\": \"all\"\n },\n {\n \"label\": \"contacts\",\n \"value\": \"contacts\"\n },\n {\n \"label\": \"contact_blacklist\",\n \"value\": \"contact_blacklist\"\n },\n {\n \"label\": \"none\",\n \"value\": \"none\"\n }\n]"},"online":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.privacySettings.online))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","fieldType":"Select","sourceData":"all","isCustomField":false,"accessor":"online","identifier":"online","position":3.0,"originalIdentifier":"online","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","boxShadow":"none","isDisabled":false,"isFilterable":false,"isRequired":false,"isVisible":true,"label":"Online","labelTextSize":"0.875rem","serverSideFiltering":false,"options":"[\n {\n \"label\": \"all\",\n \"value\": \"all\"\n },\n {\n \"label\": \"match_last_seen\",\n \"value\": \"match_last_seen\"\n }\n]"},"last":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.privacySettings.last))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","fieldType":"Select","sourceData":"contacts","isCustomField":false,"accessor":"last","identifier":"last","position":4.0,"originalIdentifier":"last","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","boxShadow":"none","isDisabled":false,"isFilterable":false,"isRequired":false,"isVisible":true,"label":"Last","labelTextSize":"0.875rem","serverSideFiltering":false,"options":"[\n {\n \"label\": \"all\",\n \"value\": \"all\"\n },\n {\n \"label\": \"contacts\",\n \"value\": \"contacts\"\n },\n {\n \"label\": \"contact_blacklist\",\n \"value\": \"contact_blacklist\"\n },\n {\n \"label\": \"none\",\n \"value\": \"none\"\n }\n]"},"groupadd":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.privacySettings.groupadd))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","fieldType":"Select","sourceData":"all","isCustomField":false,"accessor":"groupadd","identifier":"groupadd","position":5.0,"originalIdentifier":"groupadd","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","boxShadow":"none","isDisabled":false,"isFilterable":false,"isRequired":false,"isVisible":true,"label":"Groupadd","labelTextSize":"0.875rem","serverSideFiltering":false,"options":"[\n {\n \"label\": \"all\",\n \"value\": \"all\"\n },\n {\n \"label\": \"contacts\",\n \"value\": \"contacts\"\n },\n {\n \"label\": \"contact_blacklist\",\n \"value\": \"contact_blacklist\"\n },\n {\n \"label\": \"none\",\n \"value\": \"none\"\n }\n]"}},"dataType":"object","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.privacySettings))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","fieldType":"Object","sourceData":{"readreceipts":"all","profile":"all","status":"contacts","online":"all","last":"contacts","groupadd":"all"},"isCustomField":false,"accessor":"privacySettings","identifier":"privacySettings","position":3.0,"originalIdentifier":"privacySettings","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","boxShadow":"none","cellBorderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","cellBoxShadow":"none","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"1rem","label":"Privacy Settings","labelStyle":"BOLD"}},"dataType":"object","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","fieldType":"Object","sourceData":{"name":"John","date_of_birth":"20/02/1990","employee_id":1001.0},"isCustomField":false,"accessor":"__root_schema__","identifier":"__root_schema__","position":-1.0,"originalIdentifier":"__root_schema__","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","boxShadow":"none","cellBorderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","cellBoxShadow":"none","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":""}},"mobileBottomRow":41.0,"widgetName":"FormProfile","submitButtonStyles":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","buttonVariant":"PRIMARY"},"dynamicPropertyPathList":[],"displayName":"JSON Form","bottomRow":92.0,"fieldLimitExceeded":false,"parentRowSpace":10.0,"title":"Edit Profile","hideCard":false,"mobileRightColumn":25.0,"parentColumnSpace":6.9375,"dynamicTriggerPathList":[{"key":"onSubmit"}],"borderWidth":"0","sourceData":"{\n\t\"profilePictureUrl\": \"{{Fetch_Instance.data.instance.profilePictureUrl}}\",\n\t\"profileName\": \"{{Fetch_Instance.data.instance.profileName}}\",\n\t\"profileStatus\": \"{{Fetch_Instance.data.instance.profileStatus}}\",\n\t\"privacySettings\": {\n \"readreceipts\": {{Fetch_PrivacySettings.data.readreceipts}},\n \"profile\": {{Fetch_PrivacySettings.data.profile}},\n \"status\": {{Fetch_PrivacySettings.data.status}},\n \"online\": {{Fetch_PrivacySettings.data.online}},\n \"last\": {{Fetch_PrivacySettings.data.last}},\n \"groupadd\": {{Fetch_PrivacySettings.data.groupadd}}\n\t\t}\n}","resetButtonLabel":"","key":"72nqor459k","backgroundColor":"#fff","isDeprecated":false,"rightColumn":64.0,"widgetId":"hguxefink2","minWidth":450.0,"parentId":"basosxf5qt","renderMode":"CANVAS","mobileTopRow":0.0,"scrollContents":true,"responsiveBehavior":"fill","fixedFooter":true,"originalTopRow":0.0,"mobileLeftColumn":0.0,"maxDynamicHeight":9000.0,"minDynamicHeight":4.0}],"isDisabled":false,"key":"mepf0qsn1e","isDeprecated":false,"rightColumn":430.5,"detachFromLayout":true,"widgetId":"basosxf5qt","minWidth":450.0,"isVisible":true,"version":1.0,"parentId":"ss96aihlej","renderMode":"CANVAS","isLoading":false,"mobileTopRow":0.0,"responsiveBehavior":"fill","mobileLeftColumn":0.0,"flexLayers":[]}],"key":"4ktj7iym0b","height":940.0,"isDeprecated":false,"rightColumn":35.0,"detachFromLayout":true,"dynamicHeight":"AUTO_HEIGHT","widgetId":"ss96aihlej","canOutsideClickClose":true,"canEscapeKeyClose":true,"version":2.0,"parentId":"0","renderMode":"CANVAS","isLoading":false,"mobileTopRow":35.0,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":11.0,"maxDynamicHeight":9000.0,"width":456.0,"minDynamicHeight":24.0},{"mobileBottomRow":47.0,"widgetName":"Text6","displayName":"Text","iconSVG":"/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg","searchTags":["typography","paragraph","label"],"topRow":43.0,"bottomRow":47.0,"parentRowSpace":10.0,"type":"TEXT_WIDGET","hideCard":false,"mobileRightColumn":31.0,"animateLoading":true,"overflow":"NONE","fontFamily":"{{appsmith.theme.fontFamily.appFont}}","parentColumnSpace":12.3125,"dynamicTriggerPathList":[],"leftColumn":15.0,"dynamicBindingPathList":[{"key":"truncateButtonColor"},{"key":"fontFamily"},{"key":"borderRadius"}],"shouldTruncate":false,"truncateButtonColor":"{{appsmith.theme.colors.primaryColor}}","text":"This evolution api instance management panel is compatible from version 1.5 or higher\n","key":"vpoi1p6qvn","isDeprecated":false,"rightColumn":63.0,"textAlign":"LEFT","dynamicHeight":"AUTO_HEIGHT","widgetId":"yfenuu2x36","minWidth":450.0,"isVisible":true,"fontStyle":"BOLD","textColor":"#ef4444","version":1.0,"parentId":"0","tags":["Suggested","Content"],"renderMode":"CANVAS","isLoading":false,"mobileTopRow":43.0,"responsiveBehavior":"fill","originalTopRow":43.0,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":15.0,"maxDynamicHeight":9000.0,"originalBottomRow":48.0,"fontSize":"0.875rem","minDynamicHeight":4.0}]},"layoutOnLoadActions":[[{"id":"Home_Scripts.verifyConfig","name":"Scripts.verifyConfig","collectionId":"Home_Scripts","clientSideExecution":true,"confirmBeforeExecute":false,"pluginType":"JS","jsonPathKeys":[],"timeoutInMillisecond":10000.0}],[{"id":"Home_Find_Rabbitmq","name":"Find_Rabbitmq","confirmBeforeExecute":false,"pluginType":"API","jsonPathKeys":["TableInstances.selectedRow.Apikey","encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url"],"timeoutInMillisecond":10000.0},{"id":"Home_Find_Websocket","name":"Find_Websocket","confirmBeforeExecute":false,"pluginType":"API","jsonPathKeys":["TableInstances.selectedRow.Apikey","encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url"],"timeoutInMillisecond":10000.0}]],"layoutOnLoadActionErrors":[],"validOnPageLoadActions":true,"id":"Home","deleted":false,"policies":[],"userPermissions":[]}],"userPermissions":[],"policies":[],"isHidden":false},"publishedPage":{"name":"Home","slug":"home","customSlug":"","layouts":[{"viewMode":false,"dsl":{"widgetName":"MainContainer","backgroundColor":"none","rightColumn":4896.0,"snapColumns":64.0,"detachFromLayout":true,"widgetId":"0","topRow":0.0,"bottomRow":470.0,"containerStyle":"none","snapRows":124.0,"parentRowSpace":1.0,"type":"CANVAS_WIDGET","canExtend":true,"version":83.0,"minHeight":1292.0,"dynamicTriggerPathList":[],"parentColumnSpace":1.0,"dynamicBindingPathList":[],"leftColumn":0.0,"children":[{"boxShadow":"{{appsmith.theme.boxShadow.appBoxShadow}}","borderColor":"#E0DEDE","isVisibleDownload":true,"iconSVG":"https://appcdn.appsmith.com/static/media/icon.24905525921dd6f5ff46d0dd843b9e12.svg","topRow":6.0,"isSortable":true,"type":"TABLE_WIDGET_V2","inlineEditingSaveOption":"ROW_LEVEL","animateLoading":true,"dynamicBindingPathList":[{"key":"tableData"},{"key":"primaryColumns.customColumn9.boxShadow"},{"key":"primaryColumns.customColumn9.borderRadius"},{"key":"primaryColumns.customColumn9.menuColor"},{"key":"primaryColumns.customColumn8.computedValue"},{"key":"primaryColumns.customColumn7.computedValue"},{"key":"primaryColumns.customColumn6.computedValue"},{"key":"primaryColumns.customColumn5.computedValue"},{"key":"primaryColumns.customColumn2.computedValue"},{"key":"primaryColumns.customColumn1.textColor"},{"key":"primaryColumns.customColumn1.cellBackground"},{"key":"primaryColumns.customColumn1.computedValue"},{"key":"primaryColumns.instance.computedValue"},{"key":"isVisible"},{"key":"accentColor"},{"key":"borderRadius"},{"key":"boxShadow"}],"needsHeightForContent":true,"leftColumn":14.0,"delimiter":",","defaultSelectedRowIndex":0.0,"showInlineEditingOptionDropdown":true,"accentColor":"{{appsmith.theme.colors.primaryColor}}","isVisibleFilters":true,"isVisible":"{{appsmith.store.api_key && appsmith.store.api_url ? true : false}}","enableClientSideSearch":true,"version":2.0,"totalRecordsCount":0.0,"isLoading":false,"childStylesheet":{"button":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"menuButton":{"menuColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"iconButton":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"editActions":{"saveButtonColor":"{{appsmith.theme.colors.primaryColor}}","saveBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","discardButtonColor":"{{appsmith.theme.colors.primaryColor}}","discardBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}"}},"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","columnUpdatedAt":1.690746223636E12,"defaultSelectedRowIndices":[0.0],"mobileBottomRow":32.0,"widgetName":"TableInstances","defaultPageSize":0.0,"columnOrder":["instance","customColumn5","customColumn1","customColumn2","customColumn6","customColumn7","customColumn8","customColumn9"],"dynamicPropertyPathList":[{"key":"primaryColumns.customColumn1.cellBackground"},{"key":"isVisible"}],"displayName":"Table","bottomRow":42.0,"columnWidthMap":{"customColumn3":92.0,"customColumn2":340.0,"customColumn5":254.0,"customColumn9":60.0},"parentRowSpace":10.0,"hideCard":false,"mobileRightColumn":36.0,"parentColumnSpace":20.078125,"dynamicTriggerPathList":[{"key":"primaryColumns.customColumn9.menuItems.menuItemjfzsd8g6yr.onClick"},{"key":"primaryColumns.customColumn9.menuItems.menuItem4sqork5nmt.onClick"},{"key":"primaryColumns.customColumn9.menuItems.menuItemig6ua4ixjx.onClick"},{"key":"primaryColumns.customColumn9.menuItems.menuItemx9oyhys8cj.onClick"},{"key":"primaryColumns.customColumn9.menuItems.menuItemxk5jvvwwef.onClick"},{"key":"primaryColumns.customColumn9.menuItems.menuItem16ysonwzrq.onClick"},{"key":"primaryColumns.customColumn9.menuItems.menuItembtatfbml4y.onClick"}],"borderWidth":"1","primaryColumns":{"instance":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":0.0,"width":150.0,"originalId":"instance","id":"instance","alias":"instance","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":false,"label":"Instance","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{TableInstances.processedTableData.map((currentRow, currentIndex) => ( currentRow.instance.instanceName))}}","sticky":"","validation":{}},"customColumn1":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":1.0,"width":150.0,"originalId":"customColumn1","id":"customColumn1","alias":"Status","horizontalAlignment":"CENTER","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":true,"label":"Status","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{TableInstances.processedTableData.map((currentRow, currentIndex) => ( currentRow.instance.status))}}","sticky":"","validation":{},"buttonStyle":"rgb(3, 179, 101)","labelColor":"#FFFFFF","cellBackground":"{{TableInstances.processedTableData.map((currentRow, currentIndex) => ( currentRow.instance.status === \"open\" ? \"#499B51\" : currentRow.instance.status === \"close\" ? \"#DD524C\" : \"#2770FC\"))}}","textColor":"{{TableInstances.processedTableData.map((currentRow, currentIndex) => ( (appsmith.theme.colors.backgroundColor)))}}"},"customColumn2":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":2.0,"width":150.0,"originalId":"customColumn2","id":"customColumn2","alias":"Apikey","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":true,"label":"Apikey","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{TableInstances.processedTableData.map((currentRow, currentIndex) => ( currentRow.instance.apikey))}}","sticky":"","validation":{},"buttonStyle":"rgb(3, 179, 101)","labelColor":"#FFFFFF"},"customColumn5":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":5.0,"width":150.0,"originalId":"customColumn5","id":"customColumn5","alias":"Owner","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":true,"label":"Owner","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{TableInstances.processedTableData.map((currentRow, currentIndex) => ( currentRow.instance.owner))}}","sticky":"","validation":{},"buttonStyle":"rgb(3, 179, 101)","labelColor":"#FFFFFF"},"customColumn6":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":6.0,"width":150.0,"originalId":"customColumn6","id":"customColumn6","alias":"profilePictureUrl","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":false,"isDerived":true,"label":"profilePictureUrl","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{TableInstances.processedTableData.map((currentRow, currentIndex) => ( currentRow.instance.profilePictureUrl))}}","sticky":"","validation":{},"buttonStyle":"rgb(3, 179, 101)","labelColor":"#FFFFFF"},"customColumn7":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":7.0,"width":150.0,"originalId":"customColumn7","id":"customColumn7","alias":"profileName","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":false,"isDerived":true,"label":"profileName","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{TableInstances.processedTableData.map((currentRow, currentIndex) => ( currentRow.instance.profileName))}}","sticky":"","validation":{},"buttonStyle":"rgb(3, 179, 101)","labelColor":"#FFFFFF"},"customColumn8":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":8.0,"width":150.0,"originalId":"customColumn8","id":"customColumn8","alias":"profileStatus","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"text","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":false,"isDerived":true,"label":"profileStatus","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"{{TableInstances.processedTableData.map((currentRow, currentIndex) => ( currentRow.instance.profileStatus))}}","sticky":"","validation":{},"buttonStyle":"rgb(3, 179, 101)","labelColor":"#FFFFFF"},"customColumn9":{"allowCellWrapping":false,"allowSameOptionsInNewRow":true,"index":9.0,"width":150.0,"originalId":"customColumn9","id":"customColumn9","alias":"#","horizontalAlignment":"LEFT","verticalAlignment":"CENTER","columnType":"menuButton","textSize":"0.875rem","enableFilter":true,"enableSort":true,"isVisible":true,"isDisabled":false,"isCellEditable":false,"isEditable":false,"isCellVisible":true,"isDerived":true,"label":"#","isSaveVisible":true,"isDiscardVisible":true,"computedValue":"","sticky":"","validation":{},"buttonStyle":"rgb(3, 179, 101)","labelColor":"#FFFFFF","menuColor":"{{TableInstances.processedTableData.map((currentRow, currentIndex) => ( (appsmith.theme.colors.primaryColor)))}}","borderRadius":"{{TableInstances.processedTableData.map((currentRow, currentIndex) => ( (appsmith.theme.borderRadius.appBorderRadius)))}}","boxShadow":"{{TableInstances.processedTableData.map((currentRow, currentIndex) => ( \"none\"))}}","customAlias":"","menuItemsSource":"STATIC","menuButtonLabel":" ","menuButtoniconName":"chevron-down","menuItems":{"menuItemjfzsd8g6yr":{"id":"menuItemjfzsd8g6yr","index":0.0,"label":"Webhook","widgetId":"vygcejtdun","isDisabled":false,"isVisible":true,"onClick":"{{Find_Webhook.run({\n //\"key\": \"value\",\n});\nshowModal('ModalWebhook');}}"},"menuItem4sqork5nmt":{"id":"menuItem4sqork5nmt","index":1.0,"label":"Settings","widgetId":"0hw8oqpwcj","isDisabled":false,"isVisible":true,"onClick":"{{Find_Settings.run();\nshowModal('ModalSettings');}}"},"menuItemx9oyhys8cj":{"id":"menuItemx9oyhys8cj","index":2.0,"label":"Websocket","widgetId":"j75a4k6ecq","isDisabled":false,"isVisible":true,"onClick":"{{Find_Websocket.run();\nshowModal('ModalWebsocket');}}"},"menuItemxk5jvvwwef":{"id":"menuItemxk5jvvwwef","index":3.0,"label":"Rabbitmq","widgetId":"3u94ov6qst","isDisabled":false,"isVisible":true,"onClick":"{{Find_Rabbitmq.run();\nshowModal('ModalRabbitmq');}}"},"menuItemig6ua4ixjx":{"id":"menuItemig6ua4ixjx","index":4.0,"label":"Chatwoot","widgetId":"fuq5dtgbqc","isDisabled":false,"isVisible":true,"onClick":"{{Find_Chatwoot.run()\nshowModal('ModalChatwoot');}}"},"menuItem16ysonwzrq":{"id":"menuItem16ysonwzrq","index":5.0,"label":"Set Typebot","widgetId":"fi9nb2bace","isDisabled":false,"isVisible":true,"onClick":"{{Find_Typebot.run()\nshowModal('ModalTypebot');}}"},"menuItembtatfbml4y":{"id":"menuItembtatfbml4y","index":6.0,"label":"TypeBot Set Session Status","widgetId":"7f6mg653ra","isDisabled":false,"isVisible":true,"onClick":"{{showModal('ModalTypebotChangeSessionStatu');}}"}}}},"key":"e3yxhhyeel","canFreezeColumn":true,"isDeprecated":false,"rightColumn":63.0,"textSize":"0.875rem","widgetId":"uupm7enu8u","minWidth":450.0,"tableData":"{{fetch_Instances.data}}","label":"Data","searchKey":"","parentId":"0","renderMode":"CANVAS","mobileTopRow":4.0,"horizontalAlignment":"LEFT","isVisibleSearch":true,"responsiveBehavior":"fill","mobileLeftColumn":2.0,"isVisiblePagination":true,"verticalAlignment":"CENTER"},{"resetFormOnClick":false,"boxShadow":"none","mobileBottomRow":5.0,"widgetName":"BtnNewInstance","onClick":"{{showModal('ModalInstance');}}","buttonColor":"rgb(3, 179, 101)","dynamicPropertyPathList":[{"key":"isVisible"}],"displayName":"Button","iconSVG":"/static/media/icon.7beb9123fb53027d9d6b778cdfe4caed.svg","searchTags":["click","submit"],"topRow":1.0,"bottomRow":5.0,"parentRowSpace":10.0,"type":"BUTTON_WIDGET","hideCard":false,"mobileRightColumn":8.0,"animateLoading":true,"parentColumnSpace":11.828125,"dynamicTriggerPathList":[{"key":"onClick"}],"leftColumn":7.0,"dynamicBindingPathList":[{"key":"isVisible"},{"key":"borderRadius"}],"text":"New Instance","isDisabled":false,"key":"crzwqv3pdr","isDeprecated":false,"rightColumn":19.0,"isDefaultClickDisabled":true,"iconName":"add","widgetId":"84ei9q1ugm","minWidth":120.0,"isVisible":"{{appsmith.store.api_key && appsmith.store.api_url ? true : false}}","recaptchaType":"V3","version":1.0,"parentId":"0","renderMode":"CANVAS","isLoading":false,"mobileTopRow":1.0,"responsiveBehavior":"hug","disabledWhenInvalid":false,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":0.0,"buttonVariant":"PRIMARY","iconAlign":"left","placement":"CENTER"},{"boxShadow":"none","mobileBottomRow":74.0,"widgetName":"ModalQrcode","isCanvas":true,"displayName":"Modal","iconSVG":"/static/media/icon.d2ab7de0666eaef853cc2d330f86887b.svg","searchTags":["dialog","popup","notification"],"topRow":50.0,"bottomRow":500.0,"parentRowSpace":10.0,"type":"MODAL_WIDGET","hideCard":false,"shouldScrollContents":true,"mobileRightColumn":45.0,"animateLoading":true,"parentColumnSpace":11.828125,"leftColumn":21.0,"dynamicBindingPathList":[{"key":"borderRadius"}],"children":[{"mobileBottomRow":240.0,"widgetName":"Canvas1","displayName":"Canvas","topRow":0.0,"bottomRow":450.0,"parentRowSpace":1.0,"type":"CANVAS_WIDGET","canExtend":true,"hideCard":true,"shouldScrollContents":false,"minHeight":240.0,"mobileRightColumn":283.875,"parentColumnSpace":1.0,"leftColumn":0.0,"dynamicBindingPathList":[],"children":[{"boxShadow":"none","mobileBottomRow":52.0,"widgetName":"ImageQrcode","displayName":"Image","iconSVG":"https://appcdn.appsmith.com/static/media/icon.30c8cbd442cce232b01ba2d434c53a53.svg","topRow":6.0,"bottomRow":43.0,"parentRowSpace":10.0,"type":"IMAGE_WIDGET","hideCard":false,"mobileRightColumn":55.0,"animateLoading":true,"parentColumnSpace":20.078125,"dynamicTriggerPathList":[],"imageShape":"RECTANGLE","leftColumn":2.0,"dynamicBindingPathList":[{"key":"borderRadius"},{"key":"image"}],"defaultImage":"https://manualnegocioonline.com.br/downloads/evolution-api-favicon2.png","key":"4chlj9l432","image":"{{Connect.data.base64}}","isDeprecated":false,"rightColumn":61.0,"objectFit":"contain","widgetId":"27dpgapd7q","isVisible":true,"version":1.0,"parentId":"we6j3r2byy","renderMode":"CANVAS","isLoading":false,"mobileTopRow":40.0,"maxZoomLevel":1.0,"enableDownload":false,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":43.0,"enableRotation":false},{"boxShadow":"none","mobileBottomRow":4.0,"widgetName":"IconButton1","onClick":"{{closeModal('ModalQrcode');\nfetch_Instances.run()}}","buttonColor":"{{appsmith.theme.colors.primaryColor}}","displayName":"Icon button","iconSVG":"/static/media/icon.80fc7466c0d7181ec0271de7fda795ec.svg","searchTags":["click","submit"],"topRow":0.0,"bottomRow":4.0,"type":"ICON_BUTTON_WIDGET","hideCard":false,"mobileRightColumn":64.0,"animateLoading":true,"dynamicTriggerPathList":[{"key":"onClick"}],"leftColumn":58.0,"dynamicBindingPathList":[{"key":"buttonColor"},{"key":"borderRadius"}],"iconSize":24.0,"isDisabled":false,"key":"pezy0hb491","isDeprecated":false,"rightColumn":64.0,"iconName":"cross","widgetId":"i1dw369dch","minWidth":50.0,"isVisible":true,"version":1.0,"parentId":"we6j3r2byy","renderMode":"CANVAS","isLoading":false,"mobileTopRow":0.0,"responsiveBehavior":"hug","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":58.0,"buttonVariant":"TERTIARY"},{"mobileBottomRow":5.0,"widgetName":"Text1","displayName":"Text","iconSVG":"/static/media/icon.c3b6033f570046f8c6288d911333a827.svg","searchTags":["typography","paragraph","label"],"topRow":1.0,"bottomRow":5.0,"type":"TEXT_WIDGET","hideCard":false,"mobileRightColumn":41.0,"animateLoading":true,"overflow":"NONE","fontFamily":"{{appsmith.theme.fontFamily.appFont}}","dynamicTriggerPathList":[],"leftColumn":1.0,"dynamicBindingPathList":[{"key":"fontFamily"}],"shouldTruncate":false,"truncateButtonColor":"{{appsmith.theme.colors.primaryColor}}","text":"Qrcode","key":"9s8f10sepn","isDeprecated":false,"rightColumn":41.0,"textAlign":"LEFT","dynamicHeight":"AUTO_HEIGHT","widgetId":"mg2cqsi9fn","minWidth":450.0,"isVisible":true,"fontStyle":"BOLD","textColor":"#231F20","version":1.0,"parentId":"we6j3r2byy","renderMode":"CANVAS","isLoading":false,"mobileTopRow":1.0,"responsiveBehavior":"fill","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":1.0,"maxDynamicHeight":9000.0,"fontSize":"1.25rem","minDynamicHeight":4.0}],"isDisabled":false,"key":"e8r23nd8j4","isDeprecated":false,"rightColumn":283.875,"detachFromLayout":true,"widgetId":"we6j3r2byy","minWidth":450.0,"isVisible":true,"version":1.0,"parentId":"ljwryrjhy7","renderMode":"CANVAS","isLoading":false,"mobileTopRow":0.0,"responsiveBehavior":"fill","mobileLeftColumn":0.0,"flexLayers":[]}],"key":"g8xx6ocuvi","height":450.0,"isDeprecated":false,"rightColumn":45.0,"detachFromLayout":true,"dynamicHeight":"AUTO_HEIGHT","widgetId":"ljwryrjhy7","canOutsideClickClose":true,"canEscapeKeyClose":true,"version":2.0,"parentId":"0","renderMode":"CANVAS","isLoading":false,"mobileTopRow":50.0,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":21.0,"maxDynamicHeight":9000.0,"width":456.0,"minDynamicHeight":24.0},{"resetFormOnClick":false,"boxShadow":"none","mobileBottomRow":5.0,"widgetName":"BtnConfig","onClick":"{{showModal('ModalConfig');}}","buttonColor":"#2563eb","dynamicPropertyPathList":[],"displayName":"Button","iconSVG":"/static/media/icon.7beb9123fb53027d9d6b778cdfe4caed.svg","searchTags":["click","submit"],"topRow":1.0,"bottomRow":5.0,"parentRowSpace":10.0,"type":"BUTTON_WIDGET","hideCard":false,"mobileRightColumn":30.0,"animateLoading":true,"parentColumnSpace":11.828125,"dynamicTriggerPathList":[{"key":"onClick"}],"leftColumn":1.0,"dynamicBindingPathList":[{"key":"borderRadius"}],"text":"Access","isDisabled":false,"key":"crzwqv3pdr","isDeprecated":false,"rightColumn":7.0,"isDefaultClickDisabled":true,"iconName":"user","widgetId":"uegjpy37i6","minWidth":120.0,"isVisible":true,"recaptchaType":"V3","version":1.0,"parentId":"0","renderMode":"CANVAS","isLoading":false,"mobileTopRow":1.0,"responsiveBehavior":"hug","disabledWhenInvalid":false,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":14.0,"buttonVariant":"PRIMARY","iconAlign":"left","placement":"CENTER"},{"boxShadow":"none","mobileBottomRow":73.0,"widgetName":"ModalConfig","isCanvas":true,"displayName":"Modal","iconSVG":"/static/media/icon.d2ab7de0666eaef853cc2d330f86887b.svg","searchTags":["dialog","popup","notification"],"topRow":49.0,"bottomRow":30.0,"parentRowSpace":10.0,"type":"MODAL_WIDGET","hideCard":false,"shouldScrollContents":true,"mobileRightColumn":25.0,"minHeight":300.0,"animateLoading":true,"parentColumnSpace":11.75,"leftColumn":1.0,"dynamicBindingPathList":[{"key":"borderRadius"}],"children":[{"mobileBottomRow":240.0,"widgetName":"Canvas2","displayName":"Canvas","topRow":0.0,"bottomRow":300.0,"parentRowSpace":1.0,"type":"CANVAS_WIDGET","canExtend":true,"hideCard":true,"shouldScrollContents":false,"minHeight":300.0,"mobileRightColumn":282.0,"parentColumnSpace":1.0,"leftColumn":0.0,"dynamicBindingPathList":[],"children":[{"boxShadow":"none","mobileBottomRow":84.0,"borderColor":"#E0DEDE","widgetName":"FormConfig","isCanvas":true,"displayName":"Form","iconSVG":"/static/media/icon.5d6d2ac5cb1aa68bcd9b14f11c56b44a.svg","searchTags":["group"],"topRow":0.0,"bottomRow":28.0,"parentRowSpace":10.0,"type":"FORM_WIDGET","hideCard":false,"shouldScrollContents":true,"mobileRightColumn":25.0,"animateLoading":true,"parentColumnSpace":11.828125,"dynamicTriggerPathList":[],"leftColumn":1.0,"dynamicBindingPathList":[],"children":[{"mobileBottomRow":400.0,"widgetName":"Canvas2Copy","displayName":"Canvas","topRow":0.0,"bottomRow":280.0,"parentRowSpace":1.0,"type":"CANVAS_WIDGET","canExtend":false,"hideCard":true,"minHeight":400.0,"mobileRightColumn":283.875,"parentColumnSpace":1.0,"leftColumn":0.0,"dynamicBindingPathList":[],"children":[{"mobileBottomRow":5.0,"widgetName":"Text2","displayName":"Text","iconSVG":"/static/media/icon.c3b6033f570046f8c6288d911333a827.svg","searchTags":["typography","paragraph","label"],"topRow":1.0,"bottomRow":5.0,"type":"TEXT_WIDGET","hideCard":false,"mobileRightColumn":25.5,"animateLoading":true,"overflow":"NONE","fontFamily":"{{appsmith.theme.fontFamily.appFont}}","dynamicTriggerPathList":[],"leftColumn":1.5,"dynamicBindingPathList":[{"key":"fontFamily"}],"shouldTruncate":false,"truncateButtonColor":"{{appsmith.theme.colors.primaryColor}}","text":"Access Credentials","key":"9s8f10sepn","isDeprecated":false,"rightColumn":25.5,"textAlign":"LEFT","dynamicHeight":"AUTO_HEIGHT","widgetId":"tps5rw2lk9","minWidth":450.0,"isVisible":true,"fontStyle":"BOLD","textColor":"#231F20","version":1.0,"parentId":"lrtvcpswru","renderMode":"CANVAS","isLoading":false,"mobileTopRow":1.0,"responsiveBehavior":"fill","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":1.5,"maxDynamicHeight":9000.0,"fontSize":"1.25rem","minDynamicHeight":4.0},{"resetFormOnClick":true,"boxShadow":"none","mobileBottomRow":37.0,"widgetName":"Button1","onClick":"{{storeValue('api_url', FormConfig.data.InputApiUrl);\nstoreValue('api_key', FormConfig.data.InputGlobalApiKey);\nfetch_Instances.run().then(() => {\n showAlert('successful login', 'success');\n}).catch(() => {\n showAlert('Could not load instances', 'error');\n});\ncloseModal('ModalConfig').then(() => {});}}","buttonColor":"{{appsmith.theme.colors.primaryColor}}","dynamicPropertyPathList":[{"key":"isDisabled"}],"displayName":"Button","iconSVG":"/static/media/icon.7beb9123fb53027d9d6b778cdfe4caed.svg","searchTags":["click","submit"],"topRow":22.0,"bottomRow":26.0,"type":"BUTTON_WIDGET","hideCard":false,"mobileRightColumn":62.0,"animateLoading":true,"dynamicTriggerPathList":[{"key":"onClick"}],"leftColumn":51.0,"dynamicBindingPathList":[{"key":"buttonColor"},{"key":"borderRadius"}],"text":"Login","isDisabled":"","key":"crzwqv3pdr","isDeprecated":false,"rightColumn":63.0,"isDefaultClickDisabled":true,"iconName":"log-in","widgetId":"gzxvnsxk0y","minWidth":120.0,"isVisible":true,"recaptchaType":"V3","version":1.0,"parentId":"lrtvcpswru","renderMode":"CANVAS","isLoading":false,"mobileTopRow":33.0,"responsiveBehavior":"hug","disabledWhenInvalid":true,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":46.0,"buttonVariant":"PRIMARY","iconAlign":"left","placement":"CENTER"},{"resetFormOnClick":true,"boxShadow":"none","mobileBottomRow":37.0,"widgetName":"Button1Copy","onClick":"{{removeValue('api_url');\nremoveValue('api_key').then(() => {\n showAlert('successful logout', 'success');\n});}}","buttonColor":"#dc2626","dynamicPropertyPathList":[{"key":"isDisabled"}],"displayName":"Button","iconSVG":"/static/media/icon.7beb9123fb53027d9d6b778cdfe4caed.svg","searchTags":["click","submit"],"topRow":21.0,"bottomRow":25.0,"type":"BUTTON_WIDGET","hideCard":false,"mobileRightColumn":62.0,"animateLoading":true,"dynamicTriggerPathList":[{"key":"onClick"}],"leftColumn":2.0,"dynamicBindingPathList":[{"key":"isDisabled"},{"key":"borderRadius"}],"text":"Logout","isDisabled":"{{!appsmith.store.api_key && !appsmith.store.api_url ? true : false}}","key":"crzwqv3pdr","isDeprecated":false,"rightColumn":14.0,"isDefaultClickDisabled":true,"iconName":"log-out","widgetId":"f2i8tsbgx1","minWidth":120.0,"isVisible":true,"recaptchaType":"V3","version":1.0,"parentId":"lrtvcpswru","renderMode":"CANVAS","isLoading":false,"mobileTopRow":33.0,"responsiveBehavior":"hug","disabledWhenInvalid":false,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":46.0,"buttonVariant":"PRIMARY","iconAlign":"left","placement":"CENTER"},{"boxShadow":"none","iconSVG":"/static/media/icon.d0ce957b6c4640f8a7418ce846ee200e.svg","topRow":6.0,"labelWidth":5.0,"type":"INPUT_WIDGET_V2","animateLoading":true,"resetOnSubmit":true,"leftColumn":2.0,"dynamicBindingPathList":[{"key":"defaultText"},{"key":"accentColor"},{"key":"borderRadius"}],"labelStyle":"","inputType":"TEXT","placeholderText":"","isDisabled":false,"isRequired":true,"dynamicHeight":"FIXED","accentColor":"{{appsmith.theme.colors.primaryColor}}","showStepArrows":false,"isVisible":true,"version":2.0,"isLoading":false,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileBottomRow":13.0,"widgetName":"InputApiUrl","displayName":"Input","searchTags":["form","text input","number","textarea"],"bottomRow":13.0,"parentRowSpace":10.0,"autoFocus":false,"hideCard":false,"mobileRightColumn":22.0,"parentColumnSpace":5.047119140625,"dynamicTriggerPathList":[],"labelPosition":"Top","key":"r1hfat3ouf","labelTextSize":"0.875rem","isDeprecated":false,"rightColumn":63.0,"widgetId":"spgryrb5ao","minWidth":450.0,"label":"API URL","parentId":"lrtvcpswru","labelAlignment":"left","renderMode":"CANVAS","mobileTopRow":6.0,"responsiveBehavior":"fill","mobileLeftColumn":2.0,"maxDynamicHeight":9000.0,"isSpellCheck":false,"iconAlign":"left","defaultText":"{{appsmith.store.api_url || ''}}","minDynamicHeight":4.0},{"boxShadow":"none","iconSVG":"/static/media/icon.d0ce957b6c4640f8a7418ce846ee200e.svg","topRow":14.0,"labelWidth":5.0,"type":"INPUT_WIDGET_V2","animateLoading":true,"resetOnSubmit":true,"leftColumn":2.0,"dynamicBindingPathList":[{"key":"defaultText"},{"key":"accentColor"},{"key":"borderRadius"}],"labelStyle":"","inputType":"PASSWORD","isDisabled":false,"isRequired":true,"dynamicHeight":"FIXED","accentColor":"{{appsmith.theme.colors.primaryColor}}","showStepArrows":false,"isVisible":true,"version":2.0,"isLoading":false,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileBottomRow":13.0,"widgetName":"InputGlobalApiKey","displayName":"Input","searchTags":["form","text input","number","textarea"],"bottomRow":21.0,"parentRowSpace":10.0,"autoFocus":false,"hideCard":false,"mobileRightColumn":22.0,"parentColumnSpace":5.047119140625,"dynamicTriggerPathList":[],"labelPosition":"Top","key":"r1hfat3ouf","labelTextSize":"0.875rem","isDeprecated":false,"rightColumn":63.0,"widgetId":"v2vedr13py","minWidth":450.0,"label":"GLOBAL API KEY","parentId":"lrtvcpswru","labelAlignment":"left","renderMode":"CANVAS","mobileTopRow":6.0,"responsiveBehavior":"fill","mobileLeftColumn":2.0,"maxDynamicHeight":9000.0,"shouldAllowAutofill":true,"iconAlign":"left","defaultText":"{{appsmith.store.api_key || ''}}","minDynamicHeight":4.0},{"boxShadow":"none","mobileBottomRow":4.0,"widgetName":"IconButton2","onClick":"{{closeModal('ModalConfig');}}","buttonColor":"{{appsmith.theme.colors.primaryColor}}","displayName":"Icon button","iconSVG":"/static/media/icon.80fc7466c0d7181ec0271de7fda795ec.svg","searchTags":["click","submit"],"topRow":0.0,"bottomRow":4.0,"parentRowSpace":10.0,"type":"ICON_BUTTON_WIDGET","hideCard":false,"mobileRightColumn":64.0,"animateLoading":true,"parentColumnSpace":9.072265625,"dynamicTriggerPathList":[{"key":"onClick"}],"leftColumn":60.0,"dynamicBindingPathList":[{"key":"buttonColor"},{"key":"borderRadius"}],"isDisabled":false,"key":"pezy0hb491","isDeprecated":false,"rightColumn":64.0,"iconName":"cross","widgetId":"oaouelmhi1","minWidth":50.0,"isVisible":true,"version":1.0,"parentId":"lrtvcpswru","renderMode":"CANVAS","isLoading":false,"mobileTopRow":0.0,"responsiveBehavior":"hug","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":60.0,"buttonVariant":"TERTIARY"}],"key":"e8r23nd8j4","isDeprecated":false,"rightColumn":283.875,"detachFromLayout":true,"widgetId":"lrtvcpswru","containerStyle":"none","minWidth":450.0,"isVisible":true,"version":1.0,"parentId":"h97rbttd5c","renderMode":"CANVAS","isLoading":false,"mobileTopRow":0.0,"responsiveBehavior":"fill","mobileLeftColumn":0.0,"flexLayers":[]}],"borderWidth":"0","positioning":"fixed","key":"dtzd07zsya","backgroundColor":"#FFFFFF","isDeprecated":false,"rightColumn":63.0,"dynamicHeight":"AUTO_HEIGHT","widgetId":"h97rbttd5c","minWidth":450.0,"isVisible":true,"parentId":"es5gsctogb","renderMode":"CANVAS","isLoading":false,"mobileTopRow":44.0,"responsiveBehavior":"fill","originalTopRow":0.0,"borderRadius":"0.375rem","mobileLeftColumn":1.0,"maxDynamicHeight":9000.0,"originalBottomRow":28.0,"minDynamicHeight":10.0}],"isDisabled":false,"key":"e8r23nd8j4","isDeprecated":false,"rightColumn":282.0,"detachFromLayout":true,"widgetId":"es5gsctogb","minWidth":450.0,"isVisible":true,"version":1.0,"parentId":"gneh33z88k","renderMode":"CANVAS","isLoading":false,"mobileTopRow":0.0,"responsiveBehavior":"fill","mobileLeftColumn":0.0,"flexLayers":[]}],"key":"g8xx6ocuvi","height":300.0,"isDeprecated":false,"rightColumn":25.0,"detachFromLayout":true,"dynamicHeight":"AUTO_HEIGHT","widgetId":"gneh33z88k","canOutsideClickClose":true,"canEscapeKeyClose":true,"version":2.0,"parentId":"0","renderMode":"CANVAS","isLoading":false,"mobileTopRow":49.0,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":1.0,"maxDynamicHeight":9000.0,"width":632.0,"minDynamicHeight":24.0},{"boxShadow":"none","mobileBottomRow":66.0,"widgetName":"ModalInstance","isCanvas":true,"displayName":"Modal","iconSVG":"/static/media/icon.d2ab7de0666eaef853cc2d330f86887b.svg","searchTags":["dialog","popup","notification"],"topRow":42.0,"bottomRow":1892.0,"parentRowSpace":10.0,"type":"MODAL_WIDGET","hideCard":false,"shouldScrollContents":true,"mobileRightColumn":37.0,"minHeight":1850.0,"animateLoading":true,"parentColumnSpace":11.828125,"leftColumn":13.0,"dynamicBindingPathList":[{"key":"borderRadius"}],"children":[{"mobileBottomRow":240.0,"widgetName":"Canvas3","displayName":"Canvas","topRow":0.0,"bottomRow":1850.0,"parentRowSpace":1.0,"type":"CANVAS_WIDGET","canExtend":true,"hideCard":true,"shouldScrollContents":false,"minHeight":1140.0,"mobileRightColumn":283.875,"parentColumnSpace":1.0,"leftColumn":0.0,"dynamicBindingPathList":[],"children":[{"boxShadow":"none","mobileBottomRow":4.0,"widgetName":"IconButton3Copy","onClick":"{{closeModal('ModalInstance');}}","buttonColor":"{{appsmith.theme.colors.primaryColor}}","displayName":"Icon button","iconSVG":"/static/media/icon.80fc7466c0d7181ec0271de7fda795ec.svg","searchTags":["click","submit"],"topRow":0.0,"bottomRow":4.0,"type":"ICON_BUTTON_WIDGET","hideCard":false,"mobileRightColumn":64.0,"animateLoading":true,"dynamicTriggerPathList":[{"key":"onClick"}],"leftColumn":57.0,"dynamicBindingPathList":[{"key":"buttonColor"},{"key":"borderRadius"}],"iconSize":24.0,"isDisabled":false,"key":"mr6bto7c8j","isDeprecated":false,"rightColumn":63.0,"iconName":"cross","widgetId":"xofakp4har","minWidth":50.0,"isVisible":true,"version":1.0,"parentId":"esgwuzqcwt","renderMode":"CANVAS","isLoading":false,"mobileTopRow":0.0,"responsiveBehavior":"hug","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":58.0,"buttonVariant":"TERTIARY"},{"boxShadow":"none","borderColor":"#E0DEDE","iconSVG":"/static/media/icon.efac588608711d232f1c6c8a2144d2dd.svg","onSubmit":"{{Create_Instance.run().then(() => {\n showAlert('Instance created successfully', 'success');\n}).catch(() => {\n showAlert('Error creating instance', 'error');\n});\nfetch_Instances.run();\ncloseModal('ModalInstance');}}","topRow":4.0,"type":"JSON_FORM_WIDGET","animateLoading":true,"leftColumn":0.0,"dynamicBindingPathList":[{"key":"borderRadius"},{"key":"resetButtonStyles.buttonColor"},{"key":"schema.__root_schema__.defaultValue"},{"key":"schema.__root_schema__.borderRadius"},{"key":"schema.__root_schema__.children.webhook.defaultValue"},{"key":"schema.__root_schema__.children.webhook.borderRadius"},{"key":"schema.__root_schema__.cellBorderRadius"},{"key":"schema.__root_schema__.children.instance.defaultValue"},{"key":"schema.__root_schema__.children.instance.borderRadius"},{"key":"schema.__root_schema__.children.instance.cellBorderRadius"},{"key":"schema.__root_schema__.children.instance.children.instanceName.defaultValue"},{"key":"schema.__root_schema__.children.instance.children.instanceName.accentColor"},{"key":"schema.__root_schema__.children.instance.children.instanceName.borderRadius"},{"key":"schema.__root_schema__.children.instance.children.token.defaultValue"},{"key":"schema.__root_schema__.children.instance.children.token.accentColor"},{"key":"schema.__root_schema__.children.instance.children.token.borderRadius"},{"key":"schema.__root_schema__.children.webhook.cellBorderRadius"},{"key":"schema.__root_schema__.children.webhook.children.webhook.defaultValue"},{"key":"schema.__root_schema__.children.webhook.children.webhook.accentColor"},{"key":"schema.__root_schema__.children.webhook.children.webhook.borderRadius"},{"key":"schema.__root_schema__.children.webhook.children.events.defaultValue"},{"key":"schema.__root_schema__.children.webhook.children.events.accentColor"},{"key":"schema.__root_schema__.children.webhook.children.events.borderRadius"},{"key":"schema.__root_schema__.children.webhook.children.webhook_by_events.defaultValue"},{"key":"schema.__root_schema__.children.webhook.children.webhook_by_events.accentColor"},{"key":"schema.__root_schema__.children.settings.defaultValue"},{"key":"schema.__root_schema__.children.settings.borderRadius"},{"key":"schema.__root_schema__.children.settings.cellBorderRadius"},{"key":"schema.__root_schema__.children.settings.children.reject_call.defaultValue"},{"key":"schema.__root_schema__.children.settings.children.reject_call.accentColor"},{"key":"schema.__root_schema__.children.settings.children.msg_call.defaultValue"},{"key":"schema.__root_schema__.children.settings.children.msg_call.accentColor"},{"key":"schema.__root_schema__.children.settings.children.msg_call.borderRadius"},{"key":"schema.__root_schema__.children.settings.children.groups_ignore.defaultValue"},{"key":"schema.__root_schema__.children.settings.children.groups_ignore.accentColor"},{"key":"schema.__root_schema__.children.settings.children.always_online.defaultValue"},{"key":"schema.__root_schema__.children.settings.children.always_online.accentColor"},{"key":"schema.__root_schema__.children.settings.children.read_messages.defaultValue"},{"key":"schema.__root_schema__.children.settings.children.read_messages.accentColor"},{"key":"schema.__root_schema__.children.settings.children.read_status.defaultValue"},{"key":"schema.__root_schema__.children.settings.children.read_status.accentColor"},{"key":"schema.__root_schema__.children.chatwoot.defaultValue"},{"key":"schema.__root_schema__.children.chatwoot.borderRadius"},{"key":"schema.__root_schema__.children.chatwoot.cellBorderRadius"},{"key":"schema.__root_schema__.children.chatwoot.children.chatwoot_account_id.defaultValue"},{"key":"schema.__root_schema__.children.chatwoot.children.chatwoot_account_id.accentColor"},{"key":"schema.__root_schema__.children.chatwoot.children.chatwoot_account_id.borderRadius"},{"key":"schema.__root_schema__.children.chatwoot.children.chatwoot_token.defaultValue"},{"key":"schema.__root_schema__.children.chatwoot.children.chatwoot_token.accentColor"},{"key":"schema.__root_schema__.children.chatwoot.children.chatwoot_token.borderRadius"},{"key":"schema.__root_schema__.children.chatwoot.children.chatwoot_url.defaultValue"},{"key":"schema.__root_schema__.children.chatwoot.children.chatwoot_url.accentColor"},{"key":"schema.__root_schema__.children.chatwoot.children.chatwoot_url.borderRadius"},{"key":"schema.__root_schema__.children.chatwoot.children.chatwoot_sign_msg.defaultValue"},{"key":"schema.__root_schema__.children.chatwoot.children.chatwoot_sign_msg.accentColor"},{"key":"schema.__root_schema__.children.chatwoot.children.chatwoot_reopen_conversation.defaultValue"},{"key":"schema.__root_schema__.children.chatwoot.children.chatwoot_reopen_conversation.accentColor"},{"key":"schema.__root_schema__.children.chatwoot.children.chatwoot_conversation_pending.defaultValue"},{"key":"schema.__root_schema__.children.chatwoot.children.chatwoot_conversation_pending.accentColor"},{"key":"schema.__root_schema__.children.instance.children.qrcode.defaultValue"},{"key":"schema.__root_schema__.children.instance.children.qrcode.accentColor"},{"key":"schema.__root_schema__.children.websocket.defaultValue"},{"key":"schema.__root_schema__.children.websocket.borderRadius"},{"key":"schema.__root_schema__.children.websocket.cellBorderRadius"},{"key":"schema.__root_schema__.children.websocket.children.websocket_enabled.defaultValue"},{"key":"schema.__root_schema__.children.websocket.children.websocket_enabled.accentColor"},{"key":"schema.__root_schema__.children.websocket.children.websocket_events.defaultValue"},{"key":"schema.__root_schema__.children.websocket.children.websocket_events.accentColor"},{"key":"schema.__root_schema__.children.websocket.children.websocket_events.borderRadius"},{"key":"schema.__root_schema__.children.rabbitmq.defaultValue"},{"key":"schema.__root_schema__.children.rabbitmq.borderRadius"},{"key":"schema.__root_schema__.children.rabbitmq.cellBorderRadius"},{"key":"schema.__root_schema__.children.rabbitmq.children.rabbitmq_enabled.defaultValue"},{"key":"schema.__root_schema__.children.rabbitmq.children.rabbitmq_enabled.accentColor"},{"key":"schema.__root_schema__.children.rabbitmq.children.rabbitmq_events.defaultValue"},{"key":"schema.__root_schema__.children.rabbitmq.children.rabbitmq_events.accentColor"},{"key":"schema.__root_schema__.children.rabbitmq.children.rabbitmq_events.borderRadius"}],"showReset":true,"dynamicHeight":"AUTO_HEIGHT","autoGenerateForm":true,"resetButtonStyles":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","buttonVariant":"SECONDARY","iconAlign":"left"},"isVisible":true,"version":1.0,"isLoading":false,"submitButtonLabel":"Create","childStylesheet":{"ARRAY":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","cellBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","cellBoxShadow":"none"},"OBJECT":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","cellBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","cellBoxShadow":"none"},"CHECKBOX":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}"},"CURRENCY_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"DATEPICKER":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"EMAIL_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTISELECT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTILINE_TEXT_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"NUMBER_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PASSWORD_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PHONE_NUMBER_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"RADIO_GROUP":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"SELECT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"SWITCH":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"TEXT_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"}},"disabledWhenInvalid":true,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","originalBottomRow":183.0,"useSourceData":false,"schema":{"__root_schema__":{"children":{"webhook":{"children":{"webhook":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.webhook.webhook))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Text Input","sourceData":"","isCustomField":false,"accessor":"webhook","identifier":"webhook","position":0.0,"originalIdentifier":"webhook","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Webhook"},"events":{"children":{},"dataType":"array","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.webhook.events))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Multiselect","sourceData":["APPLICATION_STARTUP","QRCODE_UPDATED","MESSAGES_SET","MESSAGES_UPSERT","MESSAGES_UPDATE","MESSAGES_DELETE","SEND_MESSAGE","CONTACTS_SET","CONTACTS_UPSERT","CONTACTS_UPDATE","PRESENCE_UPDATE","CHATS_SET","CHATS_UPSERT","CHATS_UPDATE","CHATS_DELETE","GROUPS_UPSERT","GROUP_UPDATE","GROUP_PARTICIPANTS_UPDATE","CONNECTION_UPDATE","CALL","NEW_JWT_TOKEN"],"isCustomField":false,"accessor":"events","identifier":"events","position":2.0,"originalIdentifier":"events","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","isDisabled":false,"isFilterable":false,"isRequired":false,"isVisible":true,"label":"Events","labelTextSize":"0.875rem","serverSideFiltering":false,"options":"[\n {\n \"label\": \"APPLICATION_STARTUP\",\n \"value\": \"APPLICATION_STARTUP\"\n },\n {\n \"label\": \"QRCODE_UPDATED\",\n \"value\": \"QRCODE_UPDATED\"\n },\n {\n \"label\": \"MESSAGES_SET\",\n \"value\": \"MESSAGES_SET\"\n },\n {\n \"label\": \"MESSAGES_UPSERT\",\n \"value\": \"MESSAGES_UPSERT\"\n },\n {\n \"label\": \"MESSAGES_UPDATE\",\n \"value\": \"MESSAGES_UPDATE\"\n },\n {\n \"label\": \"MESSAGES_DELETE\",\n \"value\": \"MESSAGES_DELETE\"\n },\n {\n \"label\": \"SEND_MESSAGE\",\n \"value\": \"SEND_MESSAGE\"\n },\n {\n \"label\": \"CONTACTS_SET\",\n \"value\": \"CONTACTS_SET\"\n },\n {\n \"label\": \"CONTACTS_UPSERT\",\n \"value\": \"CONTACTS_UPSERT\"\n },\n {\n \"label\": \"CONTACTS_UPDATE\",\n \"value\": \"CONTACTS_UPDATE\"\n },\n {\n \"label\": \"PRESENCE_UPDATE\",\n \"value\": \"PRESENCE_UPDATE\"\n },\n {\n \"label\": \"CHATS_SET\",\n \"value\": \"CHATS_SET\"\n },\n {\n \"label\": \"CHATS_UPSERT\",\n \"value\": \"CHATS_UPSERT\"\n },\n {\n \"label\": \"CHATS_UPDATE\",\n \"value\": \"CHATS_UPDATE\"\n },\n {\n \"label\": \"CHATS_DELETE\",\n \"value\": \"CHATS_DELETE\"\n },\n {\n \"label\": \"GROUPS_UPSERT\",\n \"value\": \"GROUPS_UPSERT\"\n },\n {\n \"label\": \"GROUP_UPDATE\",\n \"value\": \"GROUP_UPDATE\"\n },\n {\n \"label\": \"GROUP_PARTICIPANTS_UPDATE\",\n \"value\": \"GROUP_PARTICIPANTS_UPDATE\"\n },\n {\n \"label\": \"CONNECTION_UPDATE\",\n \"value\": \"CONNECTION_UPDATE\"\n },\n {\n \"label\": \"CALL\",\n \"value\": \"CALL\"\n },\n {\n \"label\": \"NEW_JWT_TOKEN\",\n \"value\": \"NEW_JWT_TOKEN\"\n }\n]"},"webhook_by_events":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.webhook.webhook_by_events))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Switch","sourceData":false,"isCustomField":false,"accessor":"webhook_by_events","identifier":"webhook_by_events","position":2.0,"originalIdentifier":"webhook_by_events","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Webhook By Events"}},"dataType":"object","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.webhook))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Object","sourceData":{},"isCustomField":false,"accessor":"webhook","identifier":"webhook","position":1.0,"originalIdentifier":"webhook","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","cellBorderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","cellBoxShadow":"none","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"1rem","label":"Webhook","labelStyle":"BOLD"},"instance":{"children":{"instanceName":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.instance.instanceName))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Text Input","sourceData":"","isCustomField":false,"accessor":"instanceName","identifier":"instanceName","position":0.0,"originalIdentifier":"instanceName","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Instance Name"},"token":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.instance.token))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Text Input","sourceData":"","isCustomField":false,"accessor":"token","identifier":"token","position":1.0,"originalIdentifier":"token","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Token"},"qrcode":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.instance.qrcode))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Switch","sourceData":false,"isCustomField":false,"accessor":"qrcode","identifier":"qrcode","position":2.0,"originalIdentifier":"qrcode","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Qrcode"}},"dataType":"object","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.instance))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Object","sourceData":{},"isCustomField":false,"accessor":"instance","identifier":"instance","position":0.0,"originalIdentifier":"instance","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","cellBorderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","cellBoxShadow":"none","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"1rem","label":"Instance","labelStyle":"BOLD"},"settings":{"children":{"reject_call":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.settings.reject_call))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Switch","sourceData":false,"isCustomField":false,"accessor":"reject_call","identifier":"reject_call","position":0.0,"originalIdentifier":"reject_call","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Reject Call"},"msg_call":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.settings.msg_call))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Text Input","sourceData":"","isCustomField":false,"accessor":"msg_call","identifier":"msg_call","position":1.0,"originalIdentifier":"msg_call","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Msg Call"},"groups_ignore":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.settings.groups_ignore))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Switch","sourceData":false,"isCustomField":false,"accessor":"groups_ignore","identifier":"groups_ignore","position":2.0,"originalIdentifier":"groups_ignore","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Groups Ignore"},"always_online":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.settings.always_online))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Switch","sourceData":false,"isCustomField":false,"accessor":"always_online","identifier":"always_online","position":3.0,"originalIdentifier":"always_online","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Always Online"},"read_messages":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.settings.read_messages))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Switch","sourceData":false,"isCustomField":false,"accessor":"read_messages","identifier":"read_messages","position":4.0,"originalIdentifier":"read_messages","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Read Messages"},"read_status":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.settings.read_status))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Switch","sourceData":false,"isCustomField":false,"accessor":"read_status","identifier":"read_status","position":5.0,"originalIdentifier":"read_status","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Read Status"}},"dataType":"object","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.settings))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Object","sourceData":{},"isCustomField":false,"accessor":"settings","identifier":"settings","position":2.0,"originalIdentifier":"settings","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","cellBorderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","cellBoxShadow":"none","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"1rem","label":"Settings","labelStyle":"BOLD"},"chatwoot":{"children":{"chatwoot_account_id":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.chatwoot.chatwoot_account_id))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Text Input","sourceData":"","isCustomField":false,"accessor":"chatwoot_account_id","identifier":"chatwoot_account_id","position":0.0,"originalIdentifier":"chatwoot_account_id","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Chatwoot Account Id"},"chatwoot_token":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.chatwoot.chatwoot_token))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Password Input","sourceData":"","isCustomField":false,"accessor":"chatwoot_token","identifier":"chatwoot_token","position":1.0,"originalIdentifier":"chatwoot_token","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Chatwoot Token","shouldAllowAutofill":true},"chatwoot_url":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.chatwoot.chatwoot_url))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Text Input","sourceData":"","isCustomField":false,"accessor":"chatwoot_url","identifier":"chatwoot_url","position":2.0,"originalIdentifier":"chatwoot_url","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Chatwoot Url"},"chatwoot_sign_msg":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.chatwoot.chatwoot_sign_msg))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Switch","sourceData":false,"isCustomField":false,"accessor":"chatwoot_sign_msg","identifier":"chatwoot_sign_msg","position":3.0,"originalIdentifier":"chatwoot_sign_msg","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Chatwoot Sign Msg"},"chatwoot_reopen_conversation":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.chatwoot.chatwoot_reopen_conversation))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Switch","sourceData":false,"isCustomField":false,"accessor":"chatwoot_reopen_conversation","identifier":"chatwoot_reopen_conversation","position":4.0,"originalIdentifier":"chatwoot_reopen_conversation","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Chatwoot Reopen Conversation"},"chatwoot_conversation_pending":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.chatwoot.chatwoot_conversation_pending))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Switch","sourceData":false,"isCustomField":false,"accessor":"chatwoot_conversation_pending","identifier":"chatwoot_conversation_pending","position":5.0,"originalIdentifier":"chatwoot_conversation_pending","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Chatwoot Conversation Pending"}},"dataType":"object","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.chatwoot))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Object","sourceData":{},"isCustomField":false,"accessor":"chatwoot","identifier":"chatwoot","position":5.0,"originalIdentifier":"chatwoot","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","cellBorderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","cellBoxShadow":"none","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"1rem","label":"Chatwoot","labelStyle":"BOLD"},"websocket":{"children":{"websocket_enabled":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.websocket.websocket_enabled))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Switch","sourceData":false,"isCustomField":false,"accessor":"websocket_enabled","identifier":"websocket_enabled","position":0.0,"originalIdentifier":"websocket_enabled","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Websocket Enabled"},"websocket_events":{"children":{},"dataType":"array","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.websocket.websocket_events))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Multiselect","sourceData":["APPLICATION_STARTUP","QRCODE_UPDATED","MESSAGES_SET","MESSAGES_UPSERT","MESSAGES_UPDATE","MESSAGES_DELETE","SEND_MESSAGE","CONTACTS_SET","CONTACTS_UPSERT","CONTACTS_UPDATE","PRESENCE_UPDATE","CHATS_SET","CHATS_UPSERT","CHATS_UPDATE","CHATS_DELETE","GROUPS_UPSERT","GROUP_UPDATE","GROUP_PARTICIPANTS_UPDATE","CONNECTION_UPDATE","CALL","NEW_JWT_TOKEN"],"isCustomField":false,"accessor":"websocket_events","identifier":"websocket_events","position":1.0,"originalIdentifier":"websocket_events","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","isDisabled":false,"isFilterable":false,"isRequired":false,"isVisible":true,"label":"Websocket Events","labelTextSize":"0.875rem","serverSideFiltering":false,"options":[{"label":"Blue","value":"BLUE"},{"label":"Green","value":"GREEN"},{"label":"Red","value":"RED"}]}},"dataType":"object","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.websocket))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Object","sourceData":{},"isCustomField":false,"accessor":"websocket","identifier":"websocket","position":3.0,"originalIdentifier":"websocket","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","cellBorderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","cellBoxShadow":"none","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"1rem","label":"Websocket","labelStyle":"BOLD"},"rabbitmq":{"children":{"rabbitmq_enabled":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.rabbitmq.rabbitmq_enabled))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Switch","sourceData":false,"isCustomField":false,"accessor":"rabbitmq_enabled","identifier":"rabbitmq_enabled","position":1.0,"originalIdentifier":"rabbitmq_enabled","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Rabbitmq Enabled"},"rabbitmq_events":{"children":{},"dataType":"array","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.rabbitmq.rabbitmq_events))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Multiselect","sourceData":["APPLICATION_STARTUP","QRCODE_UPDATED","MESSAGES_SET","MESSAGES_UPSERT","MESSAGES_UPDATE","MESSAGES_DELETE","SEND_MESSAGE","CONTACTS_SET","CONTACTS_UPSERT","CONTACTS_UPDATE","PRESENCE_UPDATE","CHATS_SET","CHATS_UPSERT","CHATS_UPDATE","CHATS_DELETE","GROUPS_UPSERT","GROUP_UPDATE","GROUP_PARTICIPANTS_UPDATE","CONNECTION_UPDATE","CALL","NEW_JWT_TOKEN"],"isCustomField":false,"accessor":"rabbitmq_events","identifier":"rabbitmq_events","position":1.0,"originalIdentifier":"rabbitmq_events","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","isDisabled":false,"isFilterable":false,"isRequired":false,"isVisible":true,"label":"Rabbitmq Events","labelTextSize":"0.875rem","serverSideFiltering":false,"options":[{"label":"Blue","value":"BLUE"},{"label":"Green","value":"GREEN"},{"label":"Red","value":"RED"}]}},"dataType":"object","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.rabbitmq))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Object","sourceData":{"websocket_enabled":false,"websocket_events":["APPLICATION_STARTUP","QRCODE_UPDATED","MESSAGES_SET","MESSAGES_UPSERT","MESSAGES_UPDATE","MESSAGES_DELETE","SEND_MESSAGE","CONTACTS_SET","CONTACTS_UPSERT","CONTACTS_UPDATE","PRESENCE_UPDATE","CHATS_SET","CHATS_UPSERT","CHATS_UPDATE","CHATS_DELETE","GROUPS_UPSERT","GROUP_UPDATE","GROUP_PARTICIPANTS_UPDATE","CONNECTION_UPDATE","CALL","NEW_JWT_TOKEN"]},"isCustomField":false,"accessor":"rabbitmq","identifier":"rabbitmq","position":4.0,"originalIdentifier":"rabbitmq","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","cellBorderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","cellBoxShadow":"none","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"1rem","label":"Rabbitmq","labelStyle":"BOLD"}},"dataType":"object","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","fieldType":"Object","sourceData":{"instanceName":"","token":"","webhook":"","webhook_by_events":false,"events":["APPLICATION_STARTUP","QRCODE_UPDATED","MESSAGES_SET","MESSAGES_UPSERT","MESSAGES_UPDATE","MESSAGES_DELETE","SEND_MESSAGE","CONTACTS_SET","CONTACTS_UPSERT","CONTACTS_UPDATE","PRESENCE_UPDATE","CHATS_SET","CHATS_UPSERT","CHATS_UPDATE","CHATS_DELETE","GROUPS_UPSERT","GROUP_UPDATE","GROUP_PARTICIPANTS_UPDATE","CONNECTION_UPDATE","CALL","NEW_JWT_TOKEN"],"reject_call":false,"msg_call":"","groups_ignore":false,"always_online":false,"read_messages":false,"read_status":false,"chatwoot_account_id":"","chatwoot_token":"","chatwoot_url":"","chatwoot_sign_msg":false,"chatwoot_reopen_conversation":false,"chatwoot_conversation_pending":false},"isCustomField":false,"accessor":"__root_schema__","identifier":"__root_schema__","position":-1.0,"originalIdentifier":"__root_schema__","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","boxShadow":"none","cellBorderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormInstance.sourceData, FormInstance.formData, FormInstance.fieldState)}}","cellBoxShadow":"none","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":""}},"mobileBottomRow":85.0,"widgetName":"FormInstance","submitButtonStyles":{"buttonColor":"rgb(3, 179, 101)","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","buttonVariant":"PRIMARY"},"dynamicPropertyPathList":[{"key":"schema.__root_schema__.children.webhook.children.webhook_by_events.defaultValue"},{"key":"schema.__root_schema__.children.settings.children.reject_call.defaultValue"},{"key":"schema.__root_schema__.children.settings.children.groups_ignore.defaultValue"},{"key":"schema.__root_schema__.children.settings.children.always_online.defaultValue"},{"key":"schema.__root_schema__.children.settings.children.read_messages.defaultValue"},{"key":"schema.__root_schema__.children.settings.children.read_status.defaultValue"},{"key":"schema.__root_schema__.children.chatwoot.children.chatwoot_sign_msg.defaultValue"},{"key":"schema.__root_schema__.children.chatwoot.children.chatwoot_reopen_conversation.defaultValue"},{"key":"schema.__root_schema__.children.chatwoot.children.chatwoot_conversation_pending.defaultValue"},{"key":"schema.__root_schema__.children.instance.children.qrcode.defaultValue"},{"key":"schema.__root_schema__.children.websocket.children.websocket_enabled.defaultValue"},{"key":"schema.__root_schema__.children.rabbitmq.children.rabbitmq_enabled.defaultValue"}],"displayName":"JSON Form","bottomRow":183.0,"fieldLimitExceeded":false,"parentRowSpace":10.0,"title":"New Instance","hideCard":false,"mobileRightColumn":22.0,"shouldScrollContents":true,"parentColumnSpace":17.9375,"dynamicTriggerPathList":[{"key":"onSubmit"}],"borderWidth":"0","sourceData":"{\n \"instance\": {\n\t\t\t\"instanceName\": \"\",\n \t\"token\": \"\",\n\t\t\t\"qrcode\": true\n\t\t},\n\t\t\"webhook\": {\n\t\t\t\"webhook\": \"\",\n\t\t\t\"events\": [\n\t\t\t\t\"APPLICATION_STARTUP\",\n\t\t\t\t\t\"QRCODE_UPDATED\",\n\t\t\t\t\t\"MESSAGES_SET\",\n\t\t\t\t\t\"MESSAGES_UPSERT\",\n\t\t\t\t\t\"MESSAGES_UPDATE\",\n\t\t\t\t\t\"MESSAGES_DELETE\",\n\t\t\t\t\t\"SEND_MESSAGE\",\n\t\t\t\t\t\"CONTACTS_SET\",\n\t\t\t\t\t\"CONTACTS_UPSERT\",\n\t\t\t\t\t\"CONTACTS_UPDATE\",\n\t\t\t\t\t\"PRESENCE_UPDATE\",\n\t\t\t\t\t\"CHATS_SET\",\n\t\t\t\t\t\"CHATS_UPSERT\",\n\t\t\t\t\t\"CHATS_UPDATE\",\n\t\t\t\t\t\"CHATS_DELETE\",\n\t\t\t\t\t\"GROUPS_UPSERT\",\n\t\t\t\t\t\"GROUP_UPDATE\",\n\t\t\t\t\t\"GROUP_PARTICIPANTS_UPDATE\",\n\t\t\t\t\t\"CONNECTION_UPDATE\",\n\t\t\t\t\t\"CALL\",\n\t\t\t\t\t\"NEW_JWT_TOKEN\"\n\t\t\t],\n\t\t\t\"webhook_by_events\": false\n\t\t},\n \"settings\": {\n\t\t\t\"reject_call\": false,\n\t\t\t\"msg_call\": \"\",\n\t\t\t\"groups_ignore\": false,\n\t\t\t\"always_online\": false,\n\t\t\t\"read_messages\": false,\n\t\t\t\"read_status\": false\n\t\t},\n\t\t\"websocket\": {\n\t\t\t\"websocket_enabled\": false,\n\t\t\t\"websocket_events\": [\n\t\t\t\t\"APPLICATION_STARTUP\",\n\t\t\t\t\t\"QRCODE_UPDATED\",\n\t\t\t\t\t\"MESSAGES_SET\",\n\t\t\t\t\t\"MESSAGES_UPSERT\",\n\t\t\t\t\t\"MESSAGES_UPDATE\",\n\t\t\t\t\t\"MESSAGES_DELETE\",\n\t\t\t\t\t\"SEND_MESSAGE\",\n\t\t\t\t\t\"CONTACTS_SET\",\n\t\t\t\t\t\"CONTACTS_UPSERT\",\n\t\t\t\t\t\"CONTACTS_UPDATE\",\n\t\t\t\t\t\"PRESENCE_UPDATE\",\n\t\t\t\t\t\"CHATS_SET\",\n\t\t\t\t\t\"CHATS_UPSERT\",\n\t\t\t\t\t\"CHATS_UPDATE\",\n\t\t\t\t\t\"CHATS_DELETE\",\n\t\t\t\t\t\"GROUPS_UPSERT\",\n\t\t\t\t\t\"GROUP_UPDATE\",\n\t\t\t\t\t\"GROUP_PARTICIPANTS_UPDATE\",\n\t\t\t\t\t\"CONNECTION_UPDATE\",\n\t\t\t\t\t\"CALL\",\n\t\t\t\t\t\"NEW_JWT_TOKEN\"\n\t\t\t]\n\t\t},\n\t\t\"rabbitmq\": {\n\t\t\t\"rabbitmq_enabled\": false,\n\t\t\t\"rabbitmq_events\": [\n\t\t\t\t\"APPLICATION_STARTUP\",\n\t\t\t\t\t\"QRCODE_UPDATED\",\n\t\t\t\t\t\"MESSAGES_SET\",\n\t\t\t\t\t\"MESSAGES_UPSERT\",\n\t\t\t\t\t\"MESSAGES_UPDATE\",\n\t\t\t\t\t\"MESSAGES_DELETE\",\n\t\t\t\t\t\"SEND_MESSAGE\",\n\t\t\t\t\t\"CONTACTS_SET\",\n\t\t\t\t\t\"CONTACTS_UPSERT\",\n\t\t\t\t\t\"CONTACTS_UPDATE\",\n\t\t\t\t\t\"PRESENCE_UPDATE\",\n\t\t\t\t\t\"CHATS_SET\",\n\t\t\t\t\t\"CHATS_UPSERT\",\n\t\t\t\t\t\"CHATS_UPDATE\",\n\t\t\t\t\t\"CHATS_DELETE\",\n\t\t\t\t\t\"GROUPS_UPSERT\",\n\t\t\t\t\t\"GROUP_UPDATE\",\n\t\t\t\t\t\"GROUP_PARTICIPANTS_UPDATE\",\n\t\t\t\t\t\"CONNECTION_UPDATE\",\n\t\t\t\t\t\"CALL\",\n\t\t\t\t\t\"NEW_JWT_TOKEN\"\n\t\t\t]\n\t\t},\n \"chatwoot\": {\n\t\t\t\"chatwoot_account_id\": \"\",\n\t\t\t\"chatwoot_token\": \"\",\n\t\t\t\"chatwoot_url\": \"\",\n\t\t\t\"chatwoot_sign_msg\": false,\n\t\t\t\"chatwoot_reopen_conversation\": false,\n\t\t\t\"chatwoot_conversation_pending\": false\n\t\t}\n}","resetButtonLabel":"Reset","key":"lgqqk5r1jk","backgroundColor":"#fff","isDeprecated":false,"rightColumn":63.0,"widgetId":"o0v8ypwnya","minWidth":450.0,"parentId":"esgwuzqcwt","renderMode":"CANVAS","mobileTopRow":44.0,"scrollContents":true,"responsiveBehavior":"fill","fixedFooter":true,"originalTopRow":4.0,"mobileLeftColumn":0.0,"maxDynamicHeight":9000.0,"minDynamicHeight":4.0}],"isDisabled":false,"key":"w17ra2a85u","isDeprecated":false,"rightColumn":283.875,"detachFromLayout":true,"widgetId":"esgwuzqcwt","minWidth":450.0,"isVisible":true,"version":1.0,"parentId":"rnttu90jzr","renderMode":"CANVAS","isLoading":false,"mobileTopRow":0.0,"responsiveBehavior":"fill","mobileLeftColumn":0.0,"flexLayers":[]}],"key":"bkvkzj4d20","height":1850.0,"isDeprecated":false,"rightColumn":37.0,"detachFromLayout":true,"dynamicHeight":"AUTO_HEIGHT","widgetId":"rnttu90jzr","canOutsideClickClose":true,"canEscapeKeyClose":true,"version":2.0,"parentId":"0","renderMode":"CANVAS","isLoading":false,"mobileTopRow":42.0,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":13.0,"maxDynamicHeight":9000.0,"width":628.0,"minDynamicHeight":24.0},{"resetFormOnClick":false,"boxShadow":"none","mobileBottomRow":5.0,"widgetName":"ButtonRefreshData","onClick":"{{fetch_Instances.run()}}","buttonColor":"#60a5fa","dynamicPropertyPathList":[{"key":"isVisible"}],"displayName":"Button","iconSVG":"/static/media/icon.7beb9123fb53027d9d6b778cdfe4caed.svg","searchTags":["click","submit"],"topRow":1.0,"bottomRow":5.0,"parentRowSpace":10.0,"type":"BUTTON_WIDGET","hideCard":false,"mobileRightColumn":35.0,"animateLoading":true,"parentColumnSpace":11.828125,"dynamicTriggerPathList":[{"key":"onClick"}],"leftColumn":19.0,"dynamicBindingPathList":[{"key":"isVisible"},{"key":"borderRadius"}],"text":"","isDisabled":false,"key":"k10nyfsas3","isDeprecated":false,"rightColumn":24.0,"isDefaultClickDisabled":true,"iconName":"refresh","widgetId":"dn1ehe3gvu","minWidth":120.0,"isVisible":"{{appsmith.store.api_key && appsmith.store.api_url ? true : false}}","recaptchaType":"V3","version":1.0,"parentId":"0","renderMode":"CANVAS","isLoading":false,"mobileTopRow":1.0,"responsiveBehavior":"hug","disabledWhenInvalid":false,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":19.0,"buttonVariant":"PRIMARY","iconAlign":"left","placement":"CENTER"},{"boxShadow":"none","mobileBottomRow":5.0,"widgetName":"ButtonGroup1","isCanvas":false,"dynamicPropertyPathList":[{"key":"isVisible"}],"displayName":"Button Group","iconSVG":"/static/media/icon.7c22979bacc83c8d84aedf56ea6c2022.svg","searchTags":["click","submit"],"topRow":1.0,"bottomRow":5.0,"parentRowSpace":10.0,"groupButtons":{"groupButton1":{"label":"Connect","iconName":"camera","id":"groupButton1","widgetId":"","buttonType":"SIMPLE","placement":"CENTER","isVisible":true,"isDisabled":false,"index":0.0,"menuItems":{},"buttonColor":"#16a34a","onClick":"{{Connect.run();\nfetch_Instances.run();\nshowModal('ModalQrcode');}}"},"groupButton2":{"label":"Restart","iconName":"reset","id":"groupButton2","buttonType":"SIMPLE","placement":"CENTER","widgetId":"","isVisible":true,"isDisabled":false,"index":1.0,"menuItems":{},"buttonColor":"#2563eb","onClick":"{{Restart.run().then(() => {\n showAlert('Instance restarted successfully', 'success');\n}).catch(() => {\n showAlert('Error restarting instance', 'error');\n});\nfetch_Instances.run();}}"},"groupButton3":{"label":"Logout","iconName":"log-in","id":"groupButton3","buttonType":"SIMPLE","placement":"CENTER","widgetId":"","isVisible":true,"isDisabled":false,"index":2.0,"menuItems":{"menuItem1":{"label":"First Option","backgroundColor":"#FFFFFF","id":"menuItem1","widgetId":"","onClick":"","isVisible":true,"isDisabled":false,"index":0.0},"menuItem2":{"label":"Second Option","backgroundColor":"#FFFFFF","id":"menuItem2","widgetId":"","onClick":"","isVisible":true,"isDisabled":false,"index":1.0},"menuItem3":{"label":"Delete","iconName":"trash","iconColor":"#FFFFFF","iconAlign":"right","textColor":"#FFFFFF","backgroundColor":"#DD4B34","id":"menuItem3","widgetId":"","onClick":"","isVisible":true,"isDisabled":false,"index":2.0}},"buttonColor":"#a16207","onClick":"{{Logout.run().then(() => {\n showAlert('Instance logout successfully', 'success');\n}).catch(() => {\n showAlert('Error logout instance', 'error');\n});\nfetch_Instances.run();}}"},"groupButtonmghcs8rd4g":{"id":"groupButtonmghcs8rd4g","index":3.0,"label":"Delete","menuItems":{},"buttonType":"SIMPLE","placement":"CENTER","widgetId":"v0qkg2pjo2","isDisabled":false,"isVisible":true,"buttonColor":"#ef4444","iconName":"cross","onClick":"{{Delete.run().then(() => {\n showAlert('Instance deleted successfully', 'success');\n}).catch(() => {\n showAlert('Error deleting instance', 'error');\n});\nfetch_Instances.run();}}"}},"type":"BUTTON_GROUP_WIDGET","hideCard":false,"mobileRightColumn":51.0,"animateLoading":true,"parentColumnSpace":11.828125,"dynamicTriggerPathList":[{"key":"groupButtons.groupButton1.onClick"},{"key":"groupButtons.groupButton2.onClick"},{"key":"groupButtons.groupButton3.onClick"},{"key":"groupButtons.groupButtonmghcs8rd4g.onClick"}],"leftColumn":27.0,"dynamicBindingPathList":[{"key":"isVisible"},{"key":"borderRadius"}],"isDisabled":false,"key":"za8m3k8x7w","orientation":"horizontal","isDeprecated":false,"rightColumn":63.0,"widgetId":"2s6fqi483g","minWidth":450.0,"isVisible":"{{appsmith.store.api_key && appsmith.store.api_url ? true : false}}","version":1.0,"parentId":"0","renderMode":"CANVAS","isLoading":false,"mobileTopRow":1.0,"responsiveBehavior":"fill","childStylesheet":{"button":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}"}},"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":27.0,"buttonVariant":"PRIMARY"},{"boxShadow":"none","mobileBottomRow":18.0,"widgetName":"ProfilePicture","dynamicPropertyPathList":[{"key":"isVisible"},{"key":"borderRadius"}],"displayName":"Image","iconSVG":"/static/media/icon.30c8cbd442cce232b01ba2d434c53a53.svg","topRow":6.0,"bottomRow":28.0,"parentRowSpace":10.0,"type":"IMAGE_WIDGET","hideCard":false,"mobileRightColumn":13.0,"animateLoading":true,"parentColumnSpace":11.828125,"dynamicTriggerPathList":[],"imageShape":"RECTANGLE","leftColumn":1.0,"dynamicBindingPathList":[{"key":"image"},{"key":"isVisible"}],"defaultImage":"https://th.bing.com/th/id/OIP.ruat7whad9-kcI8_1KH_tQHaGI?pid=ImgDet&rs=1","key":"bl30j21wwb","image":"{{TableInstances.selectedRow.profilePictureUrl}}","isDeprecated":false,"rightColumn":13.0,"objectFit":"contain","widgetId":"1sjznr31jo","isVisible":"{{appsmith.store.api_key && appsmith.store.api_url ? true : false}}","version":1.0,"parentId":"0","renderMode":"CANVAS","isLoading":false,"mobileTopRow":6.0,"maxZoomLevel":1.0,"enableDownload":false,"borderRadius":"0.335rem","mobileLeftColumn":1.0,"enableRotation":false},{"mobileBottomRow":22.0,"widgetName":"Text4","dynamicPropertyPathList":[{"key":"isVisible"}],"displayName":"Text","iconSVG":"/static/media/icon.c3b6033f570046f8c6288d911333a827.svg","searchTags":["typography","paragraph","label"],"topRow":36.0,"bottomRow":44.0,"parentRowSpace":10.0,"type":"TEXT_WIDGET","hideCard":false,"mobileRightColumn":11.0,"animateLoading":true,"overflow":"NONE","fontFamily":"{{appsmith.theme.fontFamily.appFont}}","parentColumnSpace":11.828125,"dynamicTriggerPathList":[],"leftColumn":1.0,"dynamicBindingPathList":[{"key":"text"},{"key":"isVisible"},{"key":"fontFamily"}],"shouldTruncate":false,"truncateButtonColor":"{{appsmith.theme.colors.primaryColor}}","text":"{{TableInstances.selectedRow.profileName || ''}}\n\n{{TableInstances.selectedRow.profileStatus || ''}}","key":"gqt8t28m33","isDeprecated":false,"rightColumn":13.0,"textAlign":"CENTER","dynamicHeight":"AUTO_HEIGHT","widgetId":"0c356c66hp","minWidth":450.0,"isVisible":"{{appsmith.store.api_key && appsmith.store.api_url ? true : false}}","fontStyle":"BOLD","textColor":"#231F20","version":1.0,"parentId":"0","renderMode":"CANVAS","isLoading":false,"mobileTopRow":18.0,"responsiveBehavior":"fill","originalTopRow":38.0,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":0.0,"maxDynamicHeight":9000.0,"originalBottomRow":44.0,"fontSize":"0.875rem","minDynamicHeight":4.0},{"mobileBottomRow":41.0,"widgetName":"Text5","dynamicPropertyPathList":[{"key":"isVisible"}],"displayName":"Text","iconSVG":"/static/media/icon.c3b6033f570046f8c6288d911333a827.svg","searchTags":["typography","paragraph","label"],"topRow":32.0,"bottomRow":36.0,"parentRowSpace":10.0,"type":"TEXT_WIDGET","hideCard":false,"mobileRightColumn":9.0,"animateLoading":true,"overflow":"NONE","fontFamily":"{{appsmith.theme.fontFamily.appFont}}","parentColumnSpace":11.75,"dynamicTriggerPathList":[],"leftColumn":1.0,"dynamicBindingPathList":[{"key":"text"},{"key":"isVisible"},{"key":"fontFamily"}],"shouldTruncate":false,"truncateButtonColor":"{{appsmith.theme.colors.primaryColor}}","text":"{{TableInstances.selectedRow.instance || ''}}","key":"gqt8t28m33","isDeprecated":false,"rightColumn":13.0,"textAlign":"CENTER","dynamicHeight":"AUTO_HEIGHT","widgetId":"5qg2iscn1l","minWidth":450.0,"isVisible":"{{appsmith.store.api_key && appsmith.store.api_url ? true : false}}","fontStyle":"BOLD","textColor":"#231F20","version":1.0,"parentId":"0","renderMode":"CANVAS","isLoading":false,"mobileTopRow":37.0,"responsiveBehavior":"fill","originalTopRow":32.0,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":0.0,"maxDynamicHeight":9000.0,"originalBottomRow":38.0,"fontSize":"1.25rem","minDynamicHeight":4.0},{"boxShadow":"none","mobileBottomRow":70.0,"widgetName":"ModalWebhook","isCanvas":true,"displayName":"Modal","iconSVG":"/static/media/icon.d2ab7de0666eaef853cc2d330f86887b.svg","searchTags":["dialog","popup","notification"],"topRow":46.0,"bottomRow":43.0,"parentRowSpace":10.0,"type":"MODAL_WIDGET","hideCard":false,"shouldScrollContents":true,"mobileRightColumn":35.0,"minHeight":430.0,"animateLoading":true,"parentColumnSpace":17.9375,"leftColumn":11.0,"dynamicBindingPathList":[{"key":"borderRadius"}],"children":[{"mobileBottomRow":240.0,"widgetName":"Canvas4","displayName":"Canvas","topRow":0.0,"bottomRow":430.0,"parentRowSpace":1.0,"type":"CANVAS_WIDGET","canExtend":true,"hideCard":true,"shouldScrollContents":false,"minHeight":240.0,"mobileRightColumn":430.5,"parentColumnSpace":1.0,"leftColumn":0.0,"dynamicBindingPathList":[],"children":[{"boxShadow":"none","borderColor":"#E0DEDE","iconSVG":"/static/media/icon.efac588608711d232f1c6c8a2144d2dd.svg","onSubmit":"{{Set_Webhook.run().then(() => {\n showAlert('Webhook updated successfully', 'success');\n}).catch(() => {\n showAlert('Error updating webhook', 'error');\n});\ncloseModal('ModalWebhook');}}","topRow":0.0,"type":"JSON_FORM_WIDGET","animateLoading":true,"leftColumn":0.0,"dynamicBindingPathList":[{"key":"borderRadius"},{"key":"submitButtonStyles.buttonColor"},{"key":"schema.__root_schema__.defaultValue"},{"key":"schema.__root_schema__.borderRadius"},{"key":"schema.__root_schema__.cellBorderRadius"},{"key":"sourceData"},{"key":"schema.__root_schema__.children.enabled.defaultValue"},{"key":"schema.__root_schema__.children.enabled.accentColor"},{"key":"schema.__root_schema__.children.url.defaultValue"},{"key":"schema.__root_schema__.children.url.accentColor"},{"key":"schema.__root_schema__.children.url.borderRadius"},{"key":"schema.__root_schema__.children.webhook_by_events.defaultValue"},{"key":"schema.__root_schema__.children.webhook_by_events.accentColor"},{"key":"schema.__root_schema__.children.events.defaultValue"},{"key":"schema.__root_schema__.children.events.accentColor"},{"key":"schema.__root_schema__.children.events.borderRadius"}],"showReset":false,"dynamicHeight":"AUTO_HEIGHT","autoGenerateForm":false,"resetButtonStyles":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","buttonVariant":"SECONDARY"},"isVisible":true,"version":1.0,"isLoading":false,"submitButtonLabel":"Save","childStylesheet":{"ARRAY":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","cellBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","cellBoxShadow":"none"},"OBJECT":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","cellBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","cellBoxShadow":"none"},"CHECKBOX":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}"},"CURRENCY_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"DATEPICKER":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"EMAIL_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTISELECT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTILINE_TEXT_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"NUMBER_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PASSWORD_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PHONE_NUMBER_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"RADIO_GROUP":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"SELECT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"SWITCH":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"TEXT_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"}},"disabledWhenInvalid":true,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","originalBottomRow":41.0,"useSourceData":false,"schema":{"__root_schema__":{"children":{"enabled":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.enabled))(FormWebhook.sourceData, FormWebhook.formData, FormWebhook.fieldState)}}","fieldType":"Switch","sourceData":false,"isCustomField":false,"accessor":"enabled","identifier":"enabled","position":0.0,"originalIdentifier":"enabled","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormWebhook.sourceData, FormWebhook.formData, FormWebhook.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Enabled"},"url":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.url))(FormWebhook.sourceData, FormWebhook.formData, FormWebhook.fieldState)}}","fieldType":"Text Input","sourceData":"","isCustomField":false,"accessor":"url","identifier":"url","position":1.0,"originalIdentifier":"url","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormWebhook.sourceData, FormWebhook.formData, FormWebhook.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormWebhook.sourceData, FormWebhook.formData, FormWebhook.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Url"},"webhook_by_events":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.webhook_by_events))(FormWebhook.sourceData, FormWebhook.formData, FormWebhook.fieldState)}}","fieldType":"Switch","sourceData":false,"isCustomField":false,"accessor":"webhook_by_events","identifier":"webhook_by_events","position":2.0,"originalIdentifier":"webhook_by_events","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormWebhook.sourceData, FormWebhook.formData, FormWebhook.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Webhook By Events"},"events":{"children":{},"dataType":"array","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.events))(FormWebhook.sourceData, FormWebhook.formData, FormWebhook.fieldState)}}","fieldType":"Multiselect","sourceData":[],"isCustomField":false,"accessor":"events","identifier":"events","position":3.0,"originalIdentifier":"events","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormWebhook.sourceData, FormWebhook.formData, FormWebhook.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormWebhook.sourceData, FormWebhook.formData, FormWebhook.fieldState)}}","boxShadow":"none","isDisabled":false,"isFilterable":false,"isRequired":false,"isVisible":true,"label":"Events","labelTextSize":"0.875rem","serverSideFiltering":false,"options":"[\n\n {\n \"label\": \"APPLICATION_STARTUP\",\n \"value\": \"APPLICATION_STARTUP\"\n },\n {\n \"label\": \"QRCODE_UPDATED\",\n \"value\": \"QRCODE_UPDATED\"\n },\n {\n \"label\": \"MESSAGES_SET\",\n \"value\": \"MESSAGES_SET\"\n },\n {\n \"label\": \"MESSAGES_UPSERT\",\n \"value\": \"MESSAGES_UPSERT\"\n },\n {\n \"label\": \"MESSAGES_UPDATE\",\n \"value\": \"MESSAGES_UPDATE\"\n },\n {\n \"label\": \"MESSAGES_DELETE\",\n \"value\": \"MESSAGES_DELETE\"\n },\n {\n \"label\": \"SEND_MESSAGE\",\n \"value\": \"SEND_MESSAGE\"\n },\n {\n \"label\": \"CONTACTS_SET\",\n \"value\": \"CONTACTS_SET\"\n },\n {\n \"label\": \"CONTACTS_UPSERT\",\n \"value\": \"CONTACTS_UPSERT\"\n },\n {\n \"label\": \"CONTACTS_UPDATE\",\n \"value\": \"CONTACTS_UPDATE\"\n },\n {\n \"label\": \"PRESENCE_UPDATE\",\n \"value\": \"PRESENCE_UPDATE\"\n },\n {\n \"label\": \"CHATS_SET\",\n \"value\": \"CHATS_SET\"\n },\n {\n \"label\": \"CHATS_UPSERT\",\n \"value\": \"CHATS_UPSERT\"\n },\n {\n \"label\": \"CHATS_UPDATE\",\n \"value\": \"CHATS_UPDATE\"\n },\n {\n \"label\": \"CHATS_DELETE\",\n \"value\": \"CHATS_DELETE\"\n },\n {\n \"label\": \"GROUPS_UPSERT\",\n \"value\": \"GROUPS_UPSERT\"\n },\n {\n \"label\": \"GROUP_UPDATE\",\n \"value\": \"GROUP_UPDATE\"\n },\n {\n \"label\": \"GROUP_PARTICIPANTS_UPDATE\",\n \"value\": \"GROUP_PARTICIPANTS_UPDATE\"\n },\n {\n \"label\": \"CONNECTION_UPDATE\",\n \"value\": \"CONNECTION_UPDATE\"\n },\n {\n \"label\": \"CALL\",\n \"value\": \"CALL\"\n },\n {\n \"label\": \"NEW_JWT_TOKEN\",\n \"value\": \"NEW_JWT_TOKEN\"\n }\n]"}},"dataType":"object","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData))(FormWebhook.sourceData, FormWebhook.formData, FormWebhook.fieldState)}}","fieldType":"Object","sourceData":{"enabled":false,"url":"","webhook_by_events":false,"events":[]},"isCustomField":false,"accessor":"__root_schema__","identifier":"__root_schema__","position":-1.0,"originalIdentifier":"__root_schema__","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormWebhook.sourceData, FormWebhook.formData, FormWebhook.fieldState)}}","boxShadow":"none","cellBorderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormWebhook.sourceData, FormWebhook.formData, FormWebhook.fieldState)}}","cellBoxShadow":"none","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":""}},"mobileBottomRow":41.0,"widgetName":"FormWebhook","submitButtonStyles":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","buttonVariant":"PRIMARY"},"dynamicPropertyPathList":[{"key":"schema.__root_schema__.children.webhook_by_events.defaultValue"},{"key":"schema.__root_schema__.children.enabled.defaultValue"},{"key":"schema.__root_schema__.children.url.defaultValue"}],"displayName":"JSON Form","bottomRow":41.0,"fieldLimitExceeded":false,"parentRowSpace":10.0,"title":"Webhook","hideCard":false,"mobileRightColumn":25.0,"parentColumnSpace":6.9375,"dynamicTriggerPathList":[{"key":"onSubmit"}],"borderWidth":"0","sourceData":"{\n\t\"enabled\": {{Find_Webhook.data.enabled || false}},\n\t\"url\": {{Find_Webhook.data.url}},\n \"webhook_by_events\": {{Find_Webhook.data.webhook_by_events}},\n \"events\": {{Find_Webhook.data.events || false}} \n}","resetButtonLabel":"Reset","key":"lgqqk5r1jk","backgroundColor":"#fff","isDeprecated":false,"rightColumn":63.0,"widgetId":"tb1ekur7fx","minWidth":450.0,"parentId":"mv02ta6pzr","renderMode":"CANVAS","mobileTopRow":0.0,"scrollContents":true,"responsiveBehavior":"fill","fixedFooter":true,"originalTopRow":0.0,"mobileLeftColumn":0.0,"maxDynamicHeight":9000.0,"minDynamicHeight":4.0}],"isDisabled":false,"key":"svq68rvpdn","isDeprecated":false,"rightColumn":430.5,"detachFromLayout":true,"widgetId":"mv02ta6pzr","minWidth":450.0,"isVisible":true,"version":1.0,"parentId":"0g8ql5hukz","renderMode":"CANVAS","isLoading":false,"mobileTopRow":0.0,"responsiveBehavior":"fill","mobileLeftColumn":0.0,"flexLayers":[]}],"key":"6x3z5yow7u","height":430.0,"isDeprecated":false,"rightColumn":35.0,"detachFromLayout":true,"dynamicHeight":"AUTO_HEIGHT","widgetId":"0g8ql5hukz","canOutsideClickClose":true,"canEscapeKeyClose":true,"version":2.0,"parentId":"0","renderMode":"CANVAS","isLoading":false,"mobileTopRow":46.0,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":11.0,"maxDynamicHeight":9000.0,"width":456.0,"minDynamicHeight":24.0},{"boxShadow":"none","mobileBottomRow":70.0,"widgetName":"ModalWebsocket","isCanvas":true,"displayName":"Modal","iconSVG":"/static/media/icon.d2ab7de0666eaef853cc2d330f86887b.svg","searchTags":["dialog","popup","notification"],"topRow":42.0,"bottomRow":40.0,"parentRowSpace":10.0,"type":"MODAL_WIDGET","hideCard":false,"shouldScrollContents":true,"mobileRightColumn":35.0,"minHeight":400.0,"animateLoading":true,"parentColumnSpace":17.9375,"leftColumn":11.0,"dynamicBindingPathList":[{"key":"borderRadius"}],"children":[{"mobileBottomRow":240.0,"widgetName":"Canvas4Copy1","displayName":"Canvas","topRow":0.0,"bottomRow":400.0,"parentRowSpace":1.0,"type":"CANVAS_WIDGET","canExtend":true,"hideCard":true,"shouldScrollContents":false,"minHeight":400.0,"mobileRightColumn":430.5,"parentColumnSpace":1.0,"leftColumn":0.0,"dynamicBindingPathList":[],"children":[{"boxShadow":"none","borderColor":"#E0DEDE","iconSVG":"/static/media/icon.efac588608711d232f1c6c8a2144d2dd.svg","onSubmit":"{{Set_Websocket.run().then(() => {\n showAlert('Websocket updated successfully', 'success');\n}).catch(() => {\n showAlert('Error updating websocket', 'error');\n});\ncloseModal('ModalWebsocket');}}","topRow":0.0,"type":"JSON_FORM_WIDGET","animateLoading":true,"leftColumn":0.0,"dynamicBindingPathList":[{"key":"borderRadius"},{"key":"submitButtonStyles.buttonColor"},{"key":"schema.__root_schema__.defaultValue"},{"key":"schema.__root_schema__.borderRadius"},{"key":"sourceData"},{"key":"schema.__root_schema__.children.enabled.defaultValue"},{"key":"schema.__root_schema__.children.enabled.accentColor"},{"key":"schema.__root_schema__.children.url.defaultValue"},{"key":"schema.__root_schema__.children.url.accentColor"},{"key":"schema.__root_schema__.children.url.borderRadius"},{"key":"schema.__root_schema__.children.events.defaultValue"},{"key":"schema.__root_schema__.children.events.accentColor"},{"key":"schema.__root_schema__.children.events.borderRadius"},{"key":"schema.__root_schema__.cellBorderRadius"}],"showReset":false,"dynamicHeight":"AUTO_HEIGHT","autoGenerateForm":false,"resetButtonStyles":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","buttonVariant":"SECONDARY"},"isVisible":true,"version":1.0,"isLoading":false,"submitButtonLabel":"Save","childStylesheet":{"ARRAY":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","cellBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","cellBoxShadow":"none"},"OBJECT":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","cellBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","cellBoxShadow":"none"},"CHECKBOX":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}"},"CURRENCY_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"DATEPICKER":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"EMAIL_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTISELECT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTILINE_TEXT_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"NUMBER_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PASSWORD_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PHONE_NUMBER_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"RADIO_GROUP":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"SELECT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"SWITCH":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"TEXT_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"}},"disabledWhenInvalid":true,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","originalBottomRow":38.0,"useSourceData":false,"schema":{"__root_schema__":{"children":{"enabled":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.enabled))(FormWebsocket.sourceData, FormWebsocket.formData, FormWebsocket.fieldState)}}","fieldType":"Switch","sourceData":true,"isCustomField":false,"accessor":"enabled","identifier":"enabled","position":0.0,"originalIdentifier":"enabled","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormWebsocket.sourceData, FormWebsocket.formData, FormWebsocket.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Enabled"},"url":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.url))(FormWebsocket.sourceData, FormWebsocket.formData, FormWebsocket.fieldState)}}","fieldType":"Text Input","sourceData":"https://teste.com","isCustomField":false,"accessor":"url","identifier":"url","position":1.0,"originalIdentifier":"url","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormWebsocket.sourceData, FormWebsocket.formData, FormWebsocket.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormWebsocket.sourceData, FormWebsocket.formData, FormWebsocket.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Url"},"events":{"children":{},"dataType":"array","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.events))(FormWebsocket.sourceData, FormWebsocket.formData, FormWebsocket.fieldState)}}","fieldType":"Multiselect","sourceData":["MESSAGES_UPSERT"],"isCustomField":false,"accessor":"events","identifier":"events","position":2.0,"originalIdentifier":"events","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormWebsocket.sourceData, FormWebsocket.formData, FormWebsocket.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormWebsocket.sourceData, FormWebsocket.formData, FormWebsocket.fieldState)}}","boxShadow":"none","isDisabled":false,"isFilterable":false,"isRequired":false,"isVisible":true,"label":"Events","labelTextSize":"0.875rem","serverSideFiltering":false,"options":"[\n\n {\n \"label\": \"APPLICATION_STARTUP\",\n \"value\": \"APPLICATION_STARTUP\"\n },\n {\n \"label\": \"QRCODE_UPDATED\",\n \"value\": \"QRCODE_UPDATED\"\n },\n {\n \"label\": \"MESSAGES_SET\",\n \"value\": \"MESSAGES_SET\"\n },\n {\n \"label\": \"MESSAGES_UPSERT\",\n \"value\": \"MESSAGES_UPSERT\"\n },\n {\n \"label\": \"MESSAGES_UPDATE\",\n \"value\": \"MESSAGES_UPDATE\"\n },\n {\n \"label\": \"MESSAGES_DELETE\",\n \"value\": \"MESSAGES_DELETE\"\n },\n {\n \"label\": \"SEND_MESSAGE\",\n \"value\": \"SEND_MESSAGE\"\n },\n {\n \"label\": \"CONTACTS_SET\",\n \"value\": \"CONTACTS_SET\"\n },\n {\n \"label\": \"CONTACTS_UPSERT\",\n \"value\": \"CONTACTS_UPSERT\"\n },\n {\n \"label\": \"CONTACTS_UPDATE\",\n \"value\": \"CONTACTS_UPDATE\"\n },\n {\n \"label\": \"PRESENCE_UPDATE\",\n \"value\": \"PRESENCE_UPDATE\"\n },\n {\n \"label\": \"CHATS_SET\",\n \"value\": \"CHATS_SET\"\n },\n {\n \"label\": \"CHATS_UPSERT\",\n \"value\": \"CHATS_UPSERT\"\n },\n {\n \"label\": \"CHATS_UPDATE\",\n \"value\": \"CHATS_UPDATE\"\n },\n {\n \"label\": \"CHATS_DELETE\",\n \"value\": \"CHATS_DELETE\"\n },\n {\n \"label\": \"GROUPS_UPSERT\",\n \"value\": \"GROUPS_UPSERT\"\n },\n {\n \"label\": \"GROUP_UPDATE\",\n \"value\": \"GROUP_UPDATE\"\n },\n {\n \"label\": \"GROUP_PARTICIPANTS_UPDATE\",\n \"value\": \"GROUP_PARTICIPANTS_UPDATE\"\n },\n {\n \"label\": \"CONNECTION_UPDATE\",\n \"value\": \"CONNECTION_UPDATE\"\n },\n {\n \"label\": \"CALL\",\n \"value\": \"CALL\"\n },\n {\n \"label\": \"NEW_JWT_TOKEN\",\n \"value\": \"NEW_JWT_TOKEN\"\n }\n]"}},"dataType":"object","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData))(FormWebsocket.sourceData, FormWebsocket.formData, FormWebsocket.fieldState)}}","fieldType":"Object","sourceData":{"enabled":true,"url":"https://teste.com","events":["MESSAGES_UPSERT"]},"isCustomField":false,"accessor":"__root_schema__","identifier":"__root_schema__","position":-1.0,"originalIdentifier":"__root_schema__","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormWebsocket.sourceData, FormWebsocket.formData, FormWebsocket.fieldState)}}","boxShadow":"none","cellBorderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormWebsocket.sourceData, FormWebsocket.formData, FormWebsocket.fieldState)}}","cellBoxShadow":"none","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":""}},"mobileBottomRow":41.0,"widgetName":"FormWebsocket","submitButtonStyles":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","buttonVariant":"PRIMARY"},"dynamicPropertyPathList":[{"key":"schema.__root_schema__.children.enabled.defaultValue"},{"key":"schema.__root_schema__.children.events.defaultValue"},{"key":"schema.__root_schema__.children.url.defaultValue"}],"displayName":"JSON Form","bottomRow":38.0,"fieldLimitExceeded":false,"parentRowSpace":10.0,"title":"Websocket","hideCard":false,"mobileRightColumn":25.0,"parentColumnSpace":6.9375,"dynamicTriggerPathList":[{"key":"onSubmit"}],"borderWidth":"0","sourceData":"{\n\t\"enabled\": {{Find_Websocket.data.enabled || false}},\n \"url\": {{Find_Websocket.data.url}},\n \"events\": {{Find_Websocket.data.events}}\n\t\t\n }","resetButtonLabel":"Reset","key":"lgqqk5r1jk","backgroundColor":"#fff","isDeprecated":false,"rightColumn":63.0,"widgetId":"masqwth5vo","minWidth":450.0,"parentId":"gzf4hjxdo8","renderMode":"CANVAS","mobileTopRow":0.0,"scrollContents":true,"responsiveBehavior":"fill","fixedFooter":true,"originalTopRow":0.0,"mobileLeftColumn":0.0,"maxDynamicHeight":9000.0,"minDynamicHeight":4.0}],"isDisabled":false,"key":"svq68rvpdn","isDeprecated":false,"rightColumn":430.5,"detachFromLayout":true,"widgetId":"gzf4hjxdo8","minWidth":450.0,"isVisible":true,"version":1.0,"parentId":"9twyngcwej","renderMode":"CANVAS","isLoading":false,"mobileTopRow":0.0,"responsiveBehavior":"fill","mobileLeftColumn":0.0,"flexLayers":[]}],"key":"6x3z5yow7u","height":400.0,"isDeprecated":false,"rightColumn":35.0,"detachFromLayout":true,"dynamicHeight":"AUTO_HEIGHT","widgetId":"9twyngcwej","canOutsideClickClose":true,"canEscapeKeyClose":true,"version":2.0,"parentId":"0","renderMode":"CANVAS","isLoading":false,"mobileTopRow":46.0,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":11.0,"maxDynamicHeight":9000.0,"width":456.0,"minDynamicHeight":24.0},{"boxShadow":"none","mobileBottomRow":70.0,"widgetName":"ModalRabbitmq","isCanvas":true,"displayName":"Modal","iconSVG":"/static/media/icon.d2ab7de0666eaef853cc2d330f86887b.svg","searchTags":["dialog","popup","notification"],"topRow":31.0,"bottomRow":32.0,"parentRowSpace":10.0,"type":"MODAL_WIDGET","hideCard":false,"shouldScrollContents":true,"mobileRightColumn":35.0,"minHeight":320.0,"animateLoading":true,"parentColumnSpace":17.9375,"leftColumn":11.0,"dynamicBindingPathList":[{"key":"borderRadius"}],"children":[{"mobileBottomRow":240.0,"widgetName":"Canvas4Copy1Copy","displayName":"Canvas","topRow":0.0,"bottomRow":320.0,"parentRowSpace":1.0,"type":"CANVAS_WIDGET","canExtend":true,"hideCard":true,"shouldScrollContents":false,"minHeight":240.0,"mobileRightColumn":430.5,"parentColumnSpace":1.0,"leftColumn":0.0,"dynamicBindingPathList":[],"children":[{"boxShadow":"none","borderColor":"#E0DEDE","iconSVG":"/static/media/icon.efac588608711d232f1c6c8a2144d2dd.svg","onSubmit":"{{Set_Rabbitmq.run().then(() => {\n showAlert('Rabbitmq updated successfully', 'success');\n}).catch(() => {\n showAlert('Error updating rabbitmq', 'error');\n});\ncloseModal('ModalRabbitmq');}}","topRow":0.0,"type":"JSON_FORM_WIDGET","animateLoading":true,"leftColumn":0.0,"dynamicBindingPathList":[{"key":"borderRadius"},{"key":"submitButtonStyles.buttonColor"},{"key":"sourceData"},{"key":"schema.__root_schema__.defaultValue"},{"key":"schema.__root_schema__.borderRadius"},{"key":"schema.__root_schema__.children.enabled.defaultValue"},{"key":"schema.__root_schema__.children.enabled.accentColor"},{"key":"schema.__root_schema__.children.events.defaultValue"},{"key":"schema.__root_schema__.children.events.accentColor"},{"key":"schema.__root_schema__.children.events.borderRadius"},{"key":"schema.__root_schema__.cellBorderRadius"}],"showReset":false,"dynamicHeight":"AUTO_HEIGHT","autoGenerateForm":false,"resetButtonStyles":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","buttonVariant":"SECONDARY"},"isVisible":true,"version":1.0,"isLoading":false,"submitButtonLabel":"Save","childStylesheet":{"ARRAY":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","cellBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","cellBoxShadow":"none"},"OBJECT":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","cellBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","cellBoxShadow":"none"},"CHECKBOX":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}"},"CURRENCY_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"DATEPICKER":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"EMAIL_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTISELECT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTILINE_TEXT_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"NUMBER_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PASSWORD_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PHONE_NUMBER_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"RADIO_GROUP":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"SELECT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"SWITCH":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"TEXT_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"}},"disabledWhenInvalid":true,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","originalBottomRow":30.0,"useSourceData":false,"schema":{"__root_schema__":{"children":{"enabled":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.enabled))(FormRabbitmq.sourceData, FormRabbitmq.formData, FormRabbitmq.fieldState)}}","fieldType":"Switch","sourceData":false,"isCustomField":false,"accessor":"enabled","identifier":"enabled","position":0.0,"originalIdentifier":"enabled","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormRabbitmq.sourceData, FormRabbitmq.formData, FormRabbitmq.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Enabled"},"events":{"children":{},"dataType":"array","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.events))(FormRabbitmq.sourceData, FormRabbitmq.formData, FormRabbitmq.fieldState)}}","fieldType":"Multiselect","sourceData":[],"isCustomField":false,"accessor":"events","identifier":"events","position":1.0,"originalIdentifier":"events","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormRabbitmq.sourceData, FormRabbitmq.formData, FormRabbitmq.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormRabbitmq.sourceData, FormRabbitmq.formData, FormRabbitmq.fieldState)}}","boxShadow":"none","isDisabled":false,"isFilterable":false,"isRequired":false,"isVisible":true,"label":"Events","labelTextSize":"0.875rem","serverSideFiltering":false,"options":"[\n\n {\n \"label\": \"APPLICATION_STARTUP\",\n \"value\": \"APPLICATION_STARTUP\"\n },\n {\n \"label\": \"QRCODE_UPDATED\",\n \"value\": \"QRCODE_UPDATED\"\n },\n {\n \"label\": \"MESSAGES_SET\",\n \"value\": \"MESSAGES_SET\"\n },\n {\n \"label\": \"MESSAGES_UPSERT\",\n \"value\": \"MESSAGES_UPSERT\"\n },\n {\n \"label\": \"MESSAGES_UPDATE\",\n \"value\": \"MESSAGES_UPDATE\"\n },\n {\n \"label\": \"MESSAGES_DELETE\",\n \"value\": \"MESSAGES_DELETE\"\n },\n {\n \"label\": \"SEND_MESSAGE\",\n \"value\": \"SEND_MESSAGE\"\n },\n {\n \"label\": \"CONTACTS_SET\",\n \"value\": \"CONTACTS_SET\"\n },\n {\n \"label\": \"CONTACTS_UPSERT\",\n \"value\": \"CONTACTS_UPSERT\"\n },\n {\n \"label\": \"CONTACTS_UPDATE\",\n \"value\": \"CONTACTS_UPDATE\"\n },\n {\n \"label\": \"PRESENCE_UPDATE\",\n \"value\": \"PRESENCE_UPDATE\"\n },\n {\n \"label\": \"CHATS_SET\",\n \"value\": \"CHATS_SET\"\n },\n {\n \"label\": \"CHATS_UPSERT\",\n \"value\": \"CHATS_UPSERT\"\n },\n {\n \"label\": \"CHATS_UPDATE\",\n \"value\": \"CHATS_UPDATE\"\n },\n {\n \"label\": \"CHATS_DELETE\",\n \"value\": \"CHATS_DELETE\"\n },\n {\n \"label\": \"GROUPS_UPSERT\",\n \"value\": \"GROUPS_UPSERT\"\n },\n {\n \"label\": \"GROUP_UPDATE\",\n \"value\": \"GROUP_UPDATE\"\n },\n {\n \"label\": \"GROUP_PARTICIPANTS_UPDATE\",\n \"value\": \"GROUP_PARTICIPANTS_UPDATE\"\n },\n {\n \"label\": \"CONNECTION_UPDATE\",\n \"value\": \"CONNECTION_UPDATE\"\n },\n {\n \"label\": \"CALL\",\n \"value\": \"CALL\"\n },\n {\n \"label\": \"NEW_JWT_TOKEN\",\n \"value\": \"NEW_JWT_TOKEN\"\n }\n]"}},"dataType":"object","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData))(FormRabbitmq.sourceData, FormRabbitmq.formData, FormRabbitmq.fieldState)}}","fieldType":"Object","sourceData":{"enabled":false,"events":[]},"isCustomField":false,"accessor":"__root_schema__","identifier":"__root_schema__","position":-1.0,"originalIdentifier":"__root_schema__","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormRabbitmq.sourceData, FormRabbitmq.formData, FormRabbitmq.fieldState)}}","boxShadow":"none","cellBorderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormRabbitmq.sourceData, FormRabbitmq.formData, FormRabbitmq.fieldState)}}","cellBoxShadow":"none","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":""}},"mobileBottomRow":41.0,"widgetName":"FormRabbitmq","submitButtonStyles":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","buttonVariant":"PRIMARY"},"dynamicPropertyPathList":[{"key":"schema.__root_schema__.children.events.defaultValue"},{"key":"schema.__root_schema__.children.enabled.defaultValue"}],"displayName":"JSON Form","bottomRow":30.0,"fieldLimitExceeded":false,"parentRowSpace":10.0,"title":"Rabbitmq","hideCard":false,"mobileRightColumn":25.0,"parentColumnSpace":6.9375,"dynamicTriggerPathList":[{"key":"onSubmit"}],"borderWidth":"0","sourceData":"{\n\t\"enabled\": {{Find_Rabbitmq.data.enabled || false}},\n \"events\": {{Find_Rabbitmq.data.events}}\n\t\t\n }","resetButtonLabel":"Reset","key":"lgqqk5r1jk","backgroundColor":"#fff","isDeprecated":false,"rightColumn":63.0,"widgetId":"gdkpog7ep5","minWidth":450.0,"parentId":"rkuaegvcin","renderMode":"CANVAS","mobileTopRow":0.0,"scrollContents":true,"responsiveBehavior":"fill","fixedFooter":true,"originalTopRow":0.0,"mobileLeftColumn":0.0,"maxDynamicHeight":9000.0,"minDynamicHeight":4.0}],"isDisabled":false,"key":"svq68rvpdn","isDeprecated":false,"rightColumn":430.5,"detachFromLayout":true,"widgetId":"rkuaegvcin","minWidth":450.0,"isVisible":true,"version":1.0,"parentId":"76vl08dr1n","renderMode":"CANVAS","isLoading":false,"mobileTopRow":0.0,"responsiveBehavior":"fill","mobileLeftColumn":0.0,"flexLayers":[]}],"key":"6x3z5yow7u","height":320.0,"isDeprecated":false,"rightColumn":35.0,"detachFromLayout":true,"dynamicHeight":"AUTO_HEIGHT","widgetId":"76vl08dr1n","canOutsideClickClose":true,"canEscapeKeyClose":true,"version":2.0,"parentId":"0","renderMode":"CANVAS","isLoading":false,"mobileTopRow":46.0,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":11.0,"maxDynamicHeight":9000.0,"width":456.0,"minDynamicHeight":24.0},{"boxShadow":"none","mobileBottomRow":70.0,"widgetName":"ModalSettings","isCanvas":true,"displayName":"Modal","iconSVG":"/static/media/icon.d2ab7de0666eaef853cc2d330f86887b.svg","searchTags":["dialog","popup","notification"],"topRow":46.0,"bottomRow":47.0,"parentRowSpace":10.0,"type":"MODAL_WIDGET","hideCard":false,"shouldScrollContents":true,"mobileRightColumn":35.0,"minHeight":470.0,"animateLoading":true,"parentColumnSpace":17.9375,"leftColumn":11.0,"dynamicBindingPathList":[{"key":"borderRadius"}],"children":[{"mobileBottomRow":240.0,"widgetName":"Canvas4Copy","displayName":"Canvas","topRow":0.0,"bottomRow":470.0,"parentRowSpace":1.0,"type":"CANVAS_WIDGET","canExtend":true,"hideCard":true,"shouldScrollContents":false,"minHeight":240.0,"mobileRightColumn":430.5,"parentColumnSpace":1.0,"leftColumn":0.0,"dynamicBindingPathList":[],"children":[{"boxShadow":"none","borderColor":"#E0DEDE","iconSVG":"/static/media/icon.efac588608711d232f1c6c8a2144d2dd.svg","onSubmit":"{{Set_Settings.run().then(() => {\n showAlert('Settings updated successfully', 'success');\n}).catch(() => {\n showAlert('Error updating Settings', 'error');\n});\ncloseModal('ModalSettings');}}","topRow":0.0,"type":"JSON_FORM_WIDGET","animateLoading":true,"leftColumn":1.0,"dynamicBindingPathList":[{"key":"schema.__root_schema__.children.read_status.accentColor"},{"key":"schema.__root_schema__.children.read_status.defaultValue"},{"key":"schema.__root_schema__.children.read_messages.accentColor"},{"key":"schema.__root_schema__.children.read_messages.defaultValue"},{"key":"schema.__root_schema__.children.always_online.accentColor"},{"key":"schema.__root_schema__.children.always_online.defaultValue"},{"key":"schema.__root_schema__.children.groups_ignore.accentColor"},{"key":"schema.__root_schema__.children.groups_ignore.defaultValue"},{"key":"schema.__root_schema__.children.msg_call.accentColor"},{"key":"schema.__root_schema__.children.msg_call.defaultValue"},{"key":"schema.__root_schema__.children.reject_call.accentColor"},{"key":"schema.__root_schema__.children.reject_call.defaultValue"},{"key":"borderRadius"},{"key":"sourceData"},{"key":"schema.__root_schema__.children.msg_call.borderRadius"},{"key":"submitButtonStyles.buttonColor"}],"showReset":false,"dynamicHeight":"AUTO_HEIGHT","autoGenerateForm":true,"resetButtonStyles":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","buttonVariant":"SECONDARY"},"isVisible":true,"version":1.0,"isLoading":false,"submitButtonLabel":"Save","childStylesheet":{"ARRAY":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","cellBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","cellBoxShadow":"none"},"OBJECT":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","cellBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","cellBoxShadow":"none"},"CHECKBOX":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}"},"CURRENCY_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"DATEPICKER":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"EMAIL_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTISELECT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTILINE_TEXT_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"NUMBER_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PASSWORD_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PHONE_NUMBER_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"RADIO_GROUP":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"SELECT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"SWITCH":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"TEXT_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"}},"disabledWhenInvalid":true,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","originalBottomRow":45.0,"useSourceData":false,"schema":{"__root_schema__":{"children":{"reject_call":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.reject_call))(FormSettings.sourceData, FormSettings.formData, FormSettings.fieldState)}}","fieldType":"Switch","sourceData":true,"isCustomField":false,"accessor":"reject_call","identifier":"reject_call","position":0.0,"originalIdentifier":"reject_call","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormSettings.sourceData, FormSettings.formData, FormSettings.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Reject Call"},"msg_call":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.msg_call))(FormSettings.sourceData, FormSettings.formData, FormSettings.fieldState)}}","fieldType":"Text Input","sourceData":"Não aceitamos chamadas!","isCustomField":false,"accessor":"msg_call","identifier":"msg_call","position":1.0,"originalIdentifier":"msg_call","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormSettings.sourceData, FormSettings.formData, FormSettings.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormSettings.sourceData, FormSettings.formData, FormSettings.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Msg Call"},"groups_ignore":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.groups_ignore))(FormSettings.sourceData, FormSettings.formData, FormSettings.fieldState)}}","fieldType":"Switch","sourceData":true,"isCustomField":false,"accessor":"groups_ignore","identifier":"groups_ignore","position":2.0,"originalIdentifier":"groups_ignore","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormSettings.sourceData, FormSettings.formData, FormSettings.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Groups Ignore"},"always_online":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.always_online))(FormSettings.sourceData, FormSettings.formData, FormSettings.fieldState)}}","fieldType":"Switch","sourceData":true,"isCustomField":false,"accessor":"always_online","identifier":"always_online","position":3.0,"originalIdentifier":"always_online","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormSettings.sourceData, FormSettings.formData, FormSettings.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Always Online"},"read_messages":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.read_messages))(FormSettings.sourceData, FormSettings.formData, FormSettings.fieldState)}}","fieldType":"Switch","sourceData":true,"isCustomField":false,"accessor":"read_messages","identifier":"read_messages","position":4.0,"originalIdentifier":"read_messages","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormSettings.sourceData, FormSettings.formData, FormSettings.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Read Messages"},"read_status":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.read_status))(FormSettings.sourceData, FormSettings.formData, FormSettings.fieldState)}}","fieldType":"Switch","sourceData":false,"isCustomField":false,"accessor":"read_status","identifier":"read_status","position":5.0,"originalIdentifier":"read_status","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormSettings.sourceData, FormSettings.formData, FormSettings.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Read Status"}},"dataType":"object","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData))(FormWebhook.sourceData, FormWebhook.formData, FormWebhook.fieldState)}}","fieldType":"Object","sourceData":{"name":"John","date_of_birth":"20/02/1990","employee_id":1001.0},"isCustomField":false,"accessor":"__root_schema__","identifier":"__root_schema__","position":-1.0,"originalIdentifier":"__root_schema__","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormWebhook.sourceData, FormWebhook.formData, FormWebhook.fieldState)}}","boxShadow":"none","cellBorderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormWebhook.sourceData, FormWebhook.formData, FormWebhook.fieldState)}}","cellBoxShadow":"none","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":""}},"mobileBottomRow":41.0,"widgetName":"FormSettings","submitButtonStyles":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","buttonVariant":"PRIMARY"},"dynamicPropertyPathList":[{"key":"schema.__root_schema__.children.reject_call.defaultValue"},{"key":"schema.__root_schema__.children.groups_ignore.defaultValue"},{"key":"schema.__root_schema__.children.always_online.defaultValue"},{"key":"schema.__root_schema__.children.read_messages.defaultValue"},{"key":"schema.__root_schema__.children.read_status.defaultValue"},{"key":"schema.__root_schema__.children.msg_call.defaultValue"}],"displayName":"JSON Form","bottomRow":45.0,"fieldLimitExceeded":false,"parentRowSpace":10.0,"title":"Settings","hideCard":false,"mobileRightColumn":25.0,"parentColumnSpace":6.9375,"dynamicTriggerPathList":[{"key":"onSubmit"}],"borderWidth":"0","sourceData":"{\n\t\"reject_call\": {{Find_Settings.data.reject_call || false}},\n \"msg_call\": {{Find_Settings.data.msg_call}},\n \"groups_ignore\": {{Find_Settings.data.groups_ignore || false}},\n \"always_online\": {{Find_Settings.data.always_online || false}},\n \"read_messages\": {{Find_Settings.data.read_messages || false}},\n \"read_status\": {{Find_Settings.data.read_status || false}}\n}","resetButtonLabel":"Reset","key":"lgqqk5r1jk","backgroundColor":"#fff","isDeprecated":false,"rightColumn":64.0,"widgetId":"3wajdobhry","minWidth":450.0,"parentId":"bj66ktxeor","renderMode":"CANVAS","mobileTopRow":0.0,"scrollContents":true,"responsiveBehavior":"fill","fixedFooter":true,"originalTopRow":0.0,"mobileLeftColumn":0.0,"maxDynamicHeight":9000.0,"minDynamicHeight":4.0}],"isDisabled":false,"key":"svq68rvpdn","isDeprecated":false,"rightColumn":430.5,"detachFromLayout":true,"widgetId":"bj66ktxeor","minWidth":450.0,"isVisible":true,"version":1.0,"parentId":"9pvl5efylb","renderMode":"CANVAS","isLoading":false,"mobileTopRow":0.0,"responsiveBehavior":"fill","mobileLeftColumn":0.0,"flexLayers":[]}],"key":"6x3z5yow7u","height":470.0,"isDeprecated":false,"rightColumn":35.0,"detachFromLayout":true,"dynamicHeight":"AUTO_HEIGHT","widgetId":"9pvl5efylb","canOutsideClickClose":true,"canEscapeKeyClose":true,"version":2.0,"parentId":"0","renderMode":"CANVAS","isLoading":false,"mobileTopRow":46.0,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":11.0,"maxDynamicHeight":9000.0,"width":456.0,"minDynamicHeight":24.0},{"boxShadow":"none","mobileBottomRow":70.0,"widgetName":"ModalChatwoot","isCanvas":true,"displayName":"Modal","iconSVG":"/static/media/icon.d2ab7de0666eaef853cc2d330f86887b.svg","searchTags":["dialog","popup","notification"],"topRow":50.0,"bottomRow":780.0,"parentRowSpace":10.0,"type":"MODAL_WIDGET","hideCard":false,"shouldScrollContents":true,"mobileRightColumn":35.0,"minHeight":730.0,"animateLoading":true,"parentColumnSpace":17.9375,"leftColumn":11.0,"dynamicBindingPathList":[{"key":"borderRadius"}],"children":[{"mobileBottomRow":240.0,"widgetName":"Canvas4CopyCopy","displayName":"Canvas","topRow":0.0,"bottomRow":730.0,"parentRowSpace":1.0,"type":"CANVAS_WIDGET","canExtend":true,"hideCard":true,"shouldScrollContents":false,"minHeight":730.0,"mobileRightColumn":430.5,"parentColumnSpace":1.0,"leftColumn":0.0,"dynamicBindingPathList":[],"children":[{"boxShadow":"none","borderColor":"#E0DEDE","iconSVG":"/static/media/icon.efac588608711d232f1c6c8a2144d2dd.svg","onSubmit":"{{Set_Chatwoot.run().then(() => {\n showAlert('Chatwoot updated successfully', 'success');\n}).catch(() => {\n showAlert('Error updating Chatwoot', 'error');\n});\ncloseModal('ModalChatwoot');}}","topRow":0.0,"type":"JSON_FORM_WIDGET","animateLoading":true,"leftColumn":0.0,"dynamicBindingPathList":[{"key":"schema.__root_schema__.children.conversation_pending.accentColor"},{"key":"schema.__root_schema__.children.conversation_pending.defaultValue"},{"key":"schema.__root_schema__.children.reopen_conversation.accentColor"},{"key":"schema.__root_schema__.children.reopen_conversation.defaultValue"},{"key":"schema.__root_schema__.children.sign_msg.accentColor"},{"key":"schema.__root_schema__.children.sign_msg.defaultValue"},{"key":"schema.__root_schema__.children.url.borderRadius"},{"key":"schema.__root_schema__.children.url.accentColor"},{"key":"schema.__root_schema__.children.url.defaultValue"},{"key":"schema.__root_schema__.children.token.borderRadius"},{"key":"schema.__root_schema__.children.token.accentColor"},{"key":"schema.__root_schema__.children.token.defaultValue"},{"key":"schema.__root_schema__.children.account_id.accentColor"},{"key":"schema.__root_schema__.children.account_id.defaultValue"},{"key":"schema.__root_schema__.children.enabled.accentColor"},{"key":"schema.__root_schema__.children.enabled.defaultValue"},{"key":"borderRadius"},{"key":"sourceData"},{"key":"schema.__root_schema__.children.account_id.borderRadius"},{"key":"schema.__root_schema__.children.webhook_url.defaultValue"},{"key":"schema.__root_schema__.children.webhook_url.accentColor"},{"key":"schema.__root_schema__.children.webhook_url.borderRadius"},{"key":"schema.__root_schema__.defaultValue"},{"key":"schema.__root_schema__.borderRadius"},{"key":"schema.__root_schema__.cellBorderRadius"},{"key":"schema.__root_schema__.children.name_inbox.defaultValue"},{"key":"schema.__root_schema__.children.name_inbox.borderRadius"},{"key":"schema.__root_schema__.children.name_inbox.accentColor"},{"key":"submitButtonStyles.buttonColor"}],"showReset":false,"dynamicHeight":"AUTO_HEIGHT","autoGenerateForm":true,"resetButtonStyles":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","buttonVariant":"SECONDARY"},"isVisible":true,"version":1.0,"isLoading":false,"submitButtonLabel":"Save","childStylesheet":{"ARRAY":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","cellBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","cellBoxShadow":"none"},"OBJECT":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","cellBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","cellBoxShadow":"none"},"CHECKBOX":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}"},"CURRENCY_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"DATEPICKER":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"EMAIL_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTISELECT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTILINE_TEXT_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"NUMBER_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PASSWORD_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PHONE_NUMBER_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"RADIO_GROUP":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"SELECT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"SWITCH":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"TEXT_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"}},"disabledWhenInvalid":true,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","originalBottomRow":71.0,"useSourceData":false,"schema":{"__root_schema__":{"children":{"enabled":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.enabled))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","fieldType":"Switch","sourceData":true,"isCustomField":false,"accessor":"enabled","identifier":"enabled","position":0.0,"originalIdentifier":"enabled","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Enabled"},"account_id":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.account_id))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","fieldType":"Text Input","sourceData":"1","isCustomField":false,"accessor":"account_id","identifier":"account_id","position":1.0,"originalIdentifier":"account_id","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Account Id"},"token":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.token))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","fieldType":"Password Input","sourceData":"uHquVJgCdkee8JPJm9YBkdH6","isCustomField":false,"accessor":"token","identifier":"token","position":2.0,"originalIdentifier":"token","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Token","shouldAllowAutofill":true},"url":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.url))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","fieldType":"Text Input","sourceData":"https://chatwoot.evolution.dgcode.com.br","isCustomField":false,"accessor":"url","identifier":"url","position":3.0,"originalIdentifier":"url","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Url"},"sign_msg":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.sign_msg))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","fieldType":"Switch","sourceData":false,"isCustomField":false,"accessor":"sign_msg","identifier":"sign_msg","position":4.0,"originalIdentifier":"sign_msg","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Sign Msg"},"reopen_conversation":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.reopen_conversation))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","fieldType":"Switch","sourceData":true,"isCustomField":false,"accessor":"reopen_conversation","identifier":"reopen_conversation","position":5.0,"originalIdentifier":"reopen_conversation","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Reopen Conversation"},"conversation_pending":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.conversation_pending))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","fieldType":"Switch","sourceData":false,"isCustomField":false,"accessor":"conversation_pending","identifier":"conversation_pending","position":6.0,"originalIdentifier":"conversation_pending","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Conversation Pending"},"webhook_url":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.webhook_url))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","fieldType":"Text Input","sourceData":"https://api.evolution.dgcode.com.br/chatwoot/webhook/evolution-cwId-4","isCustomField":false,"accessor":"webhook_url","identifier":"webhook_url","position":8.0,"originalIdentifier":"webhook_url","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":true,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Webhook Url"},"name_inbox":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.name_inbox))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","fieldType":"Text Input","sourceData":"evolution-cwId-4","isCustomField":false,"accessor":"name_inbox","identifier":"name_inbox","position":7.0,"originalIdentifier":"name_inbox","accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormChatwoot.sourceData, FormChatwoot.formData, FormChatwoot.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":true,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Name Inbox"}},"dataType":"object","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData))(FormWebhook.sourceData, FormWebhook.formData, FormWebhook.fieldState)}}","fieldType":"Object","sourceData":{"name":"John","date_of_birth":"20/02/1990","employee_id":1001.0},"isCustomField":false,"accessor":"__root_schema__","identifier":"__root_schema__","position":-1.0,"originalIdentifier":"__root_schema__","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormWebhook.sourceData, FormWebhook.formData, FormWebhook.fieldState)}}","boxShadow":"none","cellBorderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormWebhook.sourceData, FormWebhook.formData, FormWebhook.fieldState)}}","cellBoxShadow":"none","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":""}},"mobileBottomRow":41.0,"widgetName":"FormChatwoot","submitButtonStyles":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","buttonVariant":"PRIMARY"},"dynamicPropertyPathList":[{"key":"schema.__root_schema__.children.enabled.defaultValue"},{"key":"schema.__root_schema__.children.sign_msg.defaultValue"},{"key":"schema.__root_schema__.children.reopen_conversation.defaultValue"},{"key":"schema.__root_schema__.children.conversation_pending.defaultValue"},{"key":"schema.__root_schema__.children.account_id.defaultValue"},{"key":"schema.__root_schema__.children.webhook_url.defaultValue"}],"displayName":"JSON Form","bottomRow":71.0,"fieldLimitExceeded":false,"parentRowSpace":10.0,"title":"Chatwoot","hideCard":false,"mobileRightColumn":25.0,"parentColumnSpace":6.9375,"dynamicTriggerPathList":[{"key":"onSubmit"}],"borderWidth":"0","sourceData":"{\n\t\"enabled\": {{Find_Chatwoot.data.enabled || false}},\n\t\"account_id\": {{Find_Chatwoot.data.account_id}},\n \"token\": {{Find_Chatwoot.data.token}},\n \"url\": {{Find_Chatwoot.data.url}},\n \"sign_msg\": {{Find_Chatwoot.data.sign_msg || false}},\n \"reopen_conversation\": {{Find_Chatwoot.data.reopen_conversation || false}},\n \"conversation_pending\": {{Find_Chatwoot.data.conversation_pending || false}},\n\t\t\"name_inbox\": {{Find_Chatwoot.data.name_inbox}},\n\t\t\"webhook_url\": {{Find_Chatwoot.data.webhook_url}}\n}","resetButtonLabel":"Reset","key":"lgqqk5r1jk","backgroundColor":"#fff","isDeprecated":false,"rightColumn":63.0,"widgetId":"c5v1lwuyrk","minWidth":450.0,"parentId":"wqoo05rt9h","renderMode":"CANVAS","mobileTopRow":0.0,"scrollContents":true,"responsiveBehavior":"fill","fixedFooter":true,"originalTopRow":0.0,"mobileLeftColumn":0.0,"maxDynamicHeight":9000.0,"minDynamicHeight":4.0}],"isDisabled":false,"key":"svq68rvpdn","isDeprecated":false,"rightColumn":430.5,"detachFromLayout":true,"widgetId":"wqoo05rt9h","minWidth":450.0,"isVisible":true,"version":1.0,"parentId":"kekx3o71p4","renderMode":"CANVAS","isLoading":false,"mobileTopRow":0.0,"responsiveBehavior":"fill","mobileLeftColumn":0.0,"flexLayers":[]}],"key":"6x3z5yow7u","height":730.0,"isDeprecated":false,"rightColumn":35.0,"detachFromLayout":true,"dynamicHeight":"AUTO_HEIGHT","widgetId":"kekx3o71p4","canOutsideClickClose":true,"canEscapeKeyClose":true,"version":2.0,"parentId":"0","renderMode":"CANVAS","isLoading":false,"mobileTopRow":46.0,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":11.0,"maxDynamicHeight":9000.0,"width":692.0,"minDynamicHeight":24.0},{"boxShadow":"none","mobileBottomRow":70.0,"widgetName":"ModalTypebot","isCanvas":true,"displayName":"Modal","iconSVG":"/static/media/icon.d2ab7de0666eaef853cc2d330f86887b.svg","searchTags":["dialog","popup","notification"],"topRow":45.0,"bottomRow":775.0,"parentRowSpace":10.0,"type":"MODAL_WIDGET","hideCard":false,"shouldScrollContents":true,"mobileRightColumn":35.0,"minHeight":730.0,"animateLoading":true,"parentColumnSpace":17.9375,"leftColumn":11.0,"dynamicBindingPathList":[{"key":"borderRadius"}],"children":[{"mobileBottomRow":240.0,"widgetName":"Canvas4CopyCopyCopy","displayName":"Canvas","topRow":0.0,"bottomRow":730.0,"parentRowSpace":1.0,"type":"CANVAS_WIDGET","canExtend":true,"hideCard":true,"shouldScrollContents":false,"minHeight":730.0,"mobileRightColumn":430.5,"parentColumnSpace":1.0,"leftColumn":0.0,"dynamicBindingPathList":[],"children":[{"boxShadow":"none","borderColor":"#E0DEDE","iconSVG":"/static/media/icon.efac588608711d232f1c6c8a2144d2dd.svg","onSubmit":"{{Set_Typebot.run().then(() => {\n showAlert('Typebot updated successfully', 'success');\n}).catch(() => {\n showAlert('Error updating Typebot', 'error');\n});\ncloseModal('ModalTypebot');}}","topRow":1.0,"type":"JSON_FORM_WIDGET","animateLoading":true,"leftColumn":0.0,"dynamicBindingPathList":[{"key":"borderRadius"},{"key":"schema.__root_schema__.defaultValue"},{"key":"schema.__root_schema__.borderRadius"},{"key":"submitButtonStyles.buttonColor"},{"key":"schema.__root_schema__.cellBorderRadius"},{"key":"sourceData"},{"key":"schema.__root_schema__.children.enabled.defaultValue"},{"key":"schema.__root_schema__.children.enabled.accentColor"},{"key":"schema.__root_schema__.children.url.defaultValue"},{"key":"schema.__root_schema__.children.url.accentColor"},{"key":"schema.__root_schema__.children.url.borderRadius"},{"key":"schema.__root_schema__.children.typebot.defaultValue"},{"key":"schema.__root_schema__.children.typebot.accentColor"},{"key":"schema.__root_schema__.children.typebot.borderRadius"},{"key":"schema.__root_schema__.children.expire.defaultValue"},{"key":"schema.__root_schema__.children.expire.accentColor"},{"key":"schema.__root_schema__.children.expire.borderRadius"},{"key":"schema.__root_schema__.children.keyword_finish.defaultValue"},{"key":"schema.__root_schema__.children.keyword_finish.accentColor"},{"key":"schema.__root_schema__.children.keyword_finish.borderRadius"},{"key":"schema.__root_schema__.children.delay_message.defaultValue"},{"key":"schema.__root_schema__.children.delay_message.accentColor"},{"key":"schema.__root_schema__.children.delay_message.borderRadius"},{"key":"schema.__root_schema__.children.unknown_message.defaultValue"},{"key":"schema.__root_schema__.children.unknown_message.accentColor"},{"key":"schema.__root_schema__.children.unknown_message.borderRadius"},{"key":"schema.__root_schema__.children.listening_from_me.defaultValue"},{"key":"schema.__root_schema__.children.listening_from_me.accentColor"}],"showReset":false,"dynamicHeight":"AUTO_HEIGHT","autoGenerateForm":true,"resetButtonStyles":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","buttonVariant":"SECONDARY"},"isVisible":true,"version":1.0,"isLoading":false,"submitButtonLabel":"Save","childStylesheet":{"ARRAY":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","cellBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","cellBoxShadow":"none"},"OBJECT":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","cellBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","cellBoxShadow":"none"},"CHECKBOX":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}"},"CURRENCY_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"DATEPICKER":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"EMAIL_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTISELECT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTILINE_TEXT_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"NUMBER_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PASSWORD_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PHONE_NUMBER_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"RADIO_GROUP":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"SELECT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"SWITCH":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"TEXT_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"}},"disabledWhenInvalid":true,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","originalBottomRow":71.0,"useSourceData":false,"schema":{"__root_schema__":{"children":{"enabled":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.enabled))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","fieldType":"Switch","sourceData":true,"isCustomField":false,"accessor":"enabled","identifier":"enabled","position":0.0,"originalIdentifier":"enabled","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Enabled"},"url":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.url))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","fieldType":"Text Input","sourceData":"https://bot.typebot.com","isCustomField":false,"accessor":"url","identifier":"url","position":1.0,"originalIdentifier":"url","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Url"},"typebot":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.typebot))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","fieldType":"Text Input","sourceData":"felipe-final-sbkaa3s","isCustomField":false,"accessor":"typebot","identifier":"typebot","position":2.0,"originalIdentifier":"typebot","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Typebot"},"expire":{"children":{},"dataType":"number","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.expire))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","fieldType":"Number Input","sourceData":45.0,"isCustomField":false,"accessor":"expire","identifier":"expire","position":3.0,"originalIdentifier":"expire","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Expire"},"keyword_finish":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.keyword_finish))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","fieldType":"Text Input","sourceData":"#SAIR","isCustomField":false,"accessor":"keyword_finish","identifier":"keyword_finish","position":4.0,"originalIdentifier":"keyword_finish","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Keyword Finish"},"delay_message":{"children":{},"dataType":"number","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.delay_message))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","fieldType":"Number Input","sourceData":2000.0,"isCustomField":false,"accessor":"delay_message","identifier":"delay_message","position":5.0,"originalIdentifier":"delay_message","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Delay Message"},"unknown_message":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.unknown_message))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","fieldType":"Text Input","sourceData":"","isCustomField":false,"accessor":"unknown_message","identifier":"unknown_message","position":6.0,"originalIdentifier":"unknown_message","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Unknown Message"},"listening_from_me":{"children":{},"dataType":"boolean","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.listening_from_me))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","fieldType":"Switch","sourceData":false,"isCustomField":false,"accessor":"listening_from_me","identifier":"listening_from_me","position":7.0,"originalIdentifier":"listening_from_me","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","boxShadow":"none","alignWidget":"LEFT","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Listening From Me"}},"dataType":"object","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","fieldType":"Object","sourceData":{"enabled":true,"url":"https://bot.typebot.com","typebot":"bot-typebot","expire":20.0,"keyword_finish":"#SAIR","delay_message":3000.0,"unknown_message":"Mensagem não reconhecida2"},"isCustomField":false,"accessor":"__root_schema__","identifier":"__root_schema__","position":-1.0,"originalIdentifier":"__root_schema__","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","boxShadow":"none","cellBorderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","cellBoxShadow":"none","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":""}},"mobileBottomRow":41.0,"widgetName":"FormTypebot","submitButtonStyles":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","buttonVariant":"PRIMARY"},"dynamicPropertyPathList":[{"key":"schema.__root_schema__.children.sign_msg.defaultValue"},{"key":"schema.__root_schema__.children.reopen_conversation.defaultValue"},{"key":"schema.__root_schema__.children.conversation_pending.defaultValue"},{"key":"schema.__root_schema__.children.account_id.defaultValue"},{"key":"schema.__root_schema__.children.webhook_url.defaultValue"},{"key":"schema.__root_schema__.children.enabled.defaultValue"},{"key":"schema.__root_schema__.children.listening_from_me.defaultValue"}],"displayName":"JSON Form","bottomRow":71.0,"fieldLimitExceeded":false,"parentRowSpace":10.0,"title":"Set Typebot","hideCard":false,"mobileRightColumn":25.0,"parentColumnSpace":6.9375,"dynamicTriggerPathList":[{"key":"onSubmit"}],"borderWidth":"0","sourceData":"{\n \"enabled\": {{Find_Typebot.data.enabled || false}},\n \"url\": {{Find_Typebot.data.url}},\n \"typebot\": {{Find_Typebot.data.typebot}},\n \"expire\": {{Find_Typebot.data.expire}},\n \"keyword_finish\": {{Find_Typebot.data.keyword_finish}},\n \"delay_message\": {{Find_Typebot.data.delay_message}},\n \"unknown_message\": {{Find_Typebot.data.unknown_message}},\n \"listening_from_me\": {{Find_Typebot.data.listening_from_me}}\n \n}","resetButtonLabel":"Reset","key":"lgqqk5r1jk","backgroundColor":"#fff","isDeprecated":false,"rightColumn":63.0,"widgetId":"fyu0oxvlx7","minWidth":450.0,"parentId":"bvxewkusbf","renderMode":"CANVAS","mobileTopRow":0.0,"scrollContents":true,"responsiveBehavior":"fill","fixedFooter":true,"originalTopRow":1.0,"mobileLeftColumn":0.0,"maxDynamicHeight":9000.0,"minDynamicHeight":4.0}],"isDisabled":false,"key":"svq68rvpdn","isDeprecated":false,"rightColumn":430.5,"detachFromLayout":true,"widgetId":"bvxewkusbf","minWidth":450.0,"isVisible":true,"version":1.0,"parentId":"4n3m0wo9tx","renderMode":"CANVAS","isLoading":false,"mobileTopRow":0.0,"responsiveBehavior":"fill","mobileLeftColumn":0.0,"flexLayers":[]}],"key":"6x3z5yow7u","height":730.0,"isDeprecated":false,"rightColumn":35.0,"detachFromLayout":true,"dynamicHeight":"AUTO_HEIGHT","widgetId":"4n3m0wo9tx","canOutsideClickClose":true,"canEscapeKeyClose":true,"version":2.0,"parentId":"0","renderMode":"CANVAS","isLoading":false,"mobileTopRow":46.0,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":11.0,"maxDynamicHeight":9000.0,"width":692.0,"minDynamicHeight":24.0},{"boxShadow":"none","mobileBottomRow":70.0,"widgetName":"ModalTypebotChangeSessionStatu","isCanvas":true,"displayName":"Modal","iconSVG":"/static/media/icon.d2ab7de0666eaef853cc2d330f86887b.svg","searchTags":["dialog","popup","notification"],"topRow":45.0,"bottomRow":415.0,"parentRowSpace":10.0,"type":"MODAL_WIDGET","hideCard":false,"shouldScrollContents":true,"mobileRightColumn":35.0,"minHeight":370.0,"animateLoading":true,"parentColumnSpace":17.9375,"leftColumn":11.0,"dynamicBindingPathList":[{"key":"borderRadius"}],"children":[{"mobileBottomRow":240.0,"widgetName":"Canvas4CopyCopyCopyCopy","displayName":"Canvas","topRow":0.0,"bottomRow":370.0,"parentRowSpace":1.0,"type":"CANVAS_WIDGET","canExtend":true,"hideCard":true,"shouldScrollContents":false,"minHeight":730.0,"mobileRightColumn":430.5,"parentColumnSpace":1.0,"leftColumn":0.0,"dynamicBindingPathList":[],"children":[{"boxShadow":"none","borderColor":"#E0DEDE","iconSVG":"/static/media/icon.efac588608711d232f1c6c8a2144d2dd.svg","onSubmit":"{{Set_TypebotChangeSessionStatus.run().then(() => {\n showAlert('Typebot Change Session updated successfully', 'success');\n}).catch(() => {\n showAlert('Error updating Session Typebot', 'error');\n});\ncloseModal('ModalTypebotChangeSessionStatu');}}","topRow":1.0,"type":"JSON_FORM_WIDGET","animateLoading":true,"leftColumn":0.0,"dynamicBindingPathList":[{"key":"borderRadius"},{"key":"schema.__root_schema__.defaultValue"},{"key":"schema.__root_schema__.borderRadius"},{"key":"submitButtonStyles.buttonColor"},{"key":"schema.__root_schema__.cellBorderRadius"},{"key":"schema.__root_schema__.children.remoteJid.defaultValue"},{"key":"schema.__root_schema__.children.remoteJid.accentColor"},{"key":"schema.__root_schema__.children.remoteJid.borderRadius"},{"key":"schema.__root_schema__.children.status.defaultValue"},{"key":"schema.__root_schema__.children.status.accentColor"},{"key":"schema.__root_schema__.children.status.borderRadius"}],"showReset":false,"dynamicHeight":"AUTO_HEIGHT","autoGenerateForm":true,"resetButtonStyles":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","buttonVariant":"SECONDARY"},"isVisible":true,"version":1.0,"isLoading":false,"submitButtonLabel":"Save","childStylesheet":{"ARRAY":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","cellBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","cellBoxShadow":"none"},"OBJECT":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","cellBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","cellBoxShadow":"none"},"CHECKBOX":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}"},"CURRENCY_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"DATEPICKER":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"EMAIL_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTISELECT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTILINE_TEXT_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"NUMBER_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PASSWORD_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PHONE_NUMBER_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"RADIO_GROUP":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"SELECT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"SWITCH":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"TEXT_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"}},"disabledWhenInvalid":true,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","originalBottomRow":35.0,"useSourceData":false,"schema":{"__root_schema__":{"children":{"remoteJid":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.remoteJid))(FormTypebotChangeSessionStatus.sourceData, FormTypebotChangeSessionStatus.formData, FormTypebotChangeSessionStatus.fieldState)}}","fieldType":"Text Input","sourceData":"","isCustomField":false,"accessor":"remoteJid","identifier":"remoteJid","position":0.0,"originalIdentifier":"remoteJid","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormTypebotChangeSessionStatus.sourceData, FormTypebotChangeSessionStatus.formData, FormTypebotChangeSessionStatus.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormTypebotChangeSessionStatus.sourceData, FormTypebotChangeSessionStatus.formData, FormTypebotChangeSessionStatus.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":true,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Remote Jid (WhatsApp. Ex: 5511968162699@s.whatsapp.net)"},"status":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.status))(FormTypebotChangeSessionStatus.sourceData, FormTypebotChangeSessionStatus.formData, FormTypebotChangeSessionStatus.fieldState)}}","fieldType":"Text Input","sourceData":"","isCustomField":false,"accessor":"status","identifier":"status","position":1.0,"originalIdentifier":"status","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormTypebotChangeSessionStatus.sourceData, FormTypebotChangeSessionStatus.formData, FormTypebotChangeSessionStatus.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormTypebotChangeSessionStatus.sourceData, FormTypebotChangeSessionStatus.formData, FormTypebotChangeSessionStatus.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Status (opened, paused or closed)"}},"dataType":"object","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","fieldType":"Object","sourceData":{"enabled":true,"url":"https://bot.typebot.com","typebot":"bot-typebot","expire":20.0,"keyword_finish":"#SAIR","delay_message":3000.0,"unknown_message":"Mensagem não reconhecida2"},"isCustomField":false,"accessor":"__root_schema__","identifier":"__root_schema__","position":-1.0,"originalIdentifier":"__root_schema__","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","boxShadow":"none","cellBorderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormTypebot.sourceData, FormTypebot.formData, FormTypebot.fieldState)}}","cellBoxShadow":"none","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":""}},"mobileBottomRow":41.0,"widgetName":"FormTypebotChangeSessionStatus","submitButtonStyles":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","buttonVariant":"PRIMARY"},"dynamicPropertyPathList":[{"key":"schema.__root_schema__.children.sign_msg.defaultValue"},{"key":"schema.__root_schema__.children.reopen_conversation.defaultValue"},{"key":"schema.__root_schema__.children.conversation_pending.defaultValue"},{"key":"schema.__root_schema__.children.account_id.defaultValue"},{"key":"schema.__root_schema__.children.webhook_url.defaultValue"}],"displayName":"JSON Form","bottomRow":35.0,"fieldLimitExceeded":false,"parentRowSpace":10.0,"title":"Typebot Change Session Status","hideCard":false,"mobileRightColumn":25.0,"parentColumnSpace":6.9375,"dynamicTriggerPathList":[{"key":"onSubmit"}],"borderWidth":"0","sourceData":"{\n \"remoteJid\": \"@s.whatsapp.net\",\n \"status\": \"\"\n}","resetButtonLabel":"Reset","key":"lgqqk5r1jk","backgroundColor":"#fff","isDeprecated":false,"rightColumn":63.0,"widgetId":"28lli5jdvr","minWidth":450.0,"parentId":"8m0yhclt7g","renderMode":"CANVAS","mobileTopRow":0.0,"scrollContents":true,"responsiveBehavior":"fill","fixedFooter":true,"originalTopRow":1.0,"mobileLeftColumn":0.0,"maxDynamicHeight":9000.0,"minDynamicHeight":4.0}],"isDisabled":false,"key":"svq68rvpdn","isDeprecated":false,"rightColumn":430.5,"detachFromLayout":true,"widgetId":"8m0yhclt7g","minWidth":450.0,"isVisible":true,"version":1.0,"parentId":"84rj87eew6","renderMode":"CANVAS","isLoading":false,"mobileTopRow":0.0,"responsiveBehavior":"fill","mobileLeftColumn":0.0,"flexLayers":[]}],"key":"6x3z5yow7u","height":370.0,"isDeprecated":false,"rightColumn":35.0,"detachFromLayout":true,"dynamicHeight":"AUTO_HEIGHT","widgetId":"84rj87eew6","canOutsideClickClose":true,"canEscapeKeyClose":true,"version":2.0,"parentId":"0","renderMode":"CANVAS","isLoading":false,"mobileTopRow":46.0,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":11.0,"maxDynamicHeight":9000.0,"width":692.0,"minDynamicHeight":24.0},{"resetFormOnClick":false,"boxShadow":"none","mobileBottomRow":50.0,"widgetName":"Button2","onClick":"{{Fetch_Instance.run();\nFetch_PrivacySettings.run();\nshowModal('ModalProfile');}}","buttonColor":"#2770fc","dynamicPropertyPathList":[{"key":"isVisible"}],"displayName":"Button","iconSVG":"/static/media/icon.7beb9123fb53027d9d6b778cdfe4caed.svg","searchTags":["click","submit"],"topRow":28.0,"bottomRow":32.0,"parentRowSpace":10.0,"type":"BUTTON_WIDGET","hideCard":false,"mobileRightColumn":21.0,"animateLoading":true,"parentColumnSpace":17.9375,"dynamicTriggerPathList":[{"key":"onClick"}],"leftColumn":1.0,"dynamicBindingPathList":[{"key":"borderRadius"},{"key":"isVisible"}],"text":"Edit Profile","isDisabled":false,"key":"zhd9fobc1z","isDeprecated":false,"rightColumn":13.0,"isDefaultClickDisabled":true,"iconName":"edit","widgetId":"uh6430ysqy","minWidth":120.0,"isVisible":"{{appsmith.store.api_key && appsmith.store.api_url ? TableInstances.selectedRow.instance ? TableInstances.selectedRow.Status === 'open' ? true : false : false : false}}","recaptchaType":"V3","version":1.0,"parentId":"0","renderMode":"CANVAS","isLoading":false,"mobileTopRow":46.0,"responsiveBehavior":"hug","originalTopRow":51.0,"disabledWhenInvalid":false,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":5.0,"originalBottomRow":55.0,"buttonVariant":"PRIMARY","iconAlign":"left","placement":"CENTER"},{"boxShadow":"none","mobileBottomRow":59.0,"widgetName":"ModalProfile","isCanvas":true,"displayName":"Modal","iconSVG":"/static/media/icon.d2ab7de0666eaef853cc2d330f86887b.svg","searchTags":["dialog","popup","notification"],"topRow":35.0,"bottomRow":975.0,"parentRowSpace":10.0,"type":"MODAL_WIDGET","hideCard":false,"shouldScrollContents":true,"mobileRightColumn":35.0,"minHeight":940.0,"animateLoading":true,"parentColumnSpace":17.9375,"leftColumn":11.0,"dynamicBindingPathList":[{"key":"borderRadius"}],"children":[{"mobileBottomRow":240.0,"widgetName":"Canvas5","displayName":"Canvas","topRow":0.0,"bottomRow":940.0,"parentRowSpace":1.0,"type":"CANVAS_WIDGET","canExtend":true,"hideCard":true,"shouldScrollContents":false,"minHeight":240.0,"mobileRightColumn":430.5,"parentColumnSpace":1.0,"leftColumn":0.0,"dynamicBindingPathList":[],"children":[{"boxShadow":"none","borderColor":"#E0DEDE","iconSVG":"/static/media/icon.efac588608711d232f1c6c8a2144d2dd.svg","onSubmit":"{{Update_ProfileName.run().then(() => {\n showAlert('ProfileName successfully saved!', 'success');\n}).catch(() => {\n showAlert('Error updating ProfileName', 'error');\n});\nUpdate_ProfilePicture.run().then(() => {\n showAlert('ProfilePicture successfully saved!', 'success');\n}).catch(() => {\n showAlert('Error updating ProfilePicture', 'error');\n});\nUpdate_ProfileStatus.run().then(() => {\n showAlert('ProfileStatus successfully saved!', 'success');\n}).catch(() => {\n showAlert('Error updating ProfileStatus', 'error');\n});\nUpdate_PrivacySettings.run().then(() => {\n showAlert('PrivacySttings successfully saved!', 'success');\n}).catch(() => {\n showAlert('Error updating PrivacySttings', 'error');\n});\nfetch_Instances.run();\ncloseModal('ModalProfile');}}","topRow":0.0,"type":"JSON_FORM_WIDGET","animateLoading":true,"leftColumn":0.0,"dynamicBindingPathList":[{"key":"borderRadius"},{"key":"submitButtonStyles.buttonColor"},{"key":"submitButtonStyles.borderRadius"},{"key":"resetButtonStyles.buttonColor"},{"key":"resetButtonStyles.borderRadius"},{"key":"schema.__root_schema__.defaultValue"},{"key":"schema.__root_schema__.borderRadius"},{"key":"schema.__root_schema__.cellBorderRadius"},{"key":"schema.__root_schema__.children.profileName.defaultValue"},{"key":"schema.__root_schema__.children.profileName.accentColor"},{"key":"schema.__root_schema__.children.profileName.borderRadius"},{"key":"schema.__root_schema__.children.profileStatus.defaultValue"},{"key":"schema.__root_schema__.children.profileStatus.accentColor"},{"key":"schema.__root_schema__.children.profileStatus.borderRadius"},{"key":"schema.__root_schema__.children.profilePictureUrl.defaultValue"},{"key":"schema.__root_schema__.children.profilePictureUrl.borderRadius"},{"key":"sourceData"},{"key":"schema.__root_schema__.children.profilePictureUrl.accentColor"},{"key":"schema.__root_schema__.children.privacySettings.children.readreceipts.defaultValue"},{"key":"schema.__root_schema__.children.privacySettings.children.readreceipts.accentColor"},{"key":"schema.__root_schema__.children.privacySettings.children.readreceipts.borderRadius"},{"key":"schema.__root_schema__.children.privacySettings.children.profile.defaultValue"},{"key":"schema.__root_schema__.children.privacySettings.children.profile.accentColor"},{"key":"schema.__root_schema__.children.privacySettings.children.profile.borderRadius"},{"key":"schema.__root_schema__.children.privacySettings.children.status.defaultValue"},{"key":"schema.__root_schema__.children.privacySettings.children.status.accentColor"},{"key":"schema.__root_schema__.children.privacySettings.children.status.borderRadius"},{"key":"schema.__root_schema__.children.privacySettings.children.online.defaultValue"},{"key":"schema.__root_schema__.children.privacySettings.children.online.accentColor"},{"key":"schema.__root_schema__.children.privacySettings.children.online.borderRadius"},{"key":"schema.__root_schema__.children.privacySettings.children.last.defaultValue"},{"key":"schema.__root_schema__.children.privacySettings.children.last.accentColor"},{"key":"schema.__root_schema__.children.privacySettings.children.last.borderRadius"},{"key":"schema.__root_schema__.children.privacySettings.children.groupadd.defaultValue"},{"key":"schema.__root_schema__.children.privacySettings.children.groupadd.accentColor"},{"key":"schema.__root_schema__.children.privacySettings.children.groupadd.borderRadius"},{"key":"schema.__root_schema__.children.privacySettings.defaultValue"},{"key":"schema.__root_schema__.children.privacySettings.borderRadius"},{"key":"schema.__root_schema__.children.privacySettings.cellBorderRadius"}],"showReset":false,"dynamicHeight":"AUTO_HEIGHT","autoGenerateForm":true,"resetButtonStyles":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","buttonVariant":"SECONDARY"},"isVisible":true,"version":1.0,"isLoading":false,"submitButtonLabel":"Save","childStylesheet":{"ARRAY":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","cellBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","cellBoxShadow":"none"},"OBJECT":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","cellBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","cellBoxShadow":"none"},"CHECKBOX":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}"},"CURRENCY_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"DATEPICKER":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"EMAIL_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTISELECT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTILINE_TEXT_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"NUMBER_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PASSWORD_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PHONE_NUMBER_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"RADIO_GROUP":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"SELECT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"SWITCH":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"TEXT_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"}},"disabledWhenInvalid":true,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","originalBottomRow":92.0,"useSourceData":false,"schema":{"__root_schema__":{"children":{"profileName":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.profileName))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","fieldType":"Text Input","sourceData":"","isCustomField":false,"accessor":"profileName","identifier":"profileName","position":1.0,"originalIdentifier":"profileName","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Profile Name"},"profileStatus":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.profileStatus))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","fieldType":"Text Input","sourceData":"","isCustomField":false,"accessor":"profileStatus","identifier":"profileStatus","position":2.0,"originalIdentifier":"profileStatus","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Profile Status"},"profilePictureUrl":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.profilePictureUrl))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","fieldType":"Text Input","sourceData":"https://pps.whatsapp.net/v/t61.24694-24/359816109_329991892684302_7466658594467953893_n.jpg?ccb=11-4&oh=01_AdTpgc4O-xiZDr2v0OLu_jssxaw8dsws819srLMOzUwEnw&oe=64D3C41E","isCustomField":false,"accessor":"profilePictureUrl","identifier":"profilePictureUrl","position":0.0,"originalIdentifier":"profilePictureUrl","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","boxShadow":"none","iconAlign":"left","isDisabled":false,"isRequired":false,"isSpellCheck":false,"isVisible":true,"labelTextSize":"0.875rem","label":"Profile Picture Url"},"privacySettings":{"children":{"readreceipts":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.privacySettings.readreceipts))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","fieldType":"Select","sourceData":"all","isCustomField":false,"accessor":"readreceipts","identifier":"readreceipts","position":0.0,"originalIdentifier":"readreceipts","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","boxShadow":"none","isDisabled":false,"isFilterable":false,"isRequired":false,"isVisible":true,"label":"Readreceipts","labelTextSize":"0.875rem","serverSideFiltering":false,"options":"[\n {\n \"label\": \"all\",\n \"value\": \"all\"\n },\n {\n \"label\": \"none\",\n \"value\": \"none\"\n }\n]"},"profile":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.privacySettings.profile))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","fieldType":"Select","sourceData":"all","isCustomField":false,"accessor":"profile","identifier":"profile","position":1.0,"originalIdentifier":"profile","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","boxShadow":"none","isDisabled":false,"isFilterable":false,"isRequired":false,"isVisible":true,"label":"Profile","labelTextSize":"0.875rem","serverSideFiltering":false,"options":"[\n {\n \"label\": \"all\",\n \"value\": \"all\"\n },\n {\n \"label\": \"contacts\",\n \"value\": \"contacts\"\n },\n {\n \"label\": \"contact_blacklist\",\n \"value\": \"contact_blacklist\"\n },\n {\n \"label\": \"none\",\n \"value\": \"none\"\n }\n]"},"status":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.privacySettings.status))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","fieldType":"Select","sourceData":"contacts","isCustomField":false,"accessor":"status","identifier":"status","position":2.0,"originalIdentifier":"status","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","boxShadow":"none","isDisabled":false,"isFilterable":false,"isRequired":false,"isVisible":true,"label":"Status","labelTextSize":"0.875rem","serverSideFiltering":false,"options":"[\n {\n \"label\": \"all\",\n \"value\": \"all\"\n },\n {\n \"label\": \"contacts\",\n \"value\": \"contacts\"\n },\n {\n \"label\": \"contact_blacklist\",\n \"value\": \"contact_blacklist\"\n },\n {\n \"label\": \"none\",\n \"value\": \"none\"\n }\n]"},"online":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.privacySettings.online))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","fieldType":"Select","sourceData":"all","isCustomField":false,"accessor":"online","identifier":"online","position":3.0,"originalIdentifier":"online","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","boxShadow":"none","isDisabled":false,"isFilterable":false,"isRequired":false,"isVisible":true,"label":"Online","labelTextSize":"0.875rem","serverSideFiltering":false,"options":"[\n {\n \"label\": \"all\",\n \"value\": \"all\"\n },\n {\n \"label\": \"match_last_seen\",\n \"value\": \"match_last_seen\"\n }\n]"},"last":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.privacySettings.last))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","fieldType":"Select","sourceData":"contacts","isCustomField":false,"accessor":"last","identifier":"last","position":4.0,"originalIdentifier":"last","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","boxShadow":"none","isDisabled":false,"isFilterable":false,"isRequired":false,"isVisible":true,"label":"Last","labelTextSize":"0.875rem","serverSideFiltering":false,"options":"[\n {\n \"label\": \"all\",\n \"value\": \"all\"\n },\n {\n \"label\": \"contacts\",\n \"value\": \"contacts\"\n },\n {\n \"label\": \"contact_blacklist\",\n \"value\": \"contact_blacklist\"\n },\n {\n \"label\": \"none\",\n \"value\": \"none\"\n }\n]"},"groupadd":{"children":{},"dataType":"string","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.privacySettings.groupadd))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","fieldType":"Select","sourceData":"all","isCustomField":false,"accessor":"groupadd","identifier":"groupadd","position":5.0,"originalIdentifier":"groupadd","accentColor":"{{((sourceData, formData, fieldState) => ((appsmith.theme.colors.primaryColor)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","boxShadow":"none","isDisabled":false,"isFilterable":false,"isRequired":false,"isVisible":true,"label":"Groupadd","labelTextSize":"0.875rem","serverSideFiltering":false,"options":"[\n {\n \"label\": \"all\",\n \"value\": \"all\"\n },\n {\n \"label\": \"contacts\",\n \"value\": \"contacts\"\n },\n {\n \"label\": \"contact_blacklist\",\n \"value\": \"contact_blacklist\"\n },\n {\n \"label\": \"none\",\n \"value\": \"none\"\n }\n]"}},"dataType":"object","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData.privacySettings))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","fieldType":"Object","sourceData":{"readreceipts":"all","profile":"all","status":"contacts","online":"all","last":"contacts","groupadd":"all"},"isCustomField":false,"accessor":"privacySettings","identifier":"privacySettings","position":3.0,"originalIdentifier":"privacySettings","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","boxShadow":"none","cellBorderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","cellBoxShadow":"none","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"1rem","label":"Privacy Settings","labelStyle":"BOLD"}},"dataType":"object","defaultValue":"{{((sourceData, formData, fieldState) => (sourceData))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","fieldType":"Object","sourceData":{"name":"John","date_of_birth":"20/02/1990","employee_id":1001.0},"isCustomField":false,"accessor":"__root_schema__","identifier":"__root_schema__","position":-1.0,"originalIdentifier":"__root_schema__","borderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","boxShadow":"none","cellBorderRadius":"{{((sourceData, formData, fieldState) => ((appsmith.theme.borderRadius.appBorderRadius)))(FormProfile.sourceData, FormProfile.formData, FormProfile.fieldState)}}","cellBoxShadow":"none","isDisabled":false,"isRequired":false,"isVisible":true,"labelTextSize":"0.875rem","label":""}},"mobileBottomRow":41.0,"widgetName":"FormProfile","submitButtonStyles":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","buttonVariant":"PRIMARY"},"dynamicPropertyPathList":[],"displayName":"JSON Form","bottomRow":92.0,"fieldLimitExceeded":false,"parentRowSpace":10.0,"title":"Edit Profile","hideCard":false,"mobileRightColumn":25.0,"parentColumnSpace":6.9375,"dynamicTriggerPathList":[{"key":"onSubmit"}],"borderWidth":"0","sourceData":"{\n\t\"profilePictureUrl\": \"{{Fetch_Instance.data.instance.profilePictureUrl}}\",\n\t\"profileName\": \"{{Fetch_Instance.data.instance.profileName}}\",\n\t\"profileStatus\": \"{{Fetch_Instance.data.instance.profileStatus}}\",\n\t\"privacySettings\": {\n \"readreceipts\": {{Fetch_PrivacySettings.data.readreceipts}},\n \"profile\": {{Fetch_PrivacySettings.data.profile}},\n \"status\": {{Fetch_PrivacySettings.data.status}},\n \"online\": {{Fetch_PrivacySettings.data.online}},\n \"last\": {{Fetch_PrivacySettings.data.last}},\n \"groupadd\": {{Fetch_PrivacySettings.data.groupadd}}\n\t\t}\n}","resetButtonLabel":"","key":"72nqor459k","backgroundColor":"#fff","isDeprecated":false,"rightColumn":64.0,"widgetId":"hguxefink2","minWidth":450.0,"parentId":"basosxf5qt","renderMode":"CANVAS","mobileTopRow":0.0,"scrollContents":true,"responsiveBehavior":"fill","fixedFooter":true,"originalTopRow":0.0,"mobileLeftColumn":0.0,"maxDynamicHeight":9000.0,"minDynamicHeight":4.0}],"isDisabled":false,"key":"mepf0qsn1e","isDeprecated":false,"rightColumn":430.5,"detachFromLayout":true,"widgetId":"basosxf5qt","minWidth":450.0,"isVisible":true,"version":1.0,"parentId":"ss96aihlej","renderMode":"CANVAS","isLoading":false,"mobileTopRow":0.0,"responsiveBehavior":"fill","mobileLeftColumn":0.0,"flexLayers":[]}],"key":"4ktj7iym0b","height":940.0,"isDeprecated":false,"rightColumn":35.0,"detachFromLayout":true,"dynamicHeight":"AUTO_HEIGHT","widgetId":"ss96aihlej","canOutsideClickClose":true,"canEscapeKeyClose":true,"version":2.0,"parentId":"0","renderMode":"CANVAS","isLoading":false,"mobileTopRow":35.0,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":11.0,"maxDynamicHeight":9000.0,"width":456.0,"minDynamicHeight":24.0},{"mobileBottomRow":47.0,"widgetName":"Text6","displayName":"Text","iconSVG":"/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg","searchTags":["typography","paragraph","label"],"topRow":43.0,"bottomRow":47.0,"parentRowSpace":10.0,"type":"TEXT_WIDGET","hideCard":false,"mobileRightColumn":31.0,"animateLoading":true,"overflow":"NONE","fontFamily":"{{appsmith.theme.fontFamily.appFont}}","parentColumnSpace":12.3125,"dynamicTriggerPathList":[],"leftColumn":15.0,"dynamicBindingPathList":[{"key":"truncateButtonColor"},{"key":"fontFamily"},{"key":"borderRadius"}],"shouldTruncate":false,"truncateButtonColor":"{{appsmith.theme.colors.primaryColor}}","text":"This evolution api instance management panel is compatible from version 1.5 or higher\n","key":"vpoi1p6qvn","isDeprecated":false,"rightColumn":63.0,"textAlign":"LEFT","dynamicHeight":"AUTO_HEIGHT","widgetId":"yfenuu2x36","minWidth":450.0,"isVisible":true,"fontStyle":"BOLD","textColor":"#ef4444","version":1.0,"parentId":"0","tags":["Suggested","Content"],"renderMode":"CANVAS","isLoading":false,"mobileTopRow":43.0,"responsiveBehavior":"fill","originalTopRow":43.0,"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","mobileLeftColumn":15.0,"maxDynamicHeight":9000.0,"originalBottomRow":48.0,"fontSize":"0.875rem","minDynamicHeight":4.0}]},"layoutOnLoadActions":[[{"id":"Home_Scripts.verifyConfig","name":"Scripts.verifyConfig","collectionId":"Home_Scripts","clientSideExecution":true,"confirmBeforeExecute":false,"pluginType":"JS","jsonPathKeys":[],"timeoutInMillisecond":10000.0}],[{"id":"Home_Find_Rabbitmq","name":"Find_Rabbitmq","confirmBeforeExecute":false,"pluginType":"API","jsonPathKeys":["TableInstances.selectedRow.Apikey","encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url"],"timeoutInMillisecond":10000.0},{"id":"Home_Find_Websocket","name":"Find_Websocket","confirmBeforeExecute":false,"pluginType":"API","jsonPathKeys":["TableInstances.selectedRow.Apikey","encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url"],"timeoutInMillisecond":10000.0}]],"layoutOnLoadActionErrors":[],"validOnPageLoadActions":true,"id":"Home","deleted":false,"policies":[],"userPermissions":[]}],"userPermissions":[],"policies":[],"isHidden":false},"deleted":false,"gitSyncId":"64e0b37fa2945b083c5bc7ac_64e0b37fa2945b083c5bc7b0"}],"actionList":[{"pluginType":"API","pluginId":"restapi-plugin","unpublishedAction":{"name":"Restart","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/instance/restart/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{appsmith.store.api_key}}"}],"autoGeneratedHeaders":[{"key":"content-type","value":"application/json"}],"encodeParamsToggle":true,"queryParameters":[],"body":"","bodyFormData":[],"httpMethod":"PUT","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url","appsmith.store.api_key"],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-07-30T03:01:05Z"},"publishedAction":{"name":"Restart","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/instance/restart/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{appsmith.store.api_key}}"}],"autoGeneratedHeaders":[{"key":"content-type","value":"application/json"}],"encodeParamsToggle":true,"queryParameters":[],"body":"","bodyFormData":[],"httpMethod":"PUT","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url","appsmith.store.api_key"],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-07-30T03:01:05Z"},"id":"Home_Restart","deleted":false,"gitSyncId":"64e0b37fa2945b083c5bc7ac_64e0b37fa2945b083c5bc7b4"},{"pluginType":"API","pluginId":"restapi-plugin","unpublishedAction":{"name":"Create_Instance","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/instance/create","headers":[{"key":"apikey","value":"{{appsmith.store.api_key}}"}],"autoGeneratedHeaders":[{"key":"content-type","value":"application/json"}],"encodeParamsToggle":true,"queryParameters":[],"body":"{{\n\t{\n\t\t\"instanceName\": FormInstance.formData.instance.instanceName,\n\t\t\"token\": FormInstance.formData.instance.token,\n\t\t\"qrcode\": FormInstance.formData.instance.qrcode,\n\t\t\"webhook\": FormInstance.formData.webhook.webhook,\n\t\t\"webhook_by_events\": FormInstance.formData.webhook.webhook_by_events,\n\t\t\"websocket_enabled\": FormInstance.formData.websocket.websocket_enabled,\n\t\t\"websocket_events\": FormInstance.formData.websocket.websocket_events,\n\t\t\"rabbitmq_enabled\": FormInstance.formData.websocket.rabbitmq_enabled,\n\t\t\"rabbitmq_events\": FormInstance.formData.websocket.rabbitmq_events,\n\t\t\"events\": FormInstance.formData.webhook.events,\n\t\t\"reject_call\": FormInstance.formData.settings.reject_call,\n\t\t\"msg_call\": FormInstance.formData.settings.msg_call,\n\t\t\"groups_ignore\": FormInstance.formData.settings.groups_ignore,\n\t\t\"always_online\": FormInstance.formData.settings.always_online,\n\t\t\"read_messages\": FormInstance.formData.settings.read_messages,\n\t\t\"read_status\": FormInstance.formData.settings.read_status,\n\t\t\"chatwoot_account_id\": FormInstance.formData.chatwoot.chatwoot_account_id,\n\t\t\"chatwoot_token\": FormInstance.formData.chatwoot.chatwoot_token,\n\t\t\"chatwoot_url\": FormInstance.formData.chatwoot.chatwoot_url,\n\t\t\"chatwoot_sign_msg\": FormInstance.formData.chatwoot.chatwoot_sign_msg,\n\t\t\"chatwoot_reopen_conversation\": FormInstance.formData.chatwoot.chatwoot_reopen_conversation,\n\t\t\"chatwoot_conversation_pending\": FormInstance.formData.chatwoot.chatwoot_conversation_pending\n\t}\n}}","bodyFormData":[{"key":"instanceName","value":"{{FormInstance.data.InputNewInstanceName}}"},{"key":"token","value":"{{FormInstance.data.InputNewInstanceToken}}"}],"httpMethod":"POST","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"application/json"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"},{"key":"bodyFormData[0].value"},{"key":"bodyFormData[1].value"},{"key":"body"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["\n\t{\n\t\t\"instanceName\": FormInstance.formData.instance.instanceName,\n\t\t\"token\": FormInstance.formData.instance.token,\n\t\t\"qrcode\": FormInstance.formData.instance.qrcode,\n\t\t\"webhook\": FormInstance.formData.webhook.webhook,\n\t\t\"webhook_by_events\": FormInstance.formData.webhook.webhook_by_events,\n\t\t\"websocket_enabled\": FormInstance.formData.websocket.websocket_enabled,\n\t\t\"websocket_events\": FormInstance.formData.websocket.websocket_events,\n\t\t\"rabbitmq_enabled\": FormInstance.formData.websocket.rabbitmq_enabled,\n\t\t\"rabbitmq_events\": FormInstance.formData.websocket.rabbitmq_events,\n\t\t\"events\": FormInstance.formData.webhook.events,\n\t\t\"reject_call\": FormInstance.formData.settings.reject_call,\n\t\t\"msg_call\": FormInstance.formData.settings.msg_call,\n\t\t\"groups_ignore\": FormInstance.formData.settings.groups_ignore,\n\t\t\"always_online\": FormInstance.formData.settings.always_online,\n\t\t\"read_messages\": FormInstance.formData.settings.read_messages,\n\t\t\"read_status\": FormInstance.formData.settings.read_status,\n\t\t\"chatwoot_account_id\": FormInstance.formData.chatwoot.chatwoot_account_id,\n\t\t\"chatwoot_token\": FormInstance.formData.chatwoot.chatwoot_token,\n\t\t\"chatwoot_url\": FormInstance.formData.chatwoot.chatwoot_url,\n\t\t\"chatwoot_sign_msg\": FormInstance.formData.chatwoot.chatwoot_sign_msg,\n\t\t\"chatwoot_reopen_conversation\": FormInstance.formData.chatwoot.chatwoot_reopen_conversation,\n\t\t\"chatwoot_conversation_pending\": FormInstance.formData.chatwoot.chatwoot_conversation_pending\n\t}\n","FormInstance.data.InputNewInstanceName","FormInstance.data.InputNewInstanceToken","appsmith.store.api_url","appsmith.store.api_key"],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-07-30T03:22:09Z"},"publishedAction":{"name":"Create_Instance","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/instance/create","headers":[{"key":"apikey","value":"{{appsmith.store.api_key}}"}],"autoGeneratedHeaders":[{"key":"content-type","value":"application/json"}],"encodeParamsToggle":true,"queryParameters":[],"body":"{{\n\t{\n\t\t\"instanceName\": FormInstance.formData.instance.instanceName,\n\t\t\"token\": FormInstance.formData.instance.token,\n\t\t\"qrcode\": FormInstance.formData.instance.qrcode,\n\t\t\"webhook\": FormInstance.formData.webhook.webhook,\n\t\t\"webhook_by_events\": FormInstance.formData.webhook.webhook_by_events,\n\t\t\"websocket_enabled\": FormInstance.formData.websocket.websocket_enabled,\n\t\t\"websocket_events\": FormInstance.formData.websocket.websocket_events,\n\t\t\"rabbitmq_enabled\": FormInstance.formData.websocket.rabbitmq_enabled,\n\t\t\"rabbitmq_events\": FormInstance.formData.websocket.rabbitmq_events,\n\t\t\"events\": FormInstance.formData.webhook.events,\n\t\t\"reject_call\": FormInstance.formData.settings.reject_call,\n\t\t\"msg_call\": FormInstance.formData.settings.msg_call,\n\t\t\"groups_ignore\": FormInstance.formData.settings.groups_ignore,\n\t\t\"always_online\": FormInstance.formData.settings.always_online,\n\t\t\"read_messages\": FormInstance.formData.settings.read_messages,\n\t\t\"read_status\": FormInstance.formData.settings.read_status,\n\t\t\"chatwoot_account_id\": FormInstance.formData.chatwoot.chatwoot_account_id,\n\t\t\"chatwoot_token\": FormInstance.formData.chatwoot.chatwoot_token,\n\t\t\"chatwoot_url\": FormInstance.formData.chatwoot.chatwoot_url,\n\t\t\"chatwoot_sign_msg\": FormInstance.formData.chatwoot.chatwoot_sign_msg,\n\t\t\"chatwoot_reopen_conversation\": FormInstance.formData.chatwoot.chatwoot_reopen_conversation,\n\t\t\"chatwoot_conversation_pending\": FormInstance.formData.chatwoot.chatwoot_conversation_pending\n\t}\n}}","bodyFormData":[{"key":"instanceName","value":"{{FormInstance.data.InputNewInstanceName}}"},{"key":"token","value":"{{FormInstance.data.InputNewInstanceToken}}"}],"httpMethod":"POST","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"application/json"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"},{"key":"bodyFormData[0].value"},{"key":"bodyFormData[1].value"},{"key":"body"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["\n\t{\n\t\t\"instanceName\": FormInstance.formData.instance.instanceName,\n\t\t\"token\": FormInstance.formData.instance.token,\n\t\t\"qrcode\": FormInstance.formData.instance.qrcode,\n\t\t\"webhook\": FormInstance.formData.webhook.webhook,\n\t\t\"webhook_by_events\": FormInstance.formData.webhook.webhook_by_events,\n\t\t\"websocket_enabled\": FormInstance.formData.websocket.websocket_enabled,\n\t\t\"websocket_events\": FormInstance.formData.websocket.websocket_events,\n\t\t\"rabbitmq_enabled\": FormInstance.formData.websocket.rabbitmq_enabled,\n\t\t\"rabbitmq_events\": FormInstance.formData.websocket.rabbitmq_events,\n\t\t\"events\": FormInstance.formData.webhook.events,\n\t\t\"reject_call\": FormInstance.formData.settings.reject_call,\n\t\t\"msg_call\": FormInstance.formData.settings.msg_call,\n\t\t\"groups_ignore\": FormInstance.formData.settings.groups_ignore,\n\t\t\"always_online\": FormInstance.formData.settings.always_online,\n\t\t\"read_messages\": FormInstance.formData.settings.read_messages,\n\t\t\"read_status\": FormInstance.formData.settings.read_status,\n\t\t\"chatwoot_account_id\": FormInstance.formData.chatwoot.chatwoot_account_id,\n\t\t\"chatwoot_token\": FormInstance.formData.chatwoot.chatwoot_token,\n\t\t\"chatwoot_url\": FormInstance.formData.chatwoot.chatwoot_url,\n\t\t\"chatwoot_sign_msg\": FormInstance.formData.chatwoot.chatwoot_sign_msg,\n\t\t\"chatwoot_reopen_conversation\": FormInstance.formData.chatwoot.chatwoot_reopen_conversation,\n\t\t\"chatwoot_conversation_pending\": FormInstance.formData.chatwoot.chatwoot_conversation_pending\n\t}\n","FormInstance.data.InputNewInstanceName","FormInstance.data.InputNewInstanceToken","appsmith.store.api_url","appsmith.store.api_key"],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-07-30T03:22:09Z"},"id":"Home_Create_Instance","deleted":false,"gitSyncId":"64e0b37fa2945b083c5bc7ac_64e0b37fa2945b083c5bc7b3"},{"pluginType":"API","pluginId":"restapi-plugin","unpublishedAction":{"name":"Find_Chatwoot","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/chatwoot/find/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{TableInstances.selectedRow.Apikey}}"}],"autoGeneratedHeaders":[],"encodeParamsToggle":true,"queryParameters":[],"bodyFormData":[],"httpMethod":"GET","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["TableInstances.selectedRow.Apikey","encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url"],"userSetOnLoad":true,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-07-30T19:49:33Z"},"publishedAction":{"name":"Find_Chatwoot","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/chatwoot/find/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{TableInstances.selectedRow.Apikey}}"}],"autoGeneratedHeaders":[],"encodeParamsToggle":true,"queryParameters":[],"bodyFormData":[],"httpMethod":"GET","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["TableInstances.selectedRow.Apikey","encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url"],"userSetOnLoad":true,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-07-30T19:49:33Z"},"id":"Home_Find_Chatwoot","deleted":false,"gitSyncId":"64e0b37fa2945b083c5bc7ac_64e0b37fa2945b083c5bc7b5"},{"pluginType":"JS","pluginId":"js-plugin","unpublishedAction":{"name":"verifyConfig","fullyQualifiedName":"Scripts.verifyConfig","datasource":{"name":"UNUSED_DATASOURCE","pluginId":"js-plugin","invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","collectionId":"Home_Scripts","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","encodeParamsToggle":true,"body":"async function () {\n const api_url = await appsmith.store.api_url;\n const api_key = await appsmith.store.api_key;\n if (!api_url && !api_key) {\n showModal('ModalConfig');\n return false;\n }\n fetch_Instances.run();\n Find_Webhook.run();\n Find_Settings.run();\n Find_Chatwoot.run();\n return true;\n}","selfReferencingDataPaths":[],"jsArguments":[],"isAsync":true},"executeOnLoad":true,"clientSideExecution":true,"dynamicBindingPathList":[{"key":"body"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":[],"userSetOnLoad":true,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-07-29T16:12:42Z"},"publishedAction":{"name":"verifyConfig","fullyQualifiedName":"Scripts.verifyConfig","datasource":{"name":"UNUSED_DATASOURCE","pluginId":"js-plugin","invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","collectionId":"Home_Scripts","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","encodeParamsToggle":true,"body":"async function () {\n const api_url = await appsmith.store.api_url;\n const api_key = await appsmith.store.api_key;\n if (!api_url && !api_key) {\n showModal('ModalConfig');\n return false;\n }\n fetch_Instances.run();\n Find_Webhook.run();\n Find_Settings.run();\n Find_Chatwoot.run();\n return true;\n}","selfReferencingDataPaths":[],"jsArguments":[],"isAsync":true},"executeOnLoad":true,"clientSideExecution":true,"dynamicBindingPathList":[{"key":"body"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":[],"userSetOnLoad":true,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-07-29T16:12:42Z"},"id":"Home_Scripts.verifyConfig","deleted":false,"gitSyncId":"64e0b37fa2945b083c5bc7ac_64e0b37fa2945b083c5bc7b2"},{"pluginType":"API","pluginId":"restapi-plugin","unpublishedAction":{"name":"Find_Settings","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/settings/find/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{TableInstances.selectedRow.Apikey}}"}],"autoGeneratedHeaders":[],"encodeParamsToggle":true,"queryParameters":[],"bodyFormData":[],"httpMethod":"GET","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["TableInstances.selectedRow.Apikey","encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url"],"userSetOnLoad":true,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-07-30T19:48:45Z"},"publishedAction":{"name":"Find_Settings","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/settings/find/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{TableInstances.selectedRow.Apikey}}"}],"autoGeneratedHeaders":[],"encodeParamsToggle":true,"queryParameters":[],"bodyFormData":[],"httpMethod":"GET","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["TableInstances.selectedRow.Apikey","encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url"],"userSetOnLoad":true,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-07-30T19:48:45Z"},"id":"Home_Find_Settings","deleted":false,"gitSyncId":"64e0b37fa2945b083c5bc7ac_64e0b37fa2945b083c5bc7b9"},{"pluginType":"API","pluginId":"restapi-plugin","unpublishedAction":{"name":"fetch_Instances","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/instance/fetchInstances","headers":[{"key":"apikey","value":"{{appsmith.store.api_key}}"}],"autoGeneratedHeaders":[],"encodeParamsToggle":true,"queryParameters":[],"bodyFormData":[],"httpMethod":"GET","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["appsmith.store.api_url","appsmith.store.api_key"],"userSetOnLoad":true,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-07-29T16:12:42Z"},"publishedAction":{"name":"fetch_Instances","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/instance/fetchInstances","headers":[{"key":"apikey","value":"{{appsmith.store.api_key}}"}],"autoGeneratedHeaders":[],"encodeParamsToggle":true,"queryParameters":[],"bodyFormData":[],"httpMethod":"GET","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["appsmith.store.api_url","appsmith.store.api_key"],"userSetOnLoad":true,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-07-29T16:12:42Z"},"id":"Home_fetch_Instances","deleted":false,"gitSyncId":"64e0b37fa2945b083c5bc7ac_64e0b37fa2945b083c5bc7b6"},{"pluginType":"API","pluginId":"restapi-plugin","unpublishedAction":{"name":"Connect","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/instance/connect/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{appsmith.store.api_key}}"}],"autoGeneratedHeaders":[],"encodeParamsToggle":true,"queryParameters":[],"bodyFormData":[],"httpMethod":"GET","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url","appsmith.store.api_key"],"userSetOnLoad":true,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-07-29T16:12:42Z"},"publishedAction":{"name":"Connect","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/instance/connect/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{appsmith.store.api_key}}"}],"autoGeneratedHeaders":[],"encodeParamsToggle":true,"queryParameters":[],"bodyFormData":[],"httpMethod":"GET","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url","appsmith.store.api_key"],"userSetOnLoad":true,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-07-29T16:12:42Z"},"id":"Home_Connect","deleted":false,"gitSyncId":"64e0b37fa2945b083c5bc7ac_64e0b37fa2945b083c5bc7ba"},{"pluginType":"API","pluginId":"restapi-plugin","unpublishedAction":{"name":"Delete","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/instance/delete/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{appsmith.store.api_key}}"}],"autoGeneratedHeaders":[{"key":"content-type","value":"application/json"}],"encodeParamsToggle":true,"queryParameters":[],"body":"","bodyFormData":[],"httpMethod":"DELETE","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url","appsmith.store.api_key"],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-07-30T03:02:32Z"},"publishedAction":{"name":"Delete","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/instance/delete/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{appsmith.store.api_key}}"}],"autoGeneratedHeaders":[{"key":"content-type","value":"application/json"}],"encodeParamsToggle":true,"queryParameters":[],"body":"","bodyFormData":[],"httpMethod":"DELETE","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url","appsmith.store.api_key"],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-07-30T03:02:32Z"},"id":"Home_Delete","deleted":false,"gitSyncId":"64e0b37fa2945b083c5bc7ac_64e0b37fa2945b083c5bc7b7"},{"pluginType":"API","pluginId":"restapi-plugin","unpublishedAction":{"name":"Logout","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/instance/logout/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{appsmith.store.api_key}}"}],"autoGeneratedHeaders":[{"key":"content-type","value":"application/json"}],"encodeParamsToggle":true,"queryParameters":[],"body":"","bodyFormData":[],"httpMethod":"DELETE","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url","appsmith.store.api_key"],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-07-30T03:02:00Z"},"publishedAction":{"name":"Logout","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/instance/logout/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{appsmith.store.api_key}}"}],"autoGeneratedHeaders":[{"key":"content-type","value":"application/json"}],"encodeParamsToggle":true,"queryParameters":[],"body":"","bodyFormData":[],"httpMethod":"DELETE","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url","appsmith.store.api_key"],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-07-30T03:02:00Z"},"id":"Home_Logout","deleted":false,"gitSyncId":"64e0b37fa2945b083c5bc7ac_64e0b37fa2945b083c5bc7b8"},{"pluginType":"API","pluginId":"restapi-plugin","unpublishedAction":{"name":"Find_Webhook","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/webhook/find/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{TableInstances.selectedRow.Apikey}}"}],"autoGeneratedHeaders":[],"encodeParamsToggle":true,"queryParameters":[],"bodyFormData":[],"httpMethod":"GET","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["TableInstances.selectedRow.Apikey","encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url"],"userSetOnLoad":true,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-07-30T19:46:50Z"},"publishedAction":{"name":"Find_Webhook","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/webhook/find/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{TableInstances.selectedRow.Apikey}}"}],"autoGeneratedHeaders":[],"encodeParamsToggle":true,"queryParameters":[],"bodyFormData":[],"httpMethod":"GET","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["TableInstances.selectedRow.Apikey","encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url"],"userSetOnLoad":true,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-07-30T19:46:50Z"},"id":"Home_Find_Webhook","deleted":false,"gitSyncId":"64e0b37fa2945b083c5bc7ac_64e0b37fa2945b083c5bc7c5"},{"pluginType":"API","pluginId":"restapi-plugin","unpublishedAction":{"name":"Find_Rabbitmq","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/rabbitmq/find/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{TableInstances.selectedRow.Apikey}}"}],"autoGeneratedHeaders":[],"encodeParamsToggle":true,"queryParameters":[],"bodyFormData":[],"httpMethod":"GET","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":true,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["TableInstances.selectedRow.Apikey","encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url"],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-09-20T22:28:47Z"},"publishedAction":{"name":"Find_Rabbitmq","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/rabbitmq/find/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{TableInstances.selectedRow.Apikey}}"}],"autoGeneratedHeaders":[],"encodeParamsToggle":true,"queryParameters":[],"bodyFormData":[],"httpMethod":"GET","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":true,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["TableInstances.selectedRow.Apikey","encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url"],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-09-20T22:28:47Z"},"id":"Home_Find_Rabbitmq","deleted":false,"gitSyncId":"64e0b37fa2945b083c5bc7ac_64e0b37fa2945b083c5bc7c1"},{"pluginType":"API","pluginId":"restapi-plugin","unpublishedAction":{"name":"Set_Websocket","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/websocket/set/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{TableInstances.selectedRow.Apikey}}"}],"autoGeneratedHeaders":[{"key":"content-type","value":"application/json"}],"encodeParamsToggle":true,"queryParameters":[],"body":"{{\n\tFormWebsocket.formData\n}}","bodyFormData":[],"httpMethod":"POST","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"},{"key":"body"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["TableInstances.selectedRow.Apikey","\n\tFormWebsocket.formData\n","encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url"],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-08-03T00:55:30Z"},"publishedAction":{"name":"Set_Websocket","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/websocket/set/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{TableInstances.selectedRow.Apikey}}"}],"autoGeneratedHeaders":[{"key":"content-type","value":"application/json"}],"encodeParamsToggle":true,"queryParameters":[],"body":"{{\n\tFormWebsocket.formData\n}}","bodyFormData":[],"httpMethod":"POST","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"},{"key":"body"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["TableInstances.selectedRow.Apikey","\n\tFormWebsocket.formData\n","encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url"],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-08-03T00:55:30Z"},"id":"Home_Set_Websocket","deleted":false,"gitSyncId":"64e0b37fa2945b083c5bc7ac_64e0b37fa2945b083c5bc7bd"},{"pluginType":"API","pluginId":"restapi-plugin","unpublishedAction":{"name":"Update_ProfileName","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/chat/updateProfileName/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{TableInstances.selectedRow.Apikey}}"}],"autoGeneratedHeaders":[{"key":"content-type","value":"application/json"}],"encodeParamsToggle":true,"queryParameters":[],"body":"{{\n\t{\n\t\t\"name\": FormProfile.formData.profileName\n\t}\n}}","bodyFormData":[],"httpMethod":"POST","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"},{"key":"body"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["TableInstances.selectedRow.Apikey","\n\t{\n\t\t\"name\": FormProfile.formData.profileName\n\t}\n","encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url"],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-07-31T12:22:45Z"},"publishedAction":{"name":"Update_ProfileName","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/chat/updateProfileName/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{TableInstances.selectedRow.Apikey}}"}],"autoGeneratedHeaders":[{"key":"content-type","value":"application/json"}],"encodeParamsToggle":true,"queryParameters":[],"body":"{{\n\t{\n\t\t\"name\": FormProfile.formData.profileName\n\t}\n}}","bodyFormData":[],"httpMethod":"POST","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"},{"key":"body"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["TableInstances.selectedRow.Apikey","\n\t{\n\t\t\"name\": FormProfile.formData.profileName\n\t}\n","encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url"],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-07-31T12:22:45Z"},"id":"Home_Update_ProfileName","deleted":false,"gitSyncId":"64e0b37fa2945b083c5bc7ac_64e0b37fa2945b083c5bc7bb"},{"pluginType":"API","pluginId":"restapi-plugin","unpublishedAction":{"name":"Update_ProfileStatus","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/chat/updateProfileStatus/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{TableInstances.selectedRow.Apikey}}"}],"autoGeneratedHeaders":[{"key":"content-type","value":"application/json"}],"encodeParamsToggle":true,"queryParameters":[],"body":"{{\n\t{\n\t\t\"status\": FormProfile.formData.profileStatus\n\t}\n}}","bodyFormData":[],"httpMethod":"POST","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"application/json"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"body"},{"key":"path"},{"key":"headers[0].value"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["TableInstances.selectedRow.Apikey","\n\t{\n\t\t\"status\": FormProfile.formData.profileStatus\n\t}\n","encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url"],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-07-31T12:25:00Z"},"publishedAction":{"name":"Update_ProfileStatus","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/chat/updateProfileStatus/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{TableInstances.selectedRow.Apikey}}"}],"autoGeneratedHeaders":[{"key":"content-type","value":"application/json"}],"encodeParamsToggle":true,"queryParameters":[],"body":"{{\n\t{\n\t\t\"status\": FormProfile.formData.profileStatus\n\t}\n}}","bodyFormData":[],"httpMethod":"POST","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"application/json"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"body"},{"key":"path"},{"key":"headers[0].value"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["TableInstances.selectedRow.Apikey","\n\t{\n\t\t\"status\": FormProfile.formData.profileStatus\n\t}\n","encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url"],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-07-31T12:25:00Z"},"id":"Home_Update_ProfileStatus","deleted":false,"gitSyncId":"64e0b37fa2945b083c5bc7ac_64e0b37fa2945b083c5bc7c6"},{"pluginType":"API","pluginId":"restapi-plugin","unpublishedAction":{"name":"Set_Settings","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/settings/set/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{TableInstances.selectedRow.Apikey}}"}],"autoGeneratedHeaders":[{"key":"content-type","value":"application/json"}],"encodeParamsToggle":true,"queryParameters":[],"body":"{{\n\tFormSettings.formData\n}}","bodyFormData":[],"httpMethod":"POST","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"application/json"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"},{"key":"body"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["TableInstances.selectedRow.Apikey","encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url","\n\tFormSettings.formData\n"],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-07-30T20:13:25Z"},"publishedAction":{"name":"Set_Settings","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/settings/set/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{TableInstances.selectedRow.Apikey}}"}],"autoGeneratedHeaders":[{"key":"content-type","value":"application/json"}],"encodeParamsToggle":true,"queryParameters":[],"body":"{{\n\tFormSettings.formData\n}}","bodyFormData":[],"httpMethod":"POST","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"application/json"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"},{"key":"body"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["TableInstances.selectedRow.Apikey","encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url","\n\tFormSettings.formData\n"],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-07-30T20:13:25Z"},"id":"Home_Set_Settings","deleted":false,"gitSyncId":"64e0b37fa2945b083c5bc7ac_64e0b380a2945b083c5bc7ce"},{"pluginType":"API","pluginId":"restapi-plugin","unpublishedAction":{"name":"Set_Chatwoot","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/chatwoot/set/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{TableInstances.selectedRow.Apikey}}"}],"autoGeneratedHeaders":[{"key":"content-type","value":"application/json"}],"encodeParamsToggle":true,"queryParameters":[],"body":"{{\n\t{\n\t\t\"enabled\": FormChatwoot.formData.enabled,\n\t\t\"account_id\": String(FormChatwoot.formData.account_id),\n\t\t\"token\": FormChatwoot.formData.token,\n\t\t\"url\": FormChatwoot.formData.url,\n\t\t\"sign_msg\": FormChatwoot.formData.sign_msg,\n\t\t\"reopen_conversation\": FormChatwoot.formData.reopen_conversation,\n\t\t\"conversation_pending\": FormChatwoot.formData.conversation_pending\n\t}\n}}","bodyFormData":[],"httpMethod":"POST","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"},{"key":"body"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["TableInstances.selectedRow.Apikey","\n\t{\n\t\t\"enabled\": FormChatwoot.formData.enabled,\n\t\t\"account_id\": String(FormChatwoot.formData.account_id),\n\t\t\"token\": FormChatwoot.formData.token,\n\t\t\"url\": FormChatwoot.formData.url,\n\t\t\"sign_msg\": FormChatwoot.formData.sign_msg,\n\t\t\"reopen_conversation\": FormChatwoot.formData.reopen_conversation,\n\t\t\"conversation_pending\": FormChatwoot.formData.conversation_pending\n\t}\n","encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url"],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-07-30T20:15:01Z"},"publishedAction":{"name":"Set_Chatwoot","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/chatwoot/set/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{TableInstances.selectedRow.Apikey}}"}],"autoGeneratedHeaders":[{"key":"content-type","value":"application/json"}],"encodeParamsToggle":true,"queryParameters":[],"body":"{{\n\t{\n\t\t\"enabled\": FormChatwoot.formData.enabled,\n\t\t\"account_id\": String(FormChatwoot.formData.account_id),\n\t\t\"token\": FormChatwoot.formData.token,\n\t\t\"url\": FormChatwoot.formData.url,\n\t\t\"sign_msg\": FormChatwoot.formData.sign_msg,\n\t\t\"reopen_conversation\": FormChatwoot.formData.reopen_conversation,\n\t\t\"conversation_pending\": FormChatwoot.formData.conversation_pending\n\t}\n}}","bodyFormData":[],"httpMethod":"POST","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"},{"key":"body"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["TableInstances.selectedRow.Apikey","\n\t{\n\t\t\"enabled\": FormChatwoot.formData.enabled,\n\t\t\"account_id\": String(FormChatwoot.formData.account_id),\n\t\t\"token\": FormChatwoot.formData.token,\n\t\t\"url\": FormChatwoot.formData.url,\n\t\t\"sign_msg\": FormChatwoot.formData.sign_msg,\n\t\t\"reopen_conversation\": FormChatwoot.formData.reopen_conversation,\n\t\t\"conversation_pending\": FormChatwoot.formData.conversation_pending\n\t}\n","encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url"],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-07-30T20:15:01Z"},"id":"Home_Set_Chatwoot","deleted":false,"gitSyncId":"64e0b37fa2945b083c5bc7ac_64e0b380a2945b083c5bc7d0"},{"pluginType":"API","pluginId":"restapi-plugin","unpublishedAction":{"name":"Fetch_Instance","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/instance/fetchInstances","headers":[{"key":"apikey","value":"{{appsmith.store.api_key}}"}],"autoGeneratedHeaders":[],"encodeParamsToggle":true,"queryParameters":[{"key":"instanceName","value":"{{TableInstances.selectedRow.instance}}"}],"bodyFormData":[],"httpMethod":"GET","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"path"},{"key":"queryParameters[0].value"},{"key":"headers[0].value"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["appsmith.store.api_url","appsmith.store.api_key","TableInstances.selectedRow.instance"],"userSetOnLoad":true,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-07-31T12:16:40Z"},"publishedAction":{"name":"Fetch_Instance","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/instance/fetchInstances","headers":[{"key":"apikey","value":"{{appsmith.store.api_key}}"}],"autoGeneratedHeaders":[],"encodeParamsToggle":true,"queryParameters":[{"key":"instanceName","value":"{{TableInstances.selectedRow.instance}}"}],"bodyFormData":[],"httpMethod":"GET","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"path"},{"key":"queryParameters[0].value"},{"key":"headers[0].value"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["appsmith.store.api_url","appsmith.store.api_key","TableInstances.selectedRow.instance"],"userSetOnLoad":true,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-07-31T12:16:40Z"},"id":"Home_Fetch_Instance","deleted":false,"gitSyncId":"64e0b37fa2945b083c5bc7ac_64e0b380a2945b083c5bc7cf"},{"pluginType":"API","pluginId":"restapi-plugin","unpublishedAction":{"name":"Remove_ProfilePicture","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/chat/removeProfilePicture/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{TableInstances.selectedRow.Apikey}}"}],"autoGeneratedHeaders":[{"key":"content-type","value":"application/json"}],"encodeParamsToggle":true,"queryParameters":[],"body":"","bodyFormData":[],"httpMethod":"DELETE","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["TableInstances.selectedRow.Apikey","encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url"],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-07-31T12:27:20Z"},"publishedAction":{"name":"Remove_ProfilePicture","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/chat/removeProfilePicture/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{TableInstances.selectedRow.Apikey}}"}],"autoGeneratedHeaders":[{"key":"content-type","value":"application/json"}],"encodeParamsToggle":true,"queryParameters":[],"body":"","bodyFormData":[],"httpMethod":"DELETE","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["TableInstances.selectedRow.Apikey","encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url"],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-07-31T12:27:20Z"},"id":"Home_Remove_ProfilePicture","deleted":false,"gitSyncId":"64e0b37fa2945b083c5bc7ac_64e0b380a2945b083c5bc7d4"},{"pluginType":"API","pluginId":"restapi-plugin","unpublishedAction":{"name":"Set_Webhook","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/webhook/set/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{TableInstances.selectedRow.Apikey}}"}],"autoGeneratedHeaders":[{"key":"content-type","value":"application/json"}],"encodeParamsToggle":true,"queryParameters":[],"body":"{{\n\tFormWebhook.formData\n}}","bodyFormData":[],"httpMethod":"POST","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"},{"key":"body"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["TableInstances.selectedRow.Apikey","\n\tFormWebhook.formData\n","encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url"],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-07-30T20:10:19Z"},"publishedAction":{"name":"Set_Webhook","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/webhook/set/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{TableInstances.selectedRow.Apikey}}"}],"autoGeneratedHeaders":[{"key":"content-type","value":"application/json"}],"encodeParamsToggle":true,"queryParameters":[],"body":"{{\n\tFormWebhook.formData\n}}","bodyFormData":[],"httpMethod":"POST","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"},{"key":"body"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["TableInstances.selectedRow.Apikey","\n\tFormWebhook.formData\n","encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url"],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-07-30T20:10:19Z"},"id":"Home_Set_Webhook","deleted":false,"gitSyncId":"64e0b37fa2945b083c5bc7ac_64e0b380a2945b083c5bc7d5"},{"pluginType":"API","pluginId":"restapi-plugin","unpublishedAction":{"name":"Update_ProfilePicture","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/chat/updateProfilePicture/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{TableInstances.selectedRow.Apikey}}"}],"autoGeneratedHeaders":[{"key":"content-type","value":"application/json"}],"encodeParamsToggle":true,"queryParameters":[],"body":"{{\n\t{\n\t\t\"picture\": FormProfile.formData.profilePictureUrl\n\t}\n}}","bodyFormData":[],"httpMethod":"PUT","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"},{"key":"body"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["TableInstances.selectedRow.Apikey","\n\t{\n\t\t\"picture\": FormProfile.formData.profilePictureUrl\n\t}\n","encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url"],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-07-31T12:25:56Z"},"publishedAction":{"name":"Update_ProfilePicture","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/chat/updateProfilePicture/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{TableInstances.selectedRow.Apikey}}"}],"autoGeneratedHeaders":[{"key":"content-type","value":"application/json"}],"encodeParamsToggle":true,"queryParameters":[],"body":"{{\n\t{\n\t\t\"picture\": FormProfile.formData.profilePictureUrl\n\t}\n}}","bodyFormData":[],"httpMethod":"PUT","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"},{"key":"body"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["TableInstances.selectedRow.Apikey","\n\t{\n\t\t\"picture\": FormProfile.formData.profilePictureUrl\n\t}\n","encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url"],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-07-31T12:25:56Z"},"id":"Home_Update_ProfilePicture","deleted":false,"gitSyncId":"64e0b37fa2945b083c5bc7ac_64e0b380a2945b083c5bc7d1"},{"pluginType":"API","pluginId":"restapi-plugin","unpublishedAction":{"name":"Set_TypebotChangeSessionStatus","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/typebot/changeStatus/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{TableInstances.selectedRow.Apikey}}"}],"autoGeneratedHeaders":[{"key":"content-type","value":"application/json"}],"encodeParamsToggle":true,"queryParameters":[],"body":"{{\n{\n \"remoteJid\": FormTypebotChangeSessionStatus.formData.remoteJid,\n \"status\": FormTypebotChangeSessionStatus.formData.status\n}\n}}","bodyFormData":[],"httpMethod":"POST","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"headers[0].value"},{"key":"path"},{"key":"body"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["TableInstances.selectedRow.Apikey","encodeURIComponent(TableInstances.selectedRow.instance)","\n{\n \"remoteJid\": FormTypebotChangeSessionStatus.formData.remoteJid,\n \"status\": FormTypebotChangeSessionStatus.formData.status\n}\n","appsmith.store.api_url"],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-08-19T11:28:01Z"},"publishedAction":{"name":"Set_TypebotChangeSessionStatus","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/typebot/changeStatus/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{TableInstances.selectedRow.Apikey}}"}],"autoGeneratedHeaders":[{"key":"content-type","value":"application/json"}],"encodeParamsToggle":true,"queryParameters":[],"body":"{{\n{\n \"remoteJid\": FormTypebotChangeSessionStatus.formData.remoteJid,\n \"status\": FormTypebotChangeSessionStatus.formData.status\n}\n}}","bodyFormData":[],"httpMethod":"POST","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"headers[0].value"},{"key":"path"},{"key":"body"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["TableInstances.selectedRow.Apikey","encodeURIComponent(TableInstances.selectedRow.instance)","\n{\n \"remoteJid\": FormTypebotChangeSessionStatus.formData.remoteJid,\n \"status\": FormTypebotChangeSessionStatus.formData.status\n}\n","appsmith.store.api_url"],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-08-19T11:28:01Z"},"id":"Home_Set_TypebotChangeSessionStatus","deleted":false,"gitSyncId":"64e0b37fa2945b083c5bc7ac_64e0b380a2945b083c5bc7d2"},{"pluginType":"API","pluginId":"restapi-plugin","unpublishedAction":{"name":"Set_Typebot","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/typebot/set/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{TableInstances.selectedRow.Apikey}}"}],"autoGeneratedHeaders":[{"key":"content-type","value":"application/json"}],"encodeParamsToggle":true,"queryParameters":[],"body":"{{\n\t{\n\t\t\"enabled\": FormTypebot.formData.enabled,\n\t\t\"url\": (FormTypebot.formData.url),\n\t\t\"typebot\": FormTypebot.formData.typebot,\n\t\t\"expire\": FormTypebot.formData.expire,\n\t\t\"keyword_finish\": FormTypebot.formData.keyword_finish,\n\t\t\"delay_message\": FormTypebot.formData.delay_message,\n\t\t\"unknown_message\": FormTypebot.formData.unknown_message,\n\t\t\"listening_from_me\": FormTypebot.formData.listening_from_me\n\t}\n}}","bodyFormData":[],"httpMethod":"POST","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"headers[0].value"},{"key":"path"},{"key":"body"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["TableInstances.selectedRow.Apikey","\n\t{\n\t\t\"enabled\": FormTypebot.formData.enabled,\n\t\t\"url\": (FormTypebot.formData.url),\n\t\t\"typebot\": FormTypebot.formData.typebot,\n\t\t\"expire\": FormTypebot.formData.expire,\n\t\t\"keyword_finish\": FormTypebot.formData.keyword_finish,\n\t\t\"delay_message\": FormTypebot.formData.delay_message,\n\t\t\"unknown_message\": FormTypebot.formData.unknown_message,\n\t\t\"listening_from_me\": FormTypebot.formData.listening_from_me\n\t}\n","encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url"],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-08-19T05:00:46Z"},"publishedAction":{"name":"Set_Typebot","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/typebot/set/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{TableInstances.selectedRow.Apikey}}"}],"autoGeneratedHeaders":[{"key":"content-type","value":"application/json"}],"encodeParamsToggle":true,"queryParameters":[],"body":"{{\n\t{\n\t\t\"enabled\": FormTypebot.formData.enabled,\n\t\t\"url\": (FormTypebot.formData.url),\n\t\t\"typebot\": FormTypebot.formData.typebot,\n\t\t\"expire\": FormTypebot.formData.expire,\n\t\t\"keyword_finish\": FormTypebot.formData.keyword_finish,\n\t\t\"delay_message\": FormTypebot.formData.delay_message,\n\t\t\"unknown_message\": FormTypebot.formData.unknown_message,\n\t\t\"listening_from_me\": FormTypebot.formData.listening_from_me\n\t}\n}}","bodyFormData":[],"httpMethod":"POST","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"headers[0].value"},{"key":"path"},{"key":"body"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["TableInstances.selectedRow.Apikey","\n\t{\n\t\t\"enabled\": FormTypebot.formData.enabled,\n\t\t\"url\": (FormTypebot.formData.url),\n\t\t\"typebot\": FormTypebot.formData.typebot,\n\t\t\"expire\": FormTypebot.formData.expire,\n\t\t\"keyword_finish\": FormTypebot.formData.keyword_finish,\n\t\t\"delay_message\": FormTypebot.formData.delay_message,\n\t\t\"unknown_message\": FormTypebot.formData.unknown_message,\n\t\t\"listening_from_me\": FormTypebot.formData.listening_from_me\n\t}\n","encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url"],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-08-19T05:00:46Z"},"id":"Home_Set_Typebot","deleted":false,"gitSyncId":"64e0b37fa2945b083c5bc7ac_64e0b380a2945b083c5bc7d9"},{"pluginType":"API","pluginId":"restapi-plugin","unpublishedAction":{"name":"Find_Websocket","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/websocket/find/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{TableInstances.selectedRow.Apikey}}"}],"autoGeneratedHeaders":[],"encodeParamsToggle":true,"queryParameters":[],"bodyFormData":[],"httpMethod":"GET","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":true,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["TableInstances.selectedRow.Apikey","encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url"],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-09-20T22:28:47Z"},"publishedAction":{"name":"Find_Websocket","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/websocket/find/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{TableInstances.selectedRow.Apikey}}"}],"autoGeneratedHeaders":[],"encodeParamsToggle":true,"queryParameters":[],"bodyFormData":[],"httpMethod":"GET","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":true,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["TableInstances.selectedRow.Apikey","encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url"],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-09-20T22:28:47Z"},"id":"Home_Find_Websocket","deleted":false,"gitSyncId":"64e0b37fa2945b083c5bc7ac_64e0b380a2945b083c5bc7d8"},{"pluginType":"API","pluginId":"restapi-plugin","unpublishedAction":{"name":"Fetch_PrivacySettings","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/chat/fetchPrivacySettings/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{TableInstances.selectedRow.Apikey}}"}],"autoGeneratedHeaders":[],"encodeParamsToggle":true,"queryParameters":[],"bodyFormData":[],"httpMethod":"GET","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["TableInstances.selectedRow.Apikey","encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url"],"userSetOnLoad":true,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-07-31T12:27:52Z"},"publishedAction":{"name":"Fetch_PrivacySettings","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/chat/fetchPrivacySettings/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{TableInstances.selectedRow.Apikey}}"}],"autoGeneratedHeaders":[],"encodeParamsToggle":true,"queryParameters":[],"bodyFormData":[],"httpMethod":"GET","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["TableInstances.selectedRow.Apikey","encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url"],"userSetOnLoad":true,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-07-31T12:27:52Z"},"id":"Home_Fetch_PrivacySettings","deleted":false,"gitSyncId":"64e0b37fa2945b083c5bc7ac_64e0b380a2945b083c5bc7dd"},{"pluginType":"API","pluginId":"restapi-plugin","unpublishedAction":{"name":"Set_Rabbitmq","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/rabbitmq/set/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{TableInstances.selectedRow.Apikey}}"}],"autoGeneratedHeaders":[{"key":"content-type","value":"application/json"}],"encodeParamsToggle":true,"queryParameters":[],"body":"{{\n\tFormRabbitmq.formData\n}}","bodyFormData":[],"httpMethod":"POST","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"},{"key":"body"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["TableInstances.selectedRow.Apikey","\n\tFormRabbitmq.formData\n","encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url"],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-08-03T00:56:01Z"},"publishedAction":{"name":"Set_Rabbitmq","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/rabbitmq/set/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{TableInstances.selectedRow.Apikey}}"}],"autoGeneratedHeaders":[{"key":"content-type","value":"application/json"}],"encodeParamsToggle":true,"queryParameters":[],"body":"{{\n\tFormRabbitmq.formData\n}}","bodyFormData":[],"httpMethod":"POST","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"},{"key":"body"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["TableInstances.selectedRow.Apikey","\n\tFormRabbitmq.formData\n","encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url"],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-08-03T00:56:01Z"},"id":"Home_Set_Rabbitmq","deleted":false,"gitSyncId":"64e0b37fa2945b083c5bc7ac_64e0b380a2945b083c5bc7de"},{"pluginType":"API","pluginId":"restapi-plugin","unpublishedAction":{"name":"Update_PrivacySettings","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/chat/updatePrivacySettings/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{TableInstances.selectedRow.Apikey}}"}],"autoGeneratedHeaders":[{"key":"content-type","value":"application/json"}],"encodeParamsToggle":true,"queryParameters":[],"body":"{{\n\t{\n \"privacySettings\": {\n \"readreceipts\": FormProfile.formData.privacySettings.readreceipts,\n \"profile\": FormProfile.formData.privacySettings.profile,\n \"status\": FormProfile.formData.privacySettings.status,\n \"online\": FormProfile.formData.privacySettings.online,\n \"last\": FormProfile.formData.privacySettings.last,\n \"groupadd\": FormProfile.formData.privacySettings.groupadd\n\t\t}\n\t}\n}}","bodyFormData":[],"httpMethod":"PUT","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"headers[0].value"},{"key":"body"},{"key":"path"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["TableInstances.selectedRow.Apikey","\n\t{\n \"privacySettings\": {\n \"readreceipts\": FormProfile.formData.privacySettings.readreceipts,\n \"profile\": FormProfile.formData.privacySettings.profile,\n \"status\": FormProfile.formData.privacySettings.status,\n \"online\": FormProfile.formData.privacySettings.online,\n \"last\": FormProfile.formData.privacySettings.last,\n \"groupadd\": FormProfile.formData.privacySettings.groupadd\n\t\t}\n\t}\n","encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url"],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-07-31T12:28:39Z"},"publishedAction":{"name":"Update_PrivacySettings","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/chat/updatePrivacySettings/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{TableInstances.selectedRow.Apikey}}"}],"autoGeneratedHeaders":[{"key":"content-type","value":"application/json"}],"encodeParamsToggle":true,"queryParameters":[],"body":"{{\n\t{\n \"privacySettings\": {\n \"readreceipts\": FormProfile.formData.privacySettings.readreceipts,\n \"profile\": FormProfile.formData.privacySettings.profile,\n \"status\": FormProfile.formData.privacySettings.status,\n \"online\": FormProfile.formData.privacySettings.online,\n \"last\": FormProfile.formData.privacySettings.last,\n \"groupadd\": FormProfile.formData.privacySettings.groupadd\n\t\t}\n\t}\n}}","bodyFormData":[],"httpMethod":"PUT","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"headers[0].value"},{"key":"body"},{"key":"path"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["TableInstances.selectedRow.Apikey","\n\t{\n \"privacySettings\": {\n \"readreceipts\": FormProfile.formData.privacySettings.readreceipts,\n \"profile\": FormProfile.formData.privacySettings.profile,\n \"status\": FormProfile.formData.privacySettings.status,\n \"online\": FormProfile.formData.privacySettings.online,\n \"last\": FormProfile.formData.privacySettings.last,\n \"groupadd\": FormProfile.formData.privacySettings.groupadd\n\t\t}\n\t}\n","encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url"],"userSetOnLoad":false,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-07-31T12:28:39Z"},"id":"Home_Update_PrivacySettings","deleted":false,"gitSyncId":"64e0b37fa2945b083c5bc7ac_64e0b380a2945b083c5bc7db"},{"pluginType":"API","pluginId":"restapi-plugin","unpublishedAction":{"name":"Find_Typebot","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/typebot/find/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{TableInstances.selectedRow.Apikey}}"}],"autoGeneratedHeaders":[],"encodeParamsToggle":true,"queryParameters":[],"bodyFormData":[],"httpMethod":"GET","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["TableInstances.selectedRow.Apikey","encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url"],"userSetOnLoad":true,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-08-19T03:57:40Z"},"publishedAction":{"name":"Find_Typebot","datasource":{"name":"DEFAULT_REST_DATASOURCE","pluginId":"restapi-plugin","datasourceConfiguration":{"url":""},"invalids":[],"messages":[],"isAutoGenerated":false,"deleted":false,"policies":[],"userPermissions":[]},"pageId":"Home","actionConfiguration":{"timeoutInMillisecond":10000.0,"paginationType":"NONE","path":"{{appsmith.store.api_url}}/typebot/find/{{encodeURIComponent(TableInstances.selectedRow.instance)}}","headers":[{"key":"apikey","value":"{{TableInstances.selectedRow.Apikey}}"}],"autoGeneratedHeaders":[],"encodeParamsToggle":true,"queryParameters":[],"bodyFormData":[],"httpMethod":"GET","selfReferencingDataPaths":[],"pluginSpecifiedTemplates":[{"value":true}],"formData":{"apiContentType":"none"}},"executeOnLoad":false,"dynamicBindingPathList":[{"key":"path"},{"key":"headers[0].value"}],"isValid":true,"invalids":[],"messages":[],"jsonPathKeys":["TableInstances.selectedRow.Apikey","encodeURIComponent(TableInstances.selectedRow.instance)","appsmith.store.api_url"],"userSetOnLoad":true,"confirmBeforeExecute":false,"policies":[],"userPermissions":[],"createdAt":"2023-08-19T03:57:40Z"},"id":"Home_Find_Typebot","deleted":false,"gitSyncId":"64e0b37fa2945b083c5bc7ac_64e0b380a2945b083c5bc7e3"}],"actionCollectionList":[{"unpublishedCollection":{"name":"Scripts","pageId":"Home","pluginId":"js-plugin","pluginType":"JS","actions":[],"archivedActions":[],"body":"export default {\n\tmyVar1: [],\n\tmyVar2: {},\n\tasync verifyConfig () {\n\t\tconst api_url = await appsmith.store.api_url;\n\t\tconst api_key = await appsmith.store.api_key;\n\t\tif(!api_url && !api_key){\n\t\t\tshowModal('ModalConfig');\n\t\t\treturn false;\n\t\t}\n\t\t\n\t\tfetch_Instances.run();\n\t\tFind_Webhook.run();\n\t\tFind_Settings.run();\n\t\tFind_Chatwoot.run();\n\t\treturn true;\n\t}\n}","variables":[{"name":"myVar1","value":"[]"},{"name":"myVar2","value":"{}"}],"userPermissions":[]},"publishedCollection":{"name":"Scripts","pageId":"Home","pluginId":"js-plugin","pluginType":"JS","actions":[],"archivedActions":[],"body":"export default {\n\tmyVar1: [],\n\tmyVar2: {},\n\tasync verifyConfig () {\n\t\tconst api_url = await appsmith.store.api_url;\n\t\tconst api_key = await appsmith.store.api_key;\n\t\tif(!api_url && !api_key){\n\t\t\tshowModal('ModalConfig');\n\t\t\treturn false;\n\t\t}\n\t\t\n\t\tfetch_Instances.run();\n\t\tFind_Webhook.run();\n\t\tFind_Settings.run();\n\t\tFind_Chatwoot.run();\n\t\treturn true;\n\t}\n}","variables":[{"name":"myVar1","value":"[]"},{"name":"myVar2","value":"{}"}],"userPermissions":[]},"id":"Home_Scripts","deleted":false,"gitSyncId":"64c534835ebbd221b60b4c54_64c5372a5dd3482b9ab5e11e"}],"updatedResources":{"customJSLibList":[],"actionList":["Scripts.verifyConfig##ENTITY_SEPARATOR##Home","Logout##ENTITY_SEPARATOR##Home","Fetch_Instance##ENTITY_SEPARATOR##Home","Set_Websocket##ENTITY_SEPARATOR##Home","Update_ProfileName##ENTITY_SEPARATOR##Home","Set_Chatwoot##ENTITY_SEPARATOR##Home","Create_Instance##ENTITY_SEPARATOR##Home","Update_ProfileStatus##ENTITY_SEPARATOR##Home","Find_Webhook##ENTITY_SEPARATOR##Home","Update_ProfilePicture##ENTITY_SEPARATOR##Home","Find_Settings##ENTITY_SEPARATOR##Home","Set_Settings##ENTITY_SEPARATOR##Home","Set_Typebot##ENTITY_SEPARATOR##Home","Update_PrivacySettings##ENTITY_SEPARATOR##Home","Find_Typebot##ENTITY_SEPARATOR##Home","Delete##ENTITY_SEPARATOR##Home","Find_Websocket##ENTITY_SEPARATOR##Home","Find_Chatwoot##ENTITY_SEPARATOR##Home","Connect##ENTITY_SEPARATOR##Home","Remove_ProfilePicture##ENTITY_SEPARATOR##Home","Fetch_PrivacySettings##ENTITY_SEPARATOR##Home","Restart##ENTITY_SEPARATOR##Home","Set_Rabbitmq##ENTITY_SEPARATOR##Home","fetch_Instances##ENTITY_SEPARATOR##Home","Find_Rabbitmq##ENTITY_SEPARATOR##Home","Set_Webhook##ENTITY_SEPARATOR##Home","Set_TypebotChangeSessionStatus##ENTITY_SEPARATOR##Home"],"pageList":["Home"],"actionCollectionList":["Scripts##ENTITY_SEPARATOR##Home"]},"editModeTheme":{"name":"Default","displayName":"Modern","config":{"colors":{"primaryColor":"#553DE9","backgroundColor":"#F8FAFC"},"borderRadius":{"appBorderRadius":{"none":"0px","M":"0.375rem","L":"1.5rem"}},"boxShadow":{"appBoxShadow":{"none":"none","S":"0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)","M":"0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)","L":"0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)"}},"fontFamily":{"appFont":["System Default","Nunito Sans","Poppins","Inter","Montserrat","Noto Sans","Open Sans","Roboto","Rubik","Ubuntu"]}},"properties":{"colors":{"primaryColor":"#16a34a","backgroundColor":"#F8FAFC"},"borderRadius":{"appBorderRadius":"0.375rem"},"boxShadow":{"appBoxShadow":"0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)"},"fontFamily":{"appFont":"Nunito Sans"}},"stylesheet":{"AUDIO_RECORDER_WIDGET":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"BUTTON_WIDGET":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"BUTTON_GROUP_WIDGET":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","childStylesheet":{"button":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}"}}},"CAMERA_WIDGET":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"CHART_WIDGET":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"{{appsmith.theme.boxShadow.appBoxShadow}}","accentColor":"{{appsmith.theme.colors.primaryColor}}","fontFamily":"{{appsmith.theme.fontFamily.appFont}}"},"CHECKBOX_WIDGET":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}"},"CHECKBOX_GROUP_WIDGET":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}"},"CONTAINER_WIDGET":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"{{appsmith.theme.boxShadow.appBoxShadow}}"},"CIRCULAR_PROGRESS_WIDGET":{"fillColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}"},"CURRENCY_INPUT_WIDGET":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PHONE_INPUT_WIDGET":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"DATE_PICKER_WIDGET2":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"FILE_PICKER_WIDGET_V2":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"FORM_WIDGET":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"{{appsmith.theme.boxShadow.appBoxShadow}}"},"FORM_BUTTON_WIDGET":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"ICON_BUTTON_WIDGET":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"IFRAME_WIDGET":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"{{appsmith.theme.boxShadow.appBoxShadow}}"},"IMAGE_WIDGET":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"INPUT_WIDGET":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"INPUT_WIDGET_V2":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"JSON_FORM_WIDGET":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"{{appsmith.theme.boxShadow.appBoxShadow}}","submitButtonStyles":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"resetButtonStyles":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"childStylesheet":{"ARRAY":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","cellBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","cellBoxShadow":"none"},"OBJECT":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","cellBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","cellBoxShadow":"none"},"CHECKBOX":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}"},"CURRENCY_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"DATEPICKER":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"EMAIL_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTISELECT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTILINE_TEXT_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"NUMBER_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PASSWORD_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PHONE_NUMBER_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"RADIO_GROUP":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"SELECT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"SWITCH":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"TEXT_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"}}},"LIST_WIDGET":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"{{appsmith.theme.boxShadow.appBoxShadow}}"},"MAP_WIDGET":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"{{appsmith.theme.boxShadow.appBoxShadow}}"},"MAP_CHART_WIDGET":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"{{appsmith.theme.boxShadow.appBoxShadow}}","fontFamily":"{{appsmith.theme.fontFamily.appFont}}"},"MENU_BUTTON_WIDGET":{"menuColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MODAL_WIDGET":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTI_SELECT_TREE_WIDGET":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTI_SELECT_WIDGET":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTI_SELECT_WIDGET_V2":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"DROP_DOWN_WIDGET":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PROGRESSBAR_WIDGET":{"fillColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}"},"PROGRESS_WIDGET":{"fillColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}"},"CODE_SCANNER_WIDGET":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"RATE_WIDGET":{"activeColor":"{{appsmith.theme.colors.primaryColor}}"},"RADIO_GROUP_WIDGET":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"RICH_TEXT_EDITOR_WIDGET":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"{{appsmith.theme.boxShadow.appBoxShadow}}"},"STATBOX_WIDGET":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"{{appsmith.theme.boxShadow.appBoxShadow}}"},"SWITCH_WIDGET":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"SWITCH_GROUP_WIDGET":{"accentColor":"{{appsmith.theme.colors.primaryColor}}"},"SELECT_WIDGET":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"TABLE_WIDGET":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"{{appsmith.theme.boxShadow.appBoxShadow}}","childStylesheet":{"button":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"menuButton":{"menuColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"iconButton":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"}}},"TABLE_WIDGET_V2":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"{{appsmith.theme.boxShadow.appBoxShadow}}","childStylesheet":{"button":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"menuButton":{"menuColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"iconButton":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"editActions":{"saveButtonColor":"{{appsmith.theme.colors.primaryColor}}","saveBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","discardButtonColor":"{{appsmith.theme.colors.primaryColor}}","discardBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}"}}},"TABS_WIDGET":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"{{appsmith.theme.boxShadow.appBoxShadow}}"},"TEXT_WIDGET":{"truncateButtonColor":"{{appsmith.theme.colors.primaryColor}}","fontFamily":"{{appsmith.theme.fontFamily.appFont}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}"},"VIDEO_WIDGET":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"{{appsmith.theme.boxShadow.appBoxShadow}}"},"SINGLE_SELECT_TREE_WIDGET":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"CATEGORY_SLIDER_WIDGET":{"accentColor":"{{appsmith.theme.colors.primaryColor}}"},"NUMBER_SLIDER_WIDGET":{"accentColor":"{{appsmith.theme.colors.primaryColor}}"},"RANGE_SLIDER_WIDGET":{"accentColor":"{{appsmith.theme.colors.primaryColor}}"}},"isSystemTheme":false,"deleted":false},"publishedTheme":{"name":"Default","displayName":"Modern","config":{"colors":{"primaryColor":"#553DE9","backgroundColor":"#F8FAFC"},"borderRadius":{"appBorderRadius":{"none":"0px","M":"0.375rem","L":"1.5rem"}},"boxShadow":{"appBoxShadow":{"none":"none","S":"0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)","M":"0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)","L":"0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)"}},"fontFamily":{"appFont":["System Default","Nunito Sans","Poppins","Inter","Montserrat","Noto Sans","Open Sans","Roboto","Rubik","Ubuntu"]}},"properties":{"colors":{"primaryColor":"#16a34a","backgroundColor":"#F8FAFC"},"borderRadius":{"appBorderRadius":"0.375rem"},"boxShadow":{"appBoxShadow":"0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)"},"fontFamily":{"appFont":"Nunito Sans"}},"stylesheet":{"AUDIO_RECORDER_WIDGET":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"BUTTON_WIDGET":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"BUTTON_GROUP_WIDGET":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","childStylesheet":{"button":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}"}}},"CAMERA_WIDGET":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"CHART_WIDGET":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"{{appsmith.theme.boxShadow.appBoxShadow}}","accentColor":"{{appsmith.theme.colors.primaryColor}}","fontFamily":"{{appsmith.theme.fontFamily.appFont}}"},"CHECKBOX_WIDGET":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}"},"CHECKBOX_GROUP_WIDGET":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}"},"CONTAINER_WIDGET":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"{{appsmith.theme.boxShadow.appBoxShadow}}"},"CIRCULAR_PROGRESS_WIDGET":{"fillColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}"},"CURRENCY_INPUT_WIDGET":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PHONE_INPUT_WIDGET":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"DATE_PICKER_WIDGET2":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"FILE_PICKER_WIDGET_V2":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"FORM_WIDGET":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"{{appsmith.theme.boxShadow.appBoxShadow}}"},"FORM_BUTTON_WIDGET":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"ICON_BUTTON_WIDGET":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"IFRAME_WIDGET":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"{{appsmith.theme.boxShadow.appBoxShadow}}"},"IMAGE_WIDGET":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"INPUT_WIDGET":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"INPUT_WIDGET_V2":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"JSON_FORM_WIDGET":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"{{appsmith.theme.boxShadow.appBoxShadow}}","submitButtonStyles":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"resetButtonStyles":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"childStylesheet":{"ARRAY":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","cellBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","cellBoxShadow":"none"},"OBJECT":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none","cellBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","cellBoxShadow":"none"},"CHECKBOX":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}"},"CURRENCY_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"DATEPICKER":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"EMAIL_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTISELECT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTILINE_TEXT_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"NUMBER_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PASSWORD_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PHONE_NUMBER_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"RADIO_GROUP":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"SELECT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"SWITCH":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"TEXT_INPUT":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"}}},"LIST_WIDGET":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"{{appsmith.theme.boxShadow.appBoxShadow}}"},"MAP_WIDGET":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"{{appsmith.theme.boxShadow.appBoxShadow}}"},"MAP_CHART_WIDGET":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"{{appsmith.theme.boxShadow.appBoxShadow}}","fontFamily":"{{appsmith.theme.fontFamily.appFont}}"},"MENU_BUTTON_WIDGET":{"menuColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MODAL_WIDGET":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTI_SELECT_TREE_WIDGET":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTI_SELECT_WIDGET":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"MULTI_SELECT_WIDGET_V2":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"DROP_DOWN_WIDGET":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"PROGRESSBAR_WIDGET":{"fillColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}"},"PROGRESS_WIDGET":{"fillColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}"},"CODE_SCANNER_WIDGET":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"RATE_WIDGET":{"activeColor":"{{appsmith.theme.colors.primaryColor}}"},"RADIO_GROUP_WIDGET":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"RICH_TEXT_EDITOR_WIDGET":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"{{appsmith.theme.boxShadow.appBoxShadow}}"},"STATBOX_WIDGET":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"{{appsmith.theme.boxShadow.appBoxShadow}}"},"SWITCH_WIDGET":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","boxShadow":"none"},"SWITCH_GROUP_WIDGET":{"accentColor":"{{appsmith.theme.colors.primaryColor}}"},"SELECT_WIDGET":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"TABLE_WIDGET":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"{{appsmith.theme.boxShadow.appBoxShadow}}","childStylesheet":{"button":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"menuButton":{"menuColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"iconButton":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"}}},"TABLE_WIDGET_V2":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"{{appsmith.theme.boxShadow.appBoxShadow}}","childStylesheet":{"button":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"menuButton":{"menuColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"iconButton":{"buttonColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"editActions":{"saveButtonColor":"{{appsmith.theme.colors.primaryColor}}","saveBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","discardButtonColor":"{{appsmith.theme.colors.primaryColor}}","discardBorderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}"}}},"TABS_WIDGET":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"{{appsmith.theme.boxShadow.appBoxShadow}}"},"TEXT_WIDGET":{"truncateButtonColor":"{{appsmith.theme.colors.primaryColor}}","fontFamily":"{{appsmith.theme.fontFamily.appFont}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}"},"VIDEO_WIDGET":{"borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"{{appsmith.theme.boxShadow.appBoxShadow}}"},"SINGLE_SELECT_TREE_WIDGET":{"accentColor":"{{appsmith.theme.colors.primaryColor}}","borderRadius":"{{appsmith.theme.borderRadius.appBorderRadius}}","boxShadow":"none"},"CATEGORY_SLIDER_WIDGET":{"accentColor":"{{appsmith.theme.colors.primaryColor}}"},"NUMBER_SLIDER_WIDGET":{"accentColor":"{{appsmith.theme.colors.primaryColor}}"},"RANGE_SLIDER_WIDGET":{"accentColor":"{{appsmith.theme.colors.primaryColor}}"}},"isSystemTheme":false,"deleted":false}} diff --git a/Extras/chatwoot/criador_de_inbox.json b/Extras/chatwoot/criador_de_inbox.json index ddf32ace..fa8bcf4d 100644 --- a/Extras/chatwoot/criador_de_inbox.json +++ b/Extras/chatwoot/criador_de_inbox.json @@ -1,22 +1,6 @@ { - "name": "[Evolution] Criador de Inbox", + "name": "criador_de_inbox_evo_v2.0", "nodes": [ - { - "parameters": { - "httpMethod": "POST", - "path": "inbox_whatsapp", - "options": {} - }, - "id": "8205b929-73e9-456a-9b0d-e1474991663a", - "name": "Webhook", - "type": "n8n-nodes-base.webhook", - "typeVersion": 1, - "position": [ - 320, - 300 - ], - "webhookId": "cf37002d-3869-4bb1-af3a-739fdd3c1756" - }, { "parameters": { "method": "POST", @@ -39,108 +23,140 @@ "parameters": [ { "name": "instanceName", - "value": "={{ $json.instance_name }}" + "value": "={{ $json.instanceName }}" }, { "name": "qrcode", "value": "={{ $json.qrcode }}" }, { - "name": "chatwoot_account_id", - "value": "={{ $json.chatwoot_account_id }}" + "name": "chatwootAccountId", + "value": "={{ $json.chatwootAccountId }}" }, { - "name": "chatwoot_token", - "value": "={{ $json.chatwoot_token }}" + "name": "chatwootToken", + "value": "={{ $json.chatwootToken }}" }, { - "name": "chatwoot_url", - "value": "={{ $json.chatwoot_url }}" + "name": "chatwootUrl", + "value": "={{ $json.chatwootUrl }}" }, { - "name": "chatwoot_sign_msg", - "value": "={{ $json.chatwoot_sign_msg }}" + "name": "chatwootSignMsg", + "value": "={{ $json.chatwootSignMsg }}" }, { - "name": "chatwoot_reopen_conversation", - "value": "={{ $json.chatwoot_reopen_conversation }}" + "name": "chatwootReopenConversation", + "value": "={{ $json.chatwootReopenConversation }}" }, { - "name": "chatwoot_conversation_pending", - "value": "={{ $json.chatwoot_conversation_pending }}" + "name": "chatwootConversationPending", + "value": "={{ $json.chatwootConversationPending }}" }, { - "name": "reject_call", - "value": "={{ $json.reject_call }}" + "name": "rejectCall", + "value": "={{ $json.rejectCall }}" }, { - "name": "msg_call", - "value": "={{ $json.msg_call }}" + "name": "msgCall", + "value": "={{ $json.msgCall }}" }, { - "name": "groups_ignore", - "value": "={{ $json.groups_ignore }}" + "name": "groupsIgnore", + "value": "={{ $json.groupsIgnore }}" }, { - "name": "always_online", - "value": "={{ $json.always_online }}" + "name": "alwaysOnline", + "value": "={{ $json.alwaysOnline }}" }, { - "name": "read_messages", - "value": "={{ $json.read_messages }}" + "name": "readMessages", + "value": "={{ $json.readMessages }}" }, { - "name": "read_status", - "value": "={{ $json.read_status }}" + "name": "readStatus", + "value": "={{ $json.readStatus }}" + }, + { + "name": "chatwootImportContacts", + "value": "={{ $json.chatwootImportContacts }}" + }, + { + "name": "chatwootImportMessages", + "value": "={{ $json.chatwootImportMessages }}" + }, + { + "name": "chatwootDaysLimitImportMessages", + "value": "={{ $json.chatwootDaysLimitImportMessages }}" + }, + { + "name": "syncFullHistory", + "value": "={{ $json.syncFullHistory }}" + }, + { + "name": "chatwootMergeBrazilContacts", + "value": "={{ $json.chatwootMergeBrazilContacts }}" + }, + { + "name": "integration", + "value": "={{ $json.integration }}" + }, + { + "name": "chatwootNameInbox", + "value": "={{ $json.chatwootNameInbox }}" + }, + { + "name": "token", + "value": "={{ $json.token }}" } ] }, "options": {} }, - "id": "275aa370-2fdb-42f4-844a-2fb3051301bd", + "id": "7da41431-cc8e-4eb4-9894-7bf413819fe3", "name": "Cria Instancia", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.1, "position": [ - 760, - 300 + 900, + 680 ] }, { "parameters": { - "url": "={{ $('Info Base').item.json[\"chatwoot_url\"] }}/api/v1/accounts/{{ $('Info Base').item.json[\"chatwoot_account_id\"] }}/inboxes/", + "url": "={{ $('Info Base').item.json[\"chatwootUrl\"] }}/api/v1/accounts/{{ $('Info Base').item.json[\"chatwootAccountId\"] }}/inboxes/", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "api_access_token", - "value": "={{ $('Info Base').item.json.chatwoot_token }}" + "value": "={{ $('Info Base').item.json.chatwootToken }}" } ] }, "options": {} }, - "id": "e4650812-ba0a-4f72-8bd8-a235eca4b2de", + "id": "d51fbbfe-4579-4fba-949f-c29e0b806feb", "name": "Lista Inboxes", "type": "n8n-nodes-base.httpRequest", "typeVersion": 3, "position": [ - 980, - 300 + 1120, + 680 ] }, { "parameters": { - "content": "## Workflow Para Criar Inbox\n**Aqui você configura a comunicação entre o chatwoot e a Evolution API para criar novas instâncias a partir do chatwoot**\n**Instruções**\n**No node Info Base, configure as variáveis de seu Chatwoot e Evolution API**", + "content": "## Workflow Para Criar Inbox - Evolution 2.0 ou superior\n**Aqui você configura a comunicação entre o chatwoot e a Evolution API para criar novas instâncias a partir do chatwoot**\n**Instruções**\n**No node Info Base, configure as variáveis de seu Chatwoot e Evolution API**", "width": 1129.7777777777778 }, - "id": "aa763d9e-d973-44fc-8399-277bb24718a5", + "id": "7c66af51-b01e-4b76-8a8c-0193e87ec9d5", "name": "Sticky Note", "type": "n8n-nodes-base.stickyNote", "typeVersion": 1, "position": [ - 320, - 80 + 460, + 460 ] }, { @@ -149,32 +165,48 @@ "values": { "string": [ { - "name": "chatwoot_url", - "value": "CHATWOOT_URL" + "name": "chatwootUrl", + "value": "https://chatwootUrl - preencha" }, { "name": "evolution_url", - "value": "EVOLUTION_URL" + "value": "https://evolution_url - preencha" }, { "name": "global_api_key", - "value": "EVOLUTION_GLOBAL_API_KEY" + "value": "global_api_key - preencha" }, { "name": "organization", "value": "={{ $json.query.organization }}" }, { - "name": "instance_name", + "name": "instanceName", "value": "={{ $json.body.messages[0].content.split(':')[1] }}-cwId-{{ $json.body.messages[0].account_id }}" }, { - "name": "chatwoot_token", + "name": "chatwootToken", "value": "={{ $json.query.utoken }}" }, { - "name": "msg_call", + "name": "msgCall", "value": "Não aceitamos chamadas, por favor deixe uma mensagem!" + }, + { + "name": "integration", + "value": "WHATSAPP-BAILEYS" + }, + { + "name": "chatwootNameInbox", + "value": "={{ $json.body.messages[0].content.split(':')[1] }}" + }, + { + "name": "chatwootAccountId", + "value": "={{ $json.body.messages[0].account_id.toString() }}" + }, + { + "name": "token", + "value": "=AfRw{{ Date.now() }}BeH4" } ], "boolean": [ @@ -183,51 +215,67 @@ "value": true }, { - "name": "chatwoot_sign_msg", + "name": "chatwootSignMsg", "value": true }, { - "name": "chatwoot_reopen_conversation", + "name": "chatwootReopenConversation", "value": true }, { - "name": "chatwoot_conversation_pending" + "name": "chatwootConversationPending" }, { - "name": "reject_call", + "name": "rejectCall" + }, + { + "name": "groupsIgnore" + }, + { + "name": "alwaysOnline", "value": true }, { - "name": "groups_ignore" - }, - { - "name": "always_online", + "name": "readMessages", "value": true }, { - "name": "read_messages", + "name": "readStatus" + }, + { + "name": "chatwootImportMessages", "value": true }, { - "name": "read_status" + "name": "chatwootImportContacts", + "value": true + }, + { + "name": "syncFullHistory" + }, + { + "name": "chatwootMergeBrazilContacts", + "value": true } ], "number": [ { - "name": "chatwoot_account_id", - "value": "={{ $json.body.messages[0].account_id }}" + "name": "chatwootDaysLimitImportMessages", + "value": 60 } ] }, - "options": {} + "options": { + "dotNotation": false + } }, - "id": "297df325-ecc4-4a34-817c-092d16d5753b", + "id": "eaffbc44-3701-4f8d-b923-92061cfb995f", "name": "Info Base", "type": "n8n-nodes-base.set", "typeVersion": 2, "position": [ - 540, - 300 + 680, + 680 ] }, { @@ -241,13 +289,13 @@ ] } }, - "id": "a8d955e6-ac51-4316-aeec-09d4d65e943a", + "id": "82eb24c8-2269-4622-b012-d6f6ad35c149", "name": "é Start Inbox?", "type": "n8n-nodes-base.if", "typeVersion": 1, "position": [ - 1660, - 200 + 1800, + 600 ] }, { @@ -255,15 +303,80 @@ "batchSize": 1, "options": {} }, - "id": "0d2d2194-aa4a-4241-9022-217d88bb581f", + "id": "b9de1318-ab0b-4529-b30a-2daea64dbcfe", "name": "Split In Batches", "type": "n8n-nodes-base.splitInBatches", "typeVersion": 2, "position": [ - 1420, - 300 + 1560, + 680 ] }, + { + "parameters": { + "method": "DELETE", + "url": "={{ $('Info Base').item.json[\"chatwootUrl\"] }}/api/v1/accounts/{{ $('Info Base').item.json[\"chatwootAccountId\"] }}/inboxes/{{ $json.id }}", + "sendHeaders": true, + "headerParameters": { + "parameters": [ + { + "name": "api_access_token", + "value": "={{ $('Info Base').item.json.chatwootToken }}" + } + ] + }, + "options": {} + }, + "id": "db2ad958-7642-41eb-8e9a-e8b1668230d1", + "name": "Deleta Inbox Start", + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 3, + "position": [ + 2040, + 480 + ] + }, + { + "parameters": {}, + "id": "6d68d3a7-d613-471f-8492-9ec473481521", + "name": "No Operation, do nothing", + "type": "n8n-nodes-base.noOp", + "typeVersion": 1, + "position": [ + 1800, + 780 + ] + }, + { + "parameters": { + "fieldToSplitOut": "payload", + "options": {} + }, + "id": "be833e77-b2ae-44c6-b4fc-ad24ffc8ad9a", + "name": "Ajusta lista", + "type": "n8n-nodes-base.itemLists", + "typeVersion": 2.2, + "position": [ + 1340, + 680 + ] + }, + { + "parameters": { + "httpMethod": "POST", + "path": "inbox_whatsapp", + "options": {} + }, + "id": "faae80e0-9070-4a0c-83bc-d47643a64653", + "name": "Webhook", + "type": "n8n-nodes-base.webhook", + "typeVersion": 1, + "position": [ + 460, + 680 + ], + "webhookId": "85cb0c27-4223-4339-b7b4-35a16c0a04b8" + }, { "parameters": { "conditions": { @@ -275,25 +388,25 @@ ] } }, - "id": "0bfbc2cb-eff5-423c-bd3a-b266aaf6a943", + "id": "4ea7b74f-bdc5-4619-8e99-1f5d33c7e28e", "name": "é_pre-existente?", "type": "n8n-nodes-base.if", "typeVersion": 1, "position": [ - 1900, - 340 + 1980, + 700 ] }, { "parameters": { "method": "PATCH", - "url": "={{ $('Info Base').item.json[\"chatwoot_url\"] }}/api/v1/accounts/{{ $('Info Base').item.json[\"chatwoot_account_id\"] }}/inboxes/{{ $json.id }}", + "url": "={{ $('Info Base').item.json[\"chatwootUrl\"] }}/api/v1/accounts/{{ $('Info Base').item.json[\"chatwootAccountId\"] }}/inboxes/{{ $json.id }}", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "api_access_token", - "value": "={{ $('Info Base').item.json.chatwoot_token }}" + "value": "={{ $('Info Base').item.json.chatwootToken }}" }, { "name": "Content-Type", @@ -303,75 +416,26 @@ }, "sendBody": true, "specifyBody": "json", - "jsonBody": "={\n\"channel\": {\n\"webhook_url\": \"{{ $('Info Base').item.json[\"evolution_url\"] }}/chatwoot/webhook/{{ encodeURIComponent($('Info Base').item.json[\"instance_name\"]) }}\"\n}\n}", + "jsonBody": "={\n\"channel\": {\n\"webhook_url\": \"{{ $('Info Base').item.json[\"evolution_url\"] }}/chatwoot/webhook/{{ encodeURIComponent($('Info Base').item.json[\"instanceName\"]) }}\"\n}\n}", "options": {} }, - "id": "fb589456-5566-4a45-96a7-75986d0aa1d5", + "id": "74d6db21-d49e-48d6-b1a8-ff8bddca67d1", "name": "Update_webhook_url", "type": "n8n-nodes-base.httpRequest", "typeVersion": 3, "position": [ - 2120, - 340 - ] - }, - { - "parameters": { - "method": "DELETE", - "url": "={{ $('Info Base').item.json[\"chatwoot_url\"] }}/api/v1/accounts/{{ $('Info Base').item.json[\"chatwoot_account_id\"] }}/inboxes/{{ $json.id }}", - "sendHeaders": true, - "headerParameters": { - "parameters": [ - { - "name": "api_access_token", - "value": "={{ $('Info Base').item.json.chatwoot_token }}" - } - ] - }, - "options": {} - }, - "id": "e6094941-410f-496c-9c9c-7b95fd9349af", - "name": "Deleta Inbox Start", - "type": "n8n-nodes-base.httpRequest", - "typeVersion": 3, - "position": [ - 1900, - 100 - ] - }, - { - "parameters": {}, - "id": "8cf9a78f-9e8a-4288-9d7b-801790af68d5", - "name": "No Operation, do nothing", - "type": "n8n-nodes-base.noOp", - "typeVersion": 1, - "position": [ - 1660, - 400 - ] - }, - { - "parameters": { - "fieldToSplitOut": "payload", - "options": {} - }, - "id": "9468896a-5f86-4598-9d20-e8f495cae859", - "name": "Ajusta lista", - "type": "n8n-nodes-base.itemLists", - "typeVersion": 2.2, - "position": [ - 1200, - 300 + 2200, + 700 ] } ], "pinData": {}, "connections": { - "Webhook": { + "Cria Instancia": { "main": [ [ { - "node": "Info Base", + "node": "Lista Inboxes", "type": "main", "index": 0 } @@ -389,17 +453,6 @@ ] ] }, - "Cria Instancia": { - "main": [ - [ - { - "node": "Lista Inboxes", - "type": "main", - "index": 0 - } - ] - ] - }, "Info Base": { "main": [ [ @@ -447,6 +500,39 @@ ] ] }, + "Deleta Inbox Start": { + "main": [ + [ + { + "node": "Split In Batches", + "type": "main", + "index": 0 + } + ] + ] + }, + "Ajusta lista": { + "main": [ + [ + { + "node": "Split In Batches", + "type": "main", + "index": 0 + } + ] + ] + }, + "Webhook": { + "main": [ + [ + { + "node": "Info Base", + "type": "main", + "index": 0 + } + ] + ] + }, "é_pre-existente?": { "main": [ [ @@ -475,36 +561,17 @@ } ] ] - }, - "Deleta Inbox Start": { - "main": [ - [ - { - "node": "Split In Batches", - "type": "main", - "index": 0 - } - ] - ] - }, - "Ajusta lista": { - "main": [ - [ - { - "node": "Split In Batches", - "type": "main", - "index": 0 - } - ] - ] } }, - "active": true, - "settings": {}, - "versionId": "ab910349-b559-4738-9ac6-de6b06d6bbce", - "id": "ByW2ccjR4XPrOyio", - "meta": { - "instanceId": "4ff16e963c7f5197d7e99e6239192860914312fea0ce2a9a7fd14d74a0a0e906" + "active": false, + "settings": { + "executionOrder": "v1" }, + "versionId": "68f9fa60-e295-4b74-8cb3-c4723d6cb2b2", + "meta": { + "templateCredsSetupCompleted": true, + "instanceId": "8ed3edb9203bfe03a4b94f63390235285fbb1c230430fdae73a456b9fae762d5" + }, + "id": "f6dLbF7I7nrjcDc4", "tags": [] -} \ No newline at end of file +} diff --git a/Extras/typebot/typebot-example.json b/Extras/typebot/typebot-example.json deleted file mode 100644 index c45cd509..00000000 --- a/Extras/typebot/typebot-example.json +++ /dev/null @@ -1 +0,0 @@ -{"id":"l27ft2bq9a7tke15i7m64d9o","version":"3","createdAt":"2023-08-04T17:27:18.072Z","updatedAt":"2023-08-20T13:35:33.073Z","icon":null,"name":"[Dgcode] [whatsapp] Pesquisa Satisfacao","folderId":"cll1fzkfy0008pa65kgz3tm86","groups":[{"id":"c76ucoughhenpernmadu7ibg","title":"Start","blocks":[{"id":"qn40kjwtw1he3l1bujt3bnje","type":"start","label":"Start","groupId":"c76ucoughhenpernmadu7ibg","outgoingEdgeId":"aovnigvk665gzhyzg7bxhvn0"}],"graphCoordinates":{"x":-126.43,"y":220.29}},{"id":"nog2woqmvhssnnjlcpwd41k5","title":"Apresentação","blocks":[{"id":"potdr8jwrn6mnkjipynqjmhh","type":"Set variable","groupId":"nog2woqmvhssnnjlcpwd41k5","options":{"type":"Random ID","variableId":"vsu5or5sxes9lyuhsgcl3cuyd"}},{"id":"mcpyoq8x28bnwp23g7h1dbc1","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Olá! {{pushName}} Bem-vindo(a) à nossa "},{"bold":true,"text":"pesquisa de satisfação"},{"text":"."}]}]},"groupId":"nog2woqmvhssnnjlcpwd41k5"},{"id":"o0731ch0epj2vm2c5aoxyvw1","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Meu nome é "},{"bold":true,"text":"🤖 Mike"},{"text":", estou aqui para ouvir sua opinião e experiência com nossos serviços."}]}]},"groupId":"nog2woqmvhssnnjlcpwd41k5"},{"id":"twx683ok814enh3bwlaexe0t","type":"Wait","groupId":"nog2woqmvhssnnjlcpwd41k5","options":{"secondsToWaitFor":"5"}},{"id":"hgqbj5kmosz64cb435xqh0am","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Sua opinião é fundamental para nos ajudar a melhorar!"}]}]},"groupId":"nog2woqmvhssnnjlcpwd41k5"},{"id":"cbvgdo0jknjyzmvwe6o614ni","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Vamos começar?"}]}]},"groupId":"nog2woqmvhssnnjlcpwd41k5"},{"id":"vpj58atr9o534tjhhu0l0t0b","type":"Wait","groupId":"nog2woqmvhssnnjlcpwd41k5","options":{"secondsToWaitFor":"5"}},{"id":"nmhkn4jod3evk08tbq5vw3s3","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Qual o seu nome?"}]}]},"groupId":"nog2woqmvhssnnjlcpwd41k5"},{"id":"o8ijci5gdfsp6fpv07kwh8br","type":"text input","groupId":"nog2woqmvhssnnjlcpwd41k5","options":{"isLong":false,"labels":{"button":"Enviar","placeholder":"Digite o seu nome"},"variableId":"vo40px5r6wg9vhs9fixd45kzn"},"outgoingEdgeId":"vwx6ofz1ur8maxcbw8fk66x9"}],"graphCoordinates":{"x":771.26,"y":213}},{"id":"j5co2kcotxafuxhzlj7u0qnn","title":"Qual seu email?","blocks":[{"id":"he1367t9ssao735kidd86mna","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Muito bem {{name}}, agora me informe seu endereço de email?"}]}]},"groupId":"j5co2kcotxafuxhzlj7u0qnn"},{"id":"qb8nwfs52g168tmnvp257b44","type":"email input","groupId":"j5co2kcotxafuxhzlj7u0qnn","options":{"labels":{"button":"Enviar","placeholder":"Digite o seu email"},"variableId":"vr75l1drc5uoxvisje0hio5ph","retryMessageContent":"Email incorreto!"},"outgoingEdgeId":"v53mvhejcapb4a1zq98swq5b"}],"graphCoordinates":{"x":1236.92,"y":204.84}},{"id":"wtd0o382phaji7i7u2n8pody","title":"Pergunta 1","blocks":[{"id":"zr69lw3bcmmkgahqq8og7shw","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Em uma escala de 0 a 10, qual é o seu nível de satisfação geral com os serviços que nossa empresa fornece?"}]}]},"groupId":"wtd0o382phaji7i7u2n8pody"},{"id":"ku0zpu43cbbnd7y0ai71ptde","type":"rating input","groupId":"wtd0o382phaji7i7u2n8pody","options":{"labels":{"button":"Send"},"length":10,"buttonType":"Numbers","customIcon":{"isEnabled":false},"variableId":"vbfl3sqze2wzicn9l1n9ckjs4"},"outgoingEdgeId":"ed1x8zan90zvrpo9xk9moroe"}],"graphCoordinates":{"x":1692.4,"y":194.19}},{"id":"ylerbfc1l2o62j68g8ghegxt","title":"Pergunta 2","blocks":[{"id":"l19jgtpln9al473dudr0gbzn","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Em uma escala de 0 a 10, em que medida nossa empresa atendeu às suas expectativas em termos de qualidade do serviço prestado?"}]}]},"groupId":"ylerbfc1l2o62j68g8ghegxt"},{"id":"kfxuc6p58cdzy1xcyp4i4ra7","type":"rating input","groupId":"ylerbfc1l2o62j68g8ghegxt","options":{"labels":{"button":"Send"},"length":10,"buttonType":"Numbers","customIcon":{"isEnabled":false},"variableId":"vkgl2bfdbyms1dyc1s6efx678"},"outgoingEdgeId":"iy61ajcfl6ubbj7zghxeu6f7"}],"graphCoordinates":{"x":2156.14,"y":190.76}},{"id":"lbieknd0qp42pogsby5l82ww","title":"Pergunta 3","blocks":[{"id":"y43s12dnoxh772c9o3pmnhxf","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Você teve alguma dificuldade em se comunicar com nossa equipe de suporte ao cliente?"}]},{"type":"p","children":[{"text":""}]},{"type":"p","children":[{"text":"1 - Sim"}]},{"type":"p","children":[{"text":"2 - Não"}]}]},"groupId":"lbieknd0qp42pogsby5l82ww"},{"id":"fb6ckchqp8vx9ypig07we6q4","type":"text input","groupId":"lbieknd0qp42pogsby5l82ww","options":{"isLong":false,"labels":{"button":"Enviar","placeholder":"Responda com uma das opções"},"variableId":"vzhsu0uc4suqoz38kv3q891ma"}},{"id":"b538q1mt18l6oddo397nh1m4","type":"Condition","items":[{"id":"dwhc3ptqvktlgfvl17xg79s5","type":1,"blockId":"b538q1mt18l6oddo397nh1m4","content":{"comparisons":[{"id":"rln6ido55pzqyr9ihqp3r0oe","value":"^([Ss][IiÍí][Mm]|1)$","variableId":"vzhsu0uc4suqoz38kv3q891ma","comparisonOperator":"Matches regex"}],"logicalOperator":"OR"},"outgoingEdgeId":"w6ao5pi6wt0966tobkned56m"},{"id":"cod3tkt16ry8ixm5u7rwxzm9","type":1,"blockId":"b538q1mt18l6oddo397nh1m4","content":{"comparisons":[{"id":"n0dm7n4vyowa9bftkmu0ypud","value":"^([Nn][AaÃã][Oo]|2)$","variableId":"vzhsu0uc4suqoz38kv3q891ma","comparisonOperator":"Matches regex"}],"logicalOperator":"OR"},"outgoingEdgeId":"wlfmh2g3j5avj75sa9q6rsab"}],"groupId":"lbieknd0qp42pogsby5l82ww","outgoingEdgeId":"ehcwqdrkc4025pui2y1s9390"}],"graphCoordinates":{"x":2605.34,"y":189.93}},{"id":"qzhp25b9f2lvt4yeniqvjkav","title":"Pergunta 4","blocks":[{"id":"pos7njae2r35r29kcbyxtz2j","type":"text","content":{"richText":[{"type":"p","children":[{"text":"{{name}}, por favor, descreva o problema para que possamos melhorar."}]}]},"groupId":"qzhp25b9f2lvt4yeniqvjkav"},{"id":"ce2eodve0e4f2rubk4wv5jf1","type":"text input","groupId":"qzhp25b9f2lvt4yeniqvjkav","options":{"isLong":false,"labels":{"button":"Enviar","placeholder":"Descreva o problema"},"variableId":"vd6fm2i9shcdjz8bhhwbsdh6t"},"outgoingEdgeId":"i11xudmpsb1tbsss7qoge6cm"}],"graphCoordinates":{"x":3041.23,"y":187.11}},{"id":"c8kh8eee1m3wyy372v4n6m1i","title":"Pergunta 5","blocks":[{"id":"txqi87lwinpa0p5of0xmqxu6","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Em uma escala de 0 a 10, como você avalia a capacidade da nossa empresa de cumprir os prazos acordados?"}]}]},"groupId":"c8kh8eee1m3wyy372v4n6m1i"},{"id":"mg2tmcmwnx3tap0hs4b7e0la","type":"rating input","groupId":"c8kh8eee1m3wyy372v4n6m1i","options":{"labels":{"button":"Enviar"},"length":10,"buttonType":"Numbers","customIcon":{"isEnabled":false},"variableId":"vz6lvahwo15dosvckdtkxduly"},"outgoingEdgeId":"c9nrzzcxt8w4dgk2sfez53n5"}],"graphCoordinates":{"x":3501.8,"y":179.58}},{"id":"tn8bcyughy9dsxhmjngrosvj","title":"Pergunta 6","blocks":[{"id":"aema350m33n9dljopcsxn8q5","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Você recomendaria nossos serviços para outras pessoas ou empresas?"}]},{"type":"p","children":[{"text":""}]},{"type":"p","children":[{"text":"1 - Sim"}]},{"type":"p","children":[{"text":"2 - Não"}]}]},"groupId":"tn8bcyughy9dsxhmjngrosvj"},{"id":"wk4bkxbxcfu9skrzn8p8077u","type":"text input","groupId":"tn8bcyughy9dsxhmjngrosvj","options":{"isLong":false,"labels":{"button":"Enviar","placeholder":"Responda com uma das opções"},"variableId":"vndjnalmnb3ez9beeon5tzrgq"}},{"id":"n3j2dxaalkljl020o0o61ef9","type":"Condition","items":[{"id":"ifhm8cj8lsulhrarnfda2oal","type":1,"blockId":"n3j2dxaalkljl020o0o61ef9","content":{"comparisons":[{"id":"rln6ido55pzqyr9ihqp3r0oe","value":"^([Ss][IiÍí][Mm]|1)$","variableId":"vndjnalmnb3ez9beeon5tzrgq","comparisonOperator":"Matches regex"}],"logicalOperator":"OR"},"outgoingEdgeId":"yu9762ttf5jn3bmhd6uzrsv8"},{"id":"gxp6j3ouga4r0t8364tn8axs","type":1,"blockId":"n3j2dxaalkljl020o0o61ef9","content":{"comparisons":[{"id":"n0dm7n4vyowa9bftkmu0ypud","value":"^([Nn][AaÃã][Oo]|2)$","variableId":"vndjnalmnb3ez9beeon5tzrgq","comparisonOperator":"Matches regex"}],"logicalOperator":"OR"},"outgoingEdgeId":"ji1y2o1hldhemto0ymwou09c"}],"groupId":"tn8bcyughy9dsxhmjngrosvj","outgoingEdgeId":"d3u83fikqplfy9ntva3sm7eg"}],"graphCoordinates":{"x":3926.41,"y":186.15}},{"id":"nzkhdw3hdv550aepsxvk2a0u","title":"Pergunta 7","blocks":[{"id":"io90onrpfrokejgkps94r3dj","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Que pena {{name}}, por gentileza, nos conte o motivo?"}]}]},"groupId":"nzkhdw3hdv550aepsxvk2a0u"},{"id":"dj7dbgyjqk0a5u3jn6kzykb2","type":"text input","groupId":"nzkhdw3hdv550aepsxvk2a0u","options":{"isLong":false,"labels":{"button":"Enviar","placeholder":"Digite o motivo"},"variableId":"vept0w6tr0w7eyyi52hgq1r3c"},"outgoingEdgeId":"k7vrrf5cfxopvmhsbf35bt3m"}],"graphCoordinates":{"x":4352.64,"y":194.04}},{"id":"jdz9w8vrz09vefk4wqrf0vwl","title":"Pergunta 8","blocks":[{"id":"hndzyb58fqxudykajr22skla","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Existe alguma sugestão que você gostaria de nos dar para melhorar nossos serviços?"}]},{"type":"p","children":[{"text":""}]},{"type":"p","children":[{"text":"1 - Sim"}]},{"type":"p","children":[{"text":"2 - Não"}]}]},"groupId":"jdz9w8vrz09vefk4wqrf0vwl"},{"id":"ol9l8fdb3q65auykrn383q6d","type":"text input","groupId":"jdz9w8vrz09vefk4wqrf0vwl","options":{"isLong":false,"labels":{"button":"Enviar","placeholder":"Responda com uma das opções"},"variableId":"vy5it60mewmth7mayzhlgmzf0"}},{"id":"zderh9hqjkpuz58p79szfa1i","type":"Condition","items":[{"id":"lur26nqa8dv7m4jmmljpyyf1","type":1,"blockId":"zderh9hqjkpuz58p79szfa1i","content":{"comparisons":[{"id":"rln6ido55pzqyr9ihqp3r0oe","value":"^([Ss][IiÍí][Mm]|1)$","variableId":"vy5it60mewmth7mayzhlgmzf0","comparisonOperator":"Matches regex"}],"logicalOperator":"OR"},"outgoingEdgeId":"x2fzu1uuukp9cgmdzecp7mgk"},{"id":"aoj7e49zimwxng4o7bd6u00s","type":1,"blockId":"zderh9hqjkpuz58p79szfa1i","content":{"comparisons":[{"id":"n0dm7n4vyowa9bftkmu0ypud","value":"^([Nn][AaÃã][Oo]|2)$","variableId":"vy5it60mewmth7mayzhlgmzf0","comparisonOperator":"Matches regex"}],"logicalOperator":"OR"},"outgoingEdgeId":"mb1fg83gijikrafud2ml6zbn"}],"groupId":"jdz9w8vrz09vefk4wqrf0vwl","outgoingEdgeId":"amyrx4i2rm3cjksym5zvwd50"}],"graphCoordinates":{"x":4768.69,"y":201.49}},{"id":"c4k1ftb4rbynkb01ulwuh4qh","title":"Pergunta 9","blocks":[{"id":"jqn5de3i29ygjyf6usbj117t","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Qual seria a sua sugestão?"}]}]},"groupId":"c4k1ftb4rbynkb01ulwuh4qh"},{"id":"wfucksh3yaeq21l7mnlnsx75","type":"text input","groupId":"c4k1ftb4rbynkb01ulwuh4qh","options":{"isLong":false,"labels":{"button":"Enviar","placeholder":"Deixe sua sugestão"},"variableId":"vhygxyvhu5l6r2uws1cbthmxm"},"outgoingEdgeId":"u8c55of7l95fnz25gf7swt1m"}],"graphCoordinates":{"x":5233.77,"y":205.27}},{"id":"vvyooiddvdbon0t21bvzdr7q","title":"Finalização","blocks":[{"id":"efk089lhks1ev4khy38caner","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Então {{name}}, agradecemos muito por dedicar um tempo para nos fornecer seu feedback."}]}]},"groupId":"vvyooiddvdbon0t21bvzdr7q"},{"id":"pvu3g8vpqdi3aecu2u0in2d0","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Sua opinião é muito importante para nós, e trabalharemos arduamente para melhorar ainda mais nossos serviços!"}]}]},"groupId":"vvyooiddvdbon0t21bvzdr7q"},{"id":"wqe9r1ivjf0ikubqichufzsg","type":"Webhook","groupId":"vvyooiddvdbon0t21bvzdr7q","options":{"isCustomBody":true,"isAdvancedConfig":true,"variablesForTest":[],"responseVariableMapping":[]},"webhookId":"i3g1959ev6fl9s61ir8hn1we"}],"graphCoordinates":{"x":7067.06,"y":231.55}},{"id":"ffm0s2y4head3auw808hwfnx","title":"Retorna Pergunta 3","blocks":[{"id":"ox70407atqtf1kwrszis4cix","type":"Set variable","groupId":"ffm0s2y4head3auw808hwfnx","options":{"type":"Empty","variableId":"vzhsu0uc4suqoz38kv3q891ma"}},{"id":"bcwkrcxtsc8drzwynb2igu0g","type":"Jump","groupId":"ffm0s2y4head3auw808hwfnx","options":{"groupId":"lbieknd0qp42pogsby5l82ww"}}],"graphCoordinates":{"x":3040.8,"y":772.28}},{"id":"cf8r0wx0sgw6c9v79ebja1tj","title":"Retorna Pergunta 6","blocks":[{"id":"e02yfpbpj298m1q9y4tb905i","type":"Set variable","groupId":"cf8r0wx0sgw6c9v79ebja1tj","options":{"type":"Empty","variableId":"vndjnalmnb3ez9beeon5tzrgq"}},{"id":"wjfe41oxiik0jgwcye7sczeu","type":"Jump","groupId":"cf8r0wx0sgw6c9v79ebja1tj","options":{"groupId":"tn8bcyughy9dsxhmjngrosvj"}}],"graphCoordinates":{"x":4360.16,"y":732.74}},{"id":"b7zfnwcxvu28s98ii03isdae","title":"Retorna Pergunta 8","blocks":[{"id":"j1xmpy60ggf162ej9a0rti4f","type":"Set variable","groupId":"b7zfnwcxvu28s98ii03isdae","options":{"type":"Empty","variableId":"vy5it60mewmth7mayzhlgmzf0"}},{"id":"lk06yb9dvrctn2u9tx35n12c","type":"Jump","groupId":"b7zfnwcxvu28s98ii03isdae","options":{"groupId":"jdz9w8vrz09vefk4wqrf0vwl"}}],"graphCoordinates":{"x":5213.21,"y":778}},{"id":"z0idhsnqisrd695z0j1tnqvw","title":"Retorna Pergunta 10","blocks":[{"id":"gs96ig682082mj4igcjjuh76","type":"Set variable","groupId":"z0idhsnqisrd695z0j1tnqvw","options":{"type":"Empty","variableId":"vx6p4ivk4mnssvbhl30c5zng9"}},{"id":"tihlp1xm8mvpdm3d0dqkwwx6","type":"Jump","groupId":"z0idhsnqisrd695z0j1tnqvw","options":{"groupId":"cs5kjnrcsh4bjiuvwf99agho"}}],"graphCoordinates":{"x":6100.86,"y":819.65}},{"id":"qsrkmfsr04kayulair47gmn0","title":"Gera QRCODE pix","blocks":[{"id":"qs1uxqm8jqla9uui43ofms65","type":"Webhook","groupId":"qsrkmfsr04kayulair47gmn0","options":{"isCustomBody":true,"isAdvancedConfig":true,"variablesForTest":[],"responseVariableMapping":[{"id":"gcia6kdba4yydt14klsg8h6x","bodyPath":"data.qrcode_base64","variableId":"vamn8ortov9nk1y04vczo375h"}]},"webhookId":"ajx8mv7trd50mbv2uj6fr3x5"},{"id":"sz447ty7t4vreto9bf07h52i","type":"Set variable","groupId":"qsrkmfsr04kayulair47gmn0","options":{"type":"Custom","variableId":"vamn8ortov9nk1y04vczo375h","expressionToEvaluate":"if({{remoteJid}}){\n return {{qrcode}}.replace('data:image/png;base64,', ''); \n}else{\n return {{qrcode}}\n}\n"}},{"id":"c3wp5ic2wx9emj6kkii42xpj","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Aqui está qrcode para sua contribuição de R$ {{question11}}, caso tenha dificuldade na leitura utilize a nossa chave:"}]},{"type":"p","children":[{"text":""}]},{"type":"p","children":[{"text":"Telefone: 7499879409"}]},{"type":"p","children":[{"text":"Em nome de: Davidson Oliveira Gomes"}]}]},"groupId":"qsrkmfsr04kayulair47gmn0"},{"id":"jncggap4fivalzgntw3bfaom","type":"image","content":{"url":"{{qrcode}}"},"groupId":"qsrkmfsr04kayulair47gmn0"},{"id":"chiz9utw18jvui4c2r0vsiqp","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Muito obrigado pela sua contribuição!"}]}]},"groupId":"qsrkmfsr04kayulair47gmn0","outgoingEdgeId":"cwlt91vwhr7gvgx0qx2mnxtr"}],"graphCoordinates":{"x":6607.75,"y":229.53}},{"id":"cs5kjnrcsh4bjiuvwf99agho","title":"Pergunta 10","blocks":[{"id":"axpk3aoauusbiy8av70fc2fo","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Gostaria de fazer uma contribuição?"}]},{"type":"p","children":[{"text":""}]},{"type":"p","children":[{"text":"1 - Sim"}]},{"type":"p","children":[{"text":"2 - Não"}]}]},"groupId":"cs5kjnrcsh4bjiuvwf99agho"},{"id":"q136n37ja1g5dyhdeisur4rg","type":"text input","groupId":"cs5kjnrcsh4bjiuvwf99agho","options":{"isLong":false,"labels":{"button":"Enviar","placeholder":"Deixe sua resposta"},"variableId":"vx6p4ivk4mnssvbhl30c5zng9"}},{"id":"xza6e0p4hgkfz1wvwcjss48s","type":"Condition","items":[{"id":"m5mvt5ecw81eevl428n56aji","type":1,"blockId":"xza6e0p4hgkfz1wvwcjss48s","content":{"comparisons":[{"id":"rln6ido55pzqyr9ihqp3r0oe","value":"^([Ss][IiÍí][Mm]|1)$","variableId":"vx6p4ivk4mnssvbhl30c5zng9","comparisonOperator":"Matches regex"}],"logicalOperator":"OR"},"outgoingEdgeId":"fe1wk4fc1xzt7mefasb2qzqz"},{"id":"bpcidulg0g7v8pwh3w9my880","type":1,"blockId":"xza6e0p4hgkfz1wvwcjss48s","content":{"comparisons":[{"id":"n0dm7n4vyowa9bftkmu0ypud","value":"^([Nn][AaÃã][Oo]|2)$","variableId":"vx6p4ivk4mnssvbhl30c5zng9","comparisonOperator":"Matches regex"}],"logicalOperator":"OR"},"outgoingEdgeId":"xg1zkpvob8ilx2r8p0kv604d"}],"groupId":"cs5kjnrcsh4bjiuvwf99agho","outgoingEdgeId":"o746eh96sq2j7juionfql73t"}],"graphCoordinates":{"x":5708.94,"y":210.9}},{"id":"tq60r6azxrmn17b4y7mjovf5","title":"Pergunta 11","blocks":[{"id":"o5fspfge731wt6m781nzjsll","type":"text","content":{"richText":[{"type":"p","children":[{"text":"Muito bem {{name}}, quanto você deseja contribuir?"}]}]},"groupId":"tq60r6azxrmn17b4y7mjovf5"},{"id":"khncvmg5fcjsmu8tlmf8in6m","type":"number input","groupId":"tq60r6azxrmn17b4y7mjovf5","options":{"max":5000,"min":1,"step":1,"labels":{"button":"Enviar","placeholder":"Digite um numero"},"variableId":"vhoqah2c0blbx92bfmd4gjnyx"},"outgoingEdgeId":"ns2kch8n15uklzwf8kn4m0lb"}],"graphCoordinates":{"x":6158.94,"y":224.91}},{"id":"h0svx6gyzgjsclr9hbpo04v6","title":"Configurações Iniciais","blocks":[{"id":"na4zglpatkg8ejqcap8lcv69","type":"Set variable","groupId":"h0svx6gyzgjsclr9hbpo04v6","options":{"variableId":"vp1ask55v2r58ukom5lek5hej","expressionToEvaluate":"https://d715-45-39-187-135.ngrok-free.app"}},{"id":"t2bdxy8x8fsn29yijk02ti43","type":"Set variable","groupId":"h0svx6gyzgjsclr9hbpo04v6","options":{"variableId":"vtsldvs2u8ui93tktazy77djw","expressionToEvaluate":"0f1c6e17-5a6a-4989-8c12-a7e7350870fe"}},{"id":"rt5h0lk6jaoh5hzag0s5hidd","type":"Set variable","groupId":"h0svx6gyzgjsclr9hbpo04v6","options":{"variableId":"vkg1qlinovziltaloqhso2cw7","expressionToEvaluate":"https://pix.dgcode.com.br"}},{"id":"mh758b8y8288t56s6wz73mht","type":"Set variable","groupId":"h0svx6gyzgjsclr9hbpo04v6","options":{"variableId":"vpjyy2e2ha6mu5x10q0nowuz3","expressionToEvaluate":"Davidson Oliveira Gomes"}},{"id":"ri9kv80djsej7r51m8xfjhuk","type":"Set variable","groupId":"h0svx6gyzgjsclr9hbpo04v6","options":{"variableId":"vicsm3nkvhssvfhgss2xce2ad","expressionToEvaluate":"Telefone"}},{"id":"ye4teva02mnxph0rvfszdnsn","type":"Set variable","groupId":"h0svx6gyzgjsclr9hbpo04v6","options":{"variableId":"vlmflx32cjlz457h0uzdi706g","expressionToEvaluate":"74999879409"}},{"id":"hfz4hqzfe6wgje96ezb5kann","type":"Set variable","groupId":"h0svx6gyzgjsclr9hbpo04v6","options":{"variableId":"veesfw943copg17w2qzdln9be","expressionToEvaluate":"Irece"}},{"id":"nd3yk369k7j73kws6exos0jw","type":"Set variable","groupId":"h0svx6gyzgjsclr9hbpo04v6","options":{"variableId":"vavwvk4wgst506zdioplg4u8p","expressionToEvaluate":"TypeBot"},"outgoingEdgeId":"mb90csrzzep8qz2opcxmw736"}],"graphCoordinates":{"x":312.08,"y":218.28}}],"variables":[{"id":"vo40px5r6wg9vhs9fixd45kzn","name":"name"},{"id":"vr75l1drc5uoxvisje0hio5ph","name":"email"},{"id":"vzhsu0uc4suqoz38kv3q891ma","name":"question3"},{"id":"vbfl3sqze2wzicn9l1n9ckjs4","name":"question1"},{"id":"vkgl2bfdbyms1dyc1s6efx678","name":"question2"},{"id":"vd6fm2i9shcdjz8bhhwbsdh6t","name":"question4"},{"id":"vz6lvahwo15dosvckdtkxduly","name":"question5"},{"id":"vndjnalmnb3ez9beeon5tzrgq","name":"question6"},{"id":"vept0w6tr0w7eyyi52hgq1r3c","name":"question7"},{"id":"vy5it60mewmth7mayzhlgmzf0","name":"question8"},{"id":"vhygxyvhu5l6r2uws1cbthmxm","name":"question9"},{"id":"vrdwfo2lpoei2fzlzazh4pp61","name":"pushName"},{"id":"vz1uq7t77aivpi5crwy6ifact","name":"remoteJid"},{"id":"vsu5or5sxes9lyuhsgcl3cuyd","name":"ID"},{"id":"vamn8ortov9nk1y04vczo375h","name":"qrcode"},{"id":"vx6p4ivk4mnssvbhl30c5zng9","name":"question10"},{"id":"vhoqah2c0blbx92bfmd4gjnyx","name":"question11"},{"id":"vpjyy2e2ha6mu5x10q0nowuz3","name":"me"},{"id":"vicsm3nkvhssvfhgss2xce2ad","name":"typePIX"},{"id":"vavwvk4wgst506zdioplg4u8p","name":"reference"},{"id":"vlmflx32cjlz457h0uzdi706g","name":"keyPIX"},{"id":"vkg1qlinovziltaloqhso2cw7","name":"apiURL"},{"id":"veesfw943copg17w2qzdln9be","name":"city"},{"id":"vp1ask55v2r58ukom5lek5hej","name":"evolutionURL"},{"id":"vtsldvs2u8ui93tktazy77djw","name":"evolutionToken"},{"id":"vpoyfwgfw4tbt4l4iy4homfoq","name":"instanceName"}],"edges":[{"id":"w6ao5pi6wt0966tobkned56m","to":{"groupId":"qzhp25b9f2lvt4yeniqvjkav"},"from":{"itemId":"dwhc3ptqvktlgfvl17xg79s5","blockId":"b538q1mt18l6oddo397nh1m4","groupId":"lbieknd0qp42pogsby5l82ww"}},{"id":"wlfmh2g3j5avj75sa9q6rsab","to":{"groupId":"tn8bcyughy9dsxhmjngrosvj"},"from":{"itemId":"cod3tkt16ry8ixm5u7rwxzm9","blockId":"b538q1mt18l6oddo397nh1m4","groupId":"lbieknd0qp42pogsby5l82ww"}},{"id":"yu9762ttf5jn3bmhd6uzrsv8","to":{"groupId":"jdz9w8vrz09vefk4wqrf0vwl"},"from":{"itemId":"ifhm8cj8lsulhrarnfda2oal","blockId":"n3j2dxaalkljl020o0o61ef9","groupId":"tn8bcyughy9dsxhmjngrosvj"}},{"id":"ji1y2o1hldhemto0ymwou09c","to":{"groupId":"nzkhdw3hdv550aepsxvk2a0u"},"from":{"itemId":"gxp6j3ouga4r0t8364tn8axs","blockId":"n3j2dxaalkljl020o0o61ef9","groupId":"tn8bcyughy9dsxhmjngrosvj"}},{"id":"x2fzu1uuukp9cgmdzecp7mgk","to":{"groupId":"c4k1ftb4rbynkb01ulwuh4qh"},"from":{"itemId":"lur26nqa8dv7m4jmmljpyyf1","blockId":"zderh9hqjkpuz58p79szfa1i","groupId":"jdz9w8vrz09vefk4wqrf0vwl"}},{"id":"d3u83fikqplfy9ntva3sm7eg","to":{"groupId":"cf8r0wx0sgw6c9v79ebja1tj"},"from":{"blockId":"n3j2dxaalkljl020o0o61ef9","groupId":"tn8bcyughy9dsxhmjngrosvj"}},{"id":"ehcwqdrkc4025pui2y1s9390","to":{"groupId":"ffm0s2y4head3auw808hwfnx"},"from":{"blockId":"b538q1mt18l6oddo397nh1m4","groupId":"lbieknd0qp42pogsby5l82ww"}},{"id":"mb1fg83gijikrafud2ml6zbn","to":{"groupId":"cs5kjnrcsh4bjiuvwf99agho"},"from":{"itemId":"aoj7e49zimwxng4o7bd6u00s","blockId":"zderh9hqjkpuz58p79szfa1i","groupId":"jdz9w8vrz09vefk4wqrf0vwl"}},{"id":"amyrx4i2rm3cjksym5zvwd50","to":{"groupId":"b7zfnwcxvu28s98ii03isdae"},"from":{"blockId":"zderh9hqjkpuz58p79szfa1i","groupId":"jdz9w8vrz09vefk4wqrf0vwl"}},{"id":"o746eh96sq2j7juionfql73t","to":{"groupId":"z0idhsnqisrd695z0j1tnqvw"},"from":{"blockId":"xza6e0p4hgkfz1wvwcjss48s","groupId":"cs5kjnrcsh4bjiuvwf99agho"}},{"id":"fe1wk4fc1xzt7mefasb2qzqz","to":{"groupId":"tq60r6azxrmn17b4y7mjovf5"},"from":{"itemId":"m5mvt5ecw81eevl428n56aji","blockId":"xza6e0p4hgkfz1wvwcjss48s","groupId":"cs5kjnrcsh4bjiuvwf99agho"}},{"id":"xg1zkpvob8ilx2r8p0kv604d","to":{"groupId":"vvyooiddvdbon0t21bvzdr7q"},"from":{"itemId":"bpcidulg0g7v8pwh3w9my880","blockId":"xza6e0p4hgkfz1wvwcjss48s","groupId":"cs5kjnrcsh4bjiuvwf99agho"}},{"id":"cwlt91vwhr7gvgx0qx2mnxtr","to":{"groupId":"vvyooiddvdbon0t21bvzdr7q"},"from":{"blockId":"chiz9utw18jvui4c2r0vsiqp","groupId":"qsrkmfsr04kayulair47gmn0"}},{"id":"aovnigvk665gzhyzg7bxhvn0","to":{"groupId":"h0svx6gyzgjsclr9hbpo04v6"},"from":{"blockId":"qn40kjwtw1he3l1bujt3bnje","groupId":"c76ucoughhenpernmadu7ibg"}},{"id":"mb90csrzzep8qz2opcxmw736","to":{"groupId":"nog2woqmvhssnnjlcpwd41k5"},"from":{"blockId":"nd3yk369k7j73kws6exos0jw","groupId":"h0svx6gyzgjsclr9hbpo04v6"}},{"id":"vwx6ofz1ur8maxcbw8fk66x9","to":{"groupId":"j5co2kcotxafuxhzlj7u0qnn"},"from":{"blockId":"o8ijci5gdfsp6fpv07kwh8br","groupId":"nog2woqmvhssnnjlcpwd41k5"}},{"id":"v53mvhejcapb4a1zq98swq5b","to":{"groupId":"wtd0o382phaji7i7u2n8pody"},"from":{"blockId":"qb8nwfs52g168tmnvp257b44","groupId":"j5co2kcotxafuxhzlj7u0qnn"}},{"id":"ed1x8zan90zvrpo9xk9moroe","to":{"groupId":"ylerbfc1l2o62j68g8ghegxt"},"from":{"blockId":"ku0zpu43cbbnd7y0ai71ptde","groupId":"wtd0o382phaji7i7u2n8pody"}},{"id":"iy61ajcfl6ubbj7zghxeu6f7","to":{"groupId":"lbieknd0qp42pogsby5l82ww"},"from":{"blockId":"kfxuc6p58cdzy1xcyp4i4ra7","groupId":"ylerbfc1l2o62j68g8ghegxt"}},{"id":"i11xudmpsb1tbsss7qoge6cm","to":{"groupId":"c8kh8eee1m3wyy372v4n6m1i"},"from":{"blockId":"ce2eodve0e4f2rubk4wv5jf1","groupId":"qzhp25b9f2lvt4yeniqvjkav"}},{"id":"c9nrzzcxt8w4dgk2sfez53n5","to":{"groupId":"tn8bcyughy9dsxhmjngrosvj"},"from":{"blockId":"mg2tmcmwnx3tap0hs4b7e0la","groupId":"c8kh8eee1m3wyy372v4n6m1i"}},{"id":"k7vrrf5cfxopvmhsbf35bt3m","to":{"groupId":"jdz9w8vrz09vefk4wqrf0vwl"},"from":{"blockId":"dj7dbgyjqk0a5u3jn6kzykb2","groupId":"nzkhdw3hdv550aepsxvk2a0u"}},{"id":"u8c55of7l95fnz25gf7swt1m","to":{"groupId":"cs5kjnrcsh4bjiuvwf99agho"},"from":{"blockId":"wfucksh3yaeq21l7mnlnsx75","groupId":"c4k1ftb4rbynkb01ulwuh4qh"}},{"id":"ns2kch8n15uklzwf8kn4m0lb","to":{"groupId":"qsrkmfsr04kayulair47gmn0"},"from":{"blockId":"khncvmg5fcjsmu8tlmf8in6m","groupId":"tq60r6azxrmn17b4y7mjovf5"}}],"theme":{"chat":{"inputs":{"color":"#ffffff","backgroundColor":"#1e293b","placeholderColor":"#9095A0"},"buttons":{"color":"#ffffff","backgroundColor":"#1a5fff"},"roundness":"large","hostAvatar":{"isEnabled":true},"guestAvatar":{"isEnabled":false},"hostBubbles":{"color":"#ffffff","backgroundColor":"#1e293b"},"guestBubbles":{"color":"#FFFFFF","backgroundColor":"#FF8E21"}},"general":{"font":"Open Sans","background":{"type":"Color","content":"#171923"}}},"selectedThemeTemplateId":"typebot-dark","settings":{"general":{"isBrandingEnabled":false},"metadata":{"imageUrl":"https://i.imgur.com/48TjKBb.jpg","description":"Sua opinião é fundamental para nos ajudar a melhorar!"},"typingEmulation":{"speed":300,"enabled":true,"maxDelay":1.5}},"publicId":"dgcode-pesquisa-satisfacao-whatsapp-7m64d9o","customDomain":null,"workspaceId":"clktt8c1y0001qa66zyg5tt23","resultsTablePreferences":null,"isArchived":false,"isClosed":false} \ No newline at end of file diff --git a/LICENSE b/LICENSE index 0da2f519..da01e779 100644 --- a/LICENSE +++ b/LICENSE @@ -1,674 +1,21 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 +# Evolution API License - 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. +Evolution API is licensed under the Apache License 2.0, with the following additional conditions: - Preamble +1. Evolution API may be utilized commercially, including as a backend service for other applications or as an application development platform for enterprises. Should the conditions below be met, a commercial license must be obtained from the producer: - The GNU General Public License is a free, copyleft license for -software and other kinds of works. +a. LOGO and copyright information: In the process of using Evolution API's frontend components, you may not remove or modify the LOGO or copyright information in the Evolution API console or applications. This restriction is inapplicable to uses of Evolution API that do not involve its frontend components. - 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. +b. Usage Notification Requirement: If Evolution API is used as part of any project, including closed-source systems (e.g., proprietary software), the user is required to display a clear notification within the system that Evolution API is being utilized. This notification should be visible to system administrators and accessible from the system's documentation or settings page. Failure to comply with this requirement may result in the necessity for a commercial license, as determined by the producer. - 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. +Please contact contato@atendai.com to inquire about licensing matters. - 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. +2. As a contributor, you should agree that: - 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. +a. The producer can adjust the open-source agreement to be more strict or relaxed as deemed necessary. +b. Your contributed code may be used for commercial purposes, including but not limited to its cloud business operations. - 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. +Apart from the specific conditions mentioned above, all other rights and restrictions follow the Apache License 2.0. Detailed information about the Apache License 2.0 can be found at http://www.apache.org/licenses/LICENSE-2.0. - 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. +© 2024 Evolution API - 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/README.md b/README.md index 13e68151..93197499 100644 --- a/README.md +++ b/README.md @@ -6,46 +6,113 @@ [![Discord Community](https://img.shields.io/badge/Discord-Community-blue)](https://evolution-api.com/discord) [![Postman Collection](https://img.shields.io/badge/Postman-Collection-orange)](https://evolution-api.com/postman) [![Documentation](https://img.shields.io/badge/Documentation-Official-green)](https://doc.evolution-api.com) -[![License](https://img.shields.io/badge/license-GPL--3.0-orange)](./LICENSE) +[![License](https://img.shields.io/badge/license-Apache--2.0-blue)](./LICENSE) [![Support](https://img.shields.io/badge/Donation-picpay-green)](https://app.picpay.com/user/davidsongomes1998) -[![Support](https://img.shields.io/badge/Buy%20me-coffe-orange)](https://bmc.link/evolutionapi) +[![Sponsors](https://img.shields.io/badge/Github-sponsor-orange)](https://github.com/sponsors/EvolutionAPI)
-## WhatsApp-Api-NodeJs +## Evolution API -This project is based on the [CodeChat](https://github.com/code-chat-br/whatsapp-api). The original project is an implementation of [Baileys](https://github.com/WhiskeySockets/Baileys), serving as a Restful API service that controls WhatsApp functions.
-The code allows the creation of multiservice chats, service bots, or any other system that utilizes WhatsApp. The documentation provides instructions on how to set up and use the project, as well as additional information about its features and configuration options. +Evolution API began as a WhatsApp controller API based on [CodeChat](https://github.com/code-chat-br/whatsapp-api), which in turn implemented the [Baileys](https://github.com/WhiskeySockets/Baileys) library. While originally focused on WhatsApp, Evolution API has grown into a comprehensive platform supporting multiple messaging services and integrations. We continue to acknowledge CodeChat for laying the groundwork. -## SSL +Today, Evolution API is not limited to WhatsApp. It integrates with various platforms such as Typebot, Chatwoot, Dify, and OpenAI, offering a broad array of functionalities beyond messaging. Evolution API supports both the Baileys-based WhatsApp API and the official WhatsApp Business API, with upcoming support for Instagram and Messenger. -To install the SSL certificate, follow the **[instructions](https://certbot.eff.org/instructions?ws=other&os=ubuntufocal)** below. +## Looking for a Lightweight Version? +For those who need a more streamlined and performance-optimized version, check out [Evolution API Lite](https://github.com/EvolutionAPI/evolution-api-lite). It's designed specifically for microservices, focusing solely on connectivity without integrations or audio conversion features. Ideal for environments that prioritize simplicity and efficiency. -# Note +## Types of Connections -This code is in no way affiliated with WhatsApp. Use at your own discretion. Don't spam this. +Evolution API supports multiple types of connections to WhatsApp, enabling flexible and powerful integration options: -This code was produced based on the baileys library and it is still under development. +- *WhatsApp API - Baileys*: + - A free API based on WhatsApp Web, leveraging the [Baileys library](https://github.com/WhiskeySockets/Baileys). + - This connection type allows control over WhatsApp Web functionalities through a RESTful API, suitable for multi-service chats, service bots, and other WhatsApp-integrated systems. + - Note: This method relies on the web version of WhatsApp and may have limitations compared to official APIs. + +- *WhatsApp Cloud API*: + - The official API provided by Meta (formerly Facebook). + - This connection type offers a robust and reliable solution designed for businesses needing higher volumes of messaging and better integration support. + - The Cloud API supports features such as end-to-end encryption, advanced analytics, and more comprehensive customer service tools. + - To use this API, you must comply with Meta's policies and potentially pay for usage based on message volume and other factors. + +## Integrations + +Evolution API supports various integrations to enhance its functionality. Below is a list of available integrations and their uses: + +- [Typebot](https://typebot.io/): + - Build conversational bots using Typebot, integrated directly into Evolution with trigger management. + +- [Chatwoot](https://www.chatwoot.com/): + - Direct integration with Chatwoot for handling customer service for your business. + +- [RabbitMQ](https://www.rabbitmq.com/): + - Receive events from the Evolution API via RabbitMQ. + +- [Amazon SQS](https://aws.amazon.com/pt/sqs/): + - Receive events from the Evolution API via Amazon SQS. + +- [Socket.io](https://socket.io/): + - Receive events from the Evolution API via WebSocket. + +- [Dify](https://dify.ai/): + - Integrate your Evolution API directly with Dify AI for seamless trigger management and multiple agents. + +- [OpenAI](https://openai.com/): + - Integrate your Evolution API with OpenAI for AI capabilities, including audio-to-text conversion, available across all Evolution integrations. + +- Amazon S3 / Minio: + - Store media files received in [Amazon S3](https://aws.amazon.com/pt/s3/) or [Minio](https://min.io/). + +## Telemetry Notice + +To continuously improve our services, we have implemented telemetry that collects data on the routes used, the most accessed routes, and the version of the API in use. We would like to assure you that no sensitive or personal data is collected during this process. The telemetry helps us identify improvements and provide a better experience for users. + +## Evolution Support Premium + +Join our Evolution Pro community for expert support and a weekly call to answer questions. Visit the link below to learn more and subscribe: + +[Click here to learn more](https://evolution-api.com/suporte-pro) # Donate to the project. -#### PicPay +#### Github Sponsors - +https://github.com/sponsors/EvolutionAPI -#### Buy me coffe - PIX +# Content Creator Partners -
- - - -

CHAVE PIX (Telefone): (74)99987-9409

-
+We are proud to collaborate with the following content creators who have contributed valuable insights and tutorials about Evolution API: -
\ No newline at end of file +- [Promovaweb](https://www.youtube.com/@promovaweb) +- [Comunidade ZDG](https://www.youtube.com/@ComunidadeZDG) +- [Francis MNO](https://www.youtube.com/@FrancisMNO) +- [Pablo Cabral](https://youtube.com/@pablocabral) +- [XPop Digital](https://www.youtube.com/@xpopdigital) +- [Costar Wagner Dev](https://www.youtube.com/@costarwagnerdev) +- [Dante Testa](https://youtube.com/@dantetesta_) +- [Rubén Salazar](https://youtube.com/channel/UCnYGZIE2riiLqaN9sI6riig) +- [OrionDesign](youtube.com/OrionDesign_Oficial) +- [IMPA 365](youtube.com/@impa365_ofc) +- [Comunidade Hub Connect](https://youtube.com/@comunidadehubconnect) +- [dSantana Automações](https://www.youtube.com/channel/UCG7DjUmAxtYyURlOGAIryNQ?view_as=subscriber) +- [Edison Martins](https://www.youtube.com/@edisonmartinsmkt) +- [Astra Online](https://www.youtube.com/@astraonlineweb) +- [MKT Seven Automações](https://www.youtube.com/@sevenautomacoes) +- [Vamos automatizar](https://www.youtube.com/vamosautomatizar) + +## License + +Evolution API is licensed under the Apache License 2.0, with the following additional conditions: + +1. **LOGO and copyright information**: In the process of using Evolution API's frontend components, you may not remove or modify the LOGO or copyright information in the Evolution API console or applications. This restriction is inapplicable to uses of Evolution API that do not involve its frontend components. + +2. **Usage Notification Requirement**: If Evolution API is used as part of any project, including closed-source systems (e.g., proprietary software), the user is required to display a clear notification within the system that Evolution API is being utilized. This notification should be visible to system administrators and accessible from the system's documentation or settings page. Failure to comply with this requirement may result in the necessity for a commercial license, as determined by the producer. + +Please contact contato@atendai.com to inquire about licensing matters. + +Apart from the specific conditions mentioned above, all other rights and restrictions follow the Apache License 2.0. Detailed information about the Apache License 2.0 can be found at [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0). + +© 2024 Evolution API \ No newline at end of file diff --git a/docker-compose.yaml.example b/docker-compose.dev.yaml similarity index 73% rename from docker-compose.yaml.example rename to docker-compose.dev.yaml index d0a75a5d..2ca3424e 100644 --- a/docker-compose.yaml.example +++ b/docker-compose.dev.yaml @@ -1,5 +1,3 @@ -version: '3.3' - services: api: container_name: evolution_api @@ -10,18 +8,16 @@ services: - 8080:8080 volumes: - evolution_instances:/evolution/instances - - evolution_store:/evolution/store networks: - evolution-net env_file: - - ./Docker/.env - command: ['node', './dist/src/main.js'] + - .env expose: - 8080 volumes: evolution_instances: - evolution_store: + networks: evolution-net: diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 00000000..9a60a9a9 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,60 @@ +services: + api: + container_name: evolution_api + image: atendai/evolution-api:homolog + restart: always + depends_on: + - redis + - postgres + ports: + - 8080:8080 + volumes: + - evolution_instances:/evolution/instances + networks: + - evolution-net + env_file: + - .env + expose: + - 8080 + + redis: + image: redis:latest + networks: + - evolution-net + container_name: redis + command: > + redis-server --port 6379 --appendonly yes + volumes: + - evolution_redis:/data + ports: + - 6379:6379 + + postgres: + container_name: postgres + image: postgres:15 + networks: + - evolution-net + command: ["postgres", "-c", "max_connections=1000", "-c", "listen_addresses=*"] + restart: always + ports: + - 5432:5432 + environment: + - POSTGRES_USER=user + - POSTGRES_PASSWORD=pass + - POSTGRES_DB=evolution + - POSTGRES_HOST_AUTH_METHOD=trust + volumes: + - postgres_data:/var/lib/postgresql/data + expose: + - 5432 + +volumes: + evolution_instances: + evolution_redis: + postgres_data: + + +networks: + evolution-net: + name: evolution-net + driver: bridge diff --git a/docker-compose.yaml.example.complete b/docker-compose.yaml.example.complete deleted file mode 100644 index de13de57..00000000 --- a/docker-compose.yaml.example.complete +++ /dev/null @@ -1,80 +0,0 @@ -version: '3.3' - -services: - api: - container_name: evolution_api - image: evolution/api:local - build: . - restart: always - ports: - - 8080:8080 - volumes: - - evolution_instances:/evolution/instances - - evolution_store:/evolution/store - networks: - - evolution-net - env_file: - - ./Docker/.env - command: ['node', './dist/src/main.js'] - expose: - - 8080 - - mongodb: - container_name: mongodb - image: mongo - restart: always - ports: - - 27017:27017 - environment: - - MONGO_INITDB_ROOT_USERNAME=root - - MONGO_INITDB_ROOT_PASSWORD=root - - PUID=1000 - - PGID=1000 - volumes: - - evolution_mongodb_data:/data/db - - evolution_mongodb_configdb:/data/configdb - networks: - - evolution-net - expose: - - 27017 - - mongo-express: - image: mongo-express - networks: - - evolution-net - environment: - ME_CONFIG_BASICAUTH_USERNAME: root - ME_CONFIG_BASICAUTH_PASSWORD: root - ME_CONFIG_MONGODB_SERVER: mongodb - ME_CONFIG_MONGODB_ADMINUSERNAME: root - ME_CONFIG_MONGODB_ADMINPASSWORD: root - ports: - - 8081:8081 - links: - - mongodb - - redis: - image: redis:latest - container_name: redis - command: > - redis-server - --port 6379 - --appendonly yes - volumes: - - evolution_redis:/data - networks: - - evolution-net - ports: - - 6379:6379 - -volumes: - evolution_instances: - evolution_store: - evolution_mongodb_data: - evolution_mongodb_configdb: - evolution_redis: - -networks: - evolution-net: - name: evolution-net - driver: bridge diff --git a/docker-compose.yaml.example.dockerhub b/docker-compose.yaml.example.dockerhub deleted file mode 100644 index b33e8f4a..00000000 --- a/docker-compose.yaml.example.dockerhub +++ /dev/null @@ -1,28 +0,0 @@ -version: '3.3' - -services: - api: - container_name: evolution_api - image: atendai/evolution-api:latest - restart: always - ports: - - 8080:8080 - volumes: - - evolution_instances:/evolution/instances - - evolution_store:/evolution/store - networks: - - evolution-net - env_file: - - ./Docker/.env - command: ['node', './dist/src/main.js'] - expose: - - 8080 - -volumes: - evolution_instances: - evolution_store: - -networks: - evolution-net: - name: evolution-net - driver: bridge diff --git a/instances/.gitkeep b/instances/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/local_install.sh b/local_install.sh new file mode 100755 index 00000000..529a2c4b --- /dev/null +++ b/local_install.sh @@ -0,0 +1,150 @@ +#!/bin/bash + +# Definir cores para melhor legibilidade +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Função para log +log() { + echo -e "${GREEN}[INFO]${NC} $1" +} +log_error() { + echo -e "${RED}[ERROR]${NC} $1" +} +log_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +# Verificar se está rodando como root +if [ "$(id -u)" = "0" ]; then + log_error "Este script não deve ser executado como root" + exit 1 +fi + +# Verificar sistema operacional +OS="$(uname -s)" +case "${OS}" in + Linux*) + if [ ! -x "$(command -v curl)" ]; then + log_warning "Curl não está instalado. Tentando instalar..." + if [ -x "$(command -v apt-get)" ]; then + sudo apt-get update && sudo apt-get install -y curl + elif [ -x "$(command -v yum)" ]; then + sudo yum install -y curl + else + log_error "Não foi possível instalar curl automaticamente. Por favor, instale manualmente." + exit 1 + fi + fi + ;; + Darwin*) + if [ ! -x "$(command -v curl)" ]; then + log_error "Curl não está instalado. Por favor, instale o Xcode Command Line Tools." + exit 1 + fi + ;; + *) + log_error "Sistema operacional não suportado: ${OS}" + exit 1 + ;; +esac + +# Verificar conexão com a internet antes de prosseguir +if ! ping -c 1 8.8.8.8 &> /dev/null; then + log_error "Sem conexão com a internet. Por favor, verifique sua conexão." + exit 1 +fi + +# Adicionar verificação de espaço em disco +REQUIRED_SPACE=1000000 # 1GB em KB +AVAILABLE_SPACE=$(df -k . | awk 'NR==2 {print $4}') +if [ $AVAILABLE_SPACE -lt $REQUIRED_SPACE ]; then + log_error "Espaço em disco insuficiente. Necessário pelo menos 1GB livre." + exit 1 +fi + +# Adicionar tratamento de erro para comandos npm +npm_install_with_retry() { + local max_attempts=3 + local attempt=1 + + while [ $attempt -le $max_attempts ]; do + log "Tentativa $attempt de $max_attempts para npm install" + if npm install; then + return 0 + fi + attempt=$((attempt + 1)) + [ $attempt -le $max_attempts ] && log_warning "Falha na instalação. Tentando novamente em 5 segundos..." && sleep 5 + done + + log_error "Falha ao executar npm install após $max_attempts tentativas" + return 1 +} + +# Adicionar timeout para comandos +execute_with_timeout() { + timeout 300 $@ || log_error "Comando excedeu o tempo limite de 5 minutos: $@" +} + +# Verificar se o NVM já está instalado +if [ -d "$HOME/.nvm" ]; then + log "NVM já está instalado." +else + log "Instalando NVM..." + curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash +fi + +# Carregar o NVM no ambiente atual +export NVM_DIR="$HOME/.nvm" +[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" +[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" + +# Verificar se a versão do Node.js já está instalada +if command -v node >/dev/null 2>&1 && [ "$(node -v)" = "v20.10.0" ]; then + log "Node.js v20.10.0 já está instalado." +else + log "Instalando Node.js v20.10.0..." + nvm install v20.10.0 +fi + +nvm use v20.10.0 + +# Verificar as versões instaladas +log "Verificando as versões instaladas:" +log "Node.js: $(node -v)" +log "npm: $(npm -v)" + +# Instala dependências do projeto +log "Instalando dependências do projeto..." +rm -rf node_modules +npm install + +# Deploy do banco de dados +log "Deploy do banco de dados..." +npm run db:generate +npm run db:deploy + +# Iniciar o projeto +log "Iniciando o projeto..." +if [ "$1" = "-dev" ]; then + npm run dev:server +else + npm run build + npm run start:prod +fi + +log "Instalação concluída com sucesso!" + +# Criar arquivo de log +LOGFILE="./installation_log_$(date +%Y%m%d_%H%M%S).log" +exec 1> >(tee -a "$LOGFILE") +exec 2>&1 + +# Adicionar trap para limpeza em caso de interrupção +cleanup() { + log "Limpando recursos temporários..." + # Adicione comandos de limpeza aqui +} +trap cleanup EXIT diff --git a/manager/dist/assets/images/evolution-logo.png b/manager/dist/assets/images/evolution-logo.png new file mode 100644 index 00000000..bd9b3850 Binary files /dev/null and b/manager/dist/assets/images/evolution-logo.png differ diff --git a/manager/dist/assets/index-CFAZX6IV.js b/manager/dist/assets/index-CFAZX6IV.js new file mode 100644 index 00000000..ffa565ff --- /dev/null +++ b/manager/dist/assets/index-CFAZX6IV.js @@ -0,0 +1,381 @@ +var Ww=e=>{throw TypeError(e)};var qI=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var sm=(e,t,n)=>t.has(e)||Ww("Cannot "+n);var R=(e,t,n)=>(sm(e,t,"read from private field"),n?n.call(e):t.get(e)),Ie=(e,t,n)=>t.has(e)?Ww("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(e):t.set(e,n),xe=(e,t,n,r)=>(sm(e,t,"write to private field"),r?r.call(e,n):t.set(e,n),n),Je=(e,t,n)=>(sm(e,t,"access private method"),n);var uf=(e,t,n,r)=>({set _(s){xe(e,t,s,n)},get _(){return R(e,t,r)}});var kse=qI((ao,io)=>{function jE(e,t){for(var n=0;nr[s]})}}}return Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const s of document.querySelectorAll('link[rel="modulepreload"]'))r(s);new MutationObserver(s=>{for(const o of s)if(o.type==="childList")for(const a of o.addedNodes)a.tagName==="LINK"&&a.rel==="modulepreload"&&r(a)}).observe(document,{childList:!0,subtree:!0});function n(s){const o={};return s.integrity&&(o.integrity=s.integrity),s.referrerPolicy&&(o.referrerPolicy=s.referrerPolicy),s.crossOrigin==="use-credentials"?o.credentials="include":s.crossOrigin==="anonymous"?o.credentials="omit":o.credentials="same-origin",o}function r(s){if(s.ep)return;s.ep=!0;const o=n(s);fetch(s.href,o)}})();function jb(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var RE={exports:{}},Oh={},PE={exports:{}},ot={};/** + * @license React + * react.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var Dd=Symbol.for("react.element"),WI=Symbol.for("react.portal"),GI=Symbol.for("react.fragment"),JI=Symbol.for("react.strict_mode"),QI=Symbol.for("react.profiler"),ZI=Symbol.for("react.provider"),YI=Symbol.for("react.context"),XI=Symbol.for("react.forward_ref"),eD=Symbol.for("react.suspense"),tD=Symbol.for("react.memo"),nD=Symbol.for("react.lazy"),Gw=Symbol.iterator;function rD(e){return e===null||typeof e!="object"?null:(e=Gw&&e[Gw]||e["@@iterator"],typeof e=="function"?e:null)}var ME={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},OE=Object.assign,NE={};function iu(e,t,n){this.props=e,this.context=t,this.refs=NE,this.updater=n||ME}iu.prototype.isReactComponent={};iu.prototype.setState=function(e,t){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")};iu.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function IE(){}IE.prototype=iu.prototype;function Rb(e,t,n){this.props=e,this.context=t,this.refs=NE,this.updater=n||ME}var Pb=Rb.prototype=new IE;Pb.constructor=Rb;OE(Pb,iu.prototype);Pb.isPureReactComponent=!0;var Jw=Array.isArray,DE=Object.prototype.hasOwnProperty,Mb={current:null},AE={key:!0,ref:!0,__self:!0,__source:!0};function FE(e,t,n){var r,s={},o=null,a=null;if(t!=null)for(r in t.ref!==void 0&&(a=t.ref),t.key!==void 0&&(o=""+t.key),t)DE.call(t,r)&&!AE.hasOwnProperty(r)&&(s[r]=t[r]);var l=arguments.length-2;if(l===1)s.children=n;else if(1{this.listeners.delete(e),this.onUnsubscribe()}}hasListeners(){return this.listeners.size>0}onSubscribe(){}onUnsubscribe(){}},Kl=typeof window>"u"||"Deno"in globalThis;function Or(){}function hD(e,t){return typeof e=="function"?e(t):e}function Tv(e){return typeof e=="number"&&e>=0&&e!==1/0}function BE(e,t){return Math.max(e+(t||0)-Date.now(),0)}function bl(e,t){return typeof e=="function"?e(t):e}function Qr(e,t){return typeof e=="function"?e(t):e}function Zw(e,t){const{type:n="all",exact:r,fetchStatus:s,predicate:o,queryKey:a,stale:l}=e;if(a){if(r){if(t.queryHash!==Nb(a,t.options))return!1}else if(!Dc(t.queryKey,a))return!1}if(n!=="all"){const c=t.isActive();if(n==="active"&&!c||n==="inactive"&&c)return!1}return!(typeof l=="boolean"&&t.isStale()!==l||s&&s!==t.state.fetchStatus||o&&!o(t))}function Yw(e,t){const{exact:n,status:r,predicate:s,mutationKey:o}=e;if(o){if(!t.options.mutationKey)return!1;if(n){if(gi(t.options.mutationKey)!==gi(o))return!1}else if(!Dc(t.options.mutationKey,o))return!1}return!(r&&t.state.status!==r||s&&!s(t))}function Nb(e,t){return((t==null?void 0:t.queryKeyHashFn)||gi)(e)}function gi(e){return JSON.stringify(e,(t,n)=>kv(n)?Object.keys(n).sort().reduce((r,s)=>(r[s]=n[s],r),{}):n)}function Dc(e,t){return e===t?!0:typeof e!=typeof t?!1:e&&t&&typeof e=="object"&&typeof t=="object"?!Object.keys(t).some(n=>!Dc(e[n],t[n])):!1}function zE(e,t){if(e===t)return e;const n=Xw(e)&&Xw(t);if(n||kv(e)&&kv(t)){const r=n?e:Object.keys(e),s=r.length,o=n?t:Object.keys(t),a=o.length,l=n?[]:{};let c=0;for(let i=0;i{setTimeout(t,e)})}function _v(e,t,n){return typeof n.structuralSharing=="function"?n.structuralSharing(e,t):n.structuralSharing!==!1?zE(e,t):t}function mD(e,t,n=0){const r=[...e,t];return n&&r.length>n?r.slice(1):r}function vD(e,t,n=0){const r=[t,...e];return n&&r.length>n?r.slice(0,-1):r}var UE=Symbol();function VE(e,t){return!e.queryFn&&(t!=null&&t.initialPromise)?()=>t.initialPromise:!e.queryFn||e.queryFn===UE?()=>Promise.reject(new Error(`Missing queryFn: '${e.queryHash}'`)):e.queryFn}var ei,Ko,Ol,yE,yD=(yE=class extends lu{constructor(){super();Ie(this,ei);Ie(this,Ko);Ie(this,Ol);xe(this,Ol,t=>{if(!Kl&&window.addEventListener){const n=()=>t();return window.addEventListener("visibilitychange",n,!1),()=>{window.removeEventListener("visibilitychange",n)}}})}onSubscribe(){R(this,Ko)||this.setEventListener(R(this,Ol))}onUnsubscribe(){var t;this.hasListeners()||((t=R(this,Ko))==null||t.call(this),xe(this,Ko,void 0))}setEventListener(t){var n;xe(this,Ol,t),(n=R(this,Ko))==null||n.call(this),xe(this,Ko,t(r=>{typeof r=="boolean"?this.setFocused(r):this.onFocus()}))}setFocused(t){R(this,ei)!==t&&(xe(this,ei,t),this.onFocus())}onFocus(){const t=this.isFocused();this.listeners.forEach(n=>{n(t)})}isFocused(){var t;return typeof R(this,ei)=="boolean"?R(this,ei):((t=globalThis.document)==null?void 0:t.visibilityState)!=="hidden"}},ei=new WeakMap,Ko=new WeakMap,Ol=new WeakMap,yE),Ib=new yD,Nl,qo,Il,bE,bD=(bE=class extends lu{constructor(){super();Ie(this,Nl,!0);Ie(this,qo);Ie(this,Il);xe(this,Il,t=>{if(!Kl&&window.addEventListener){const n=()=>t(!0),r=()=>t(!1);return window.addEventListener("online",n,!1),window.addEventListener("offline",r,!1),()=>{window.removeEventListener("online",n),window.removeEventListener("offline",r)}}})}onSubscribe(){R(this,qo)||this.setEventListener(R(this,Il))}onUnsubscribe(){var t;this.hasListeners()||((t=R(this,qo))==null||t.call(this),xe(this,qo,void 0))}setEventListener(t){var n;xe(this,Il,t),(n=R(this,qo))==null||n.call(this),xe(this,qo,t(this.setOnline.bind(this)))}setOnline(t){R(this,Nl)!==t&&(xe(this,Nl,t),this.listeners.forEach(r=>{r(t)}))}isOnline(){return R(this,Nl)}},Nl=new WeakMap,qo=new WeakMap,Il=new WeakMap,bE),kp=new bD;function xD(e){return Math.min(1e3*2**e,3e4)}function HE(e){return(e??"online")==="online"?kp.isOnline():!0}var KE=class extends Error{constructor(e){super("CancelledError"),this.revert=e==null?void 0:e.revert,this.silent=e==null?void 0:e.silent}};function am(e){return e instanceof KE}function qE(e){let t=!1,n=0,r=!1,s,o,a;const l=new Promise((b,y)=>{o=b,a=y}),c=b=>{var y;r||(g(new KE(b)),(y=e.abort)==null||y.call(e))},i=()=>{t=!0},d=()=>{t=!1},p=()=>Ib.isFocused()&&(e.networkMode==="always"||kp.isOnline())&&e.canRun(),f=()=>HE(e.networkMode)&&e.canRun(),h=b=>{var y;r||(r=!0,(y=e.onSuccess)==null||y.call(e,b),s==null||s(),o(b))},g=b=>{var y;r||(r=!0,(y=e.onError)==null||y.call(e,b),s==null||s(),a(b))},m=()=>new Promise(b=>{var y;s=w=>{(r||p())&&b(w)},(y=e.onPause)==null||y.call(e)}).then(()=>{var b;s=void 0,r||(b=e.onContinue)==null||b.call(e)}),x=()=>{if(r)return;let b;const y=n===0?e.initialPromise:void 0;try{b=y??e.fn()}catch(w){b=Promise.reject(w)}Promise.resolve(b).then(h).catch(w=>{var T;if(r)return;const S=e.retry??(Kl?0:3),E=e.retryDelay??xD,C=typeof E=="function"?E(n,w):E,k=S===!0||typeof S=="number"&&np()?void 0:m()).then(()=>{t?g(w):x()})})};return{promise:l,cancel:c,continue:()=>(s==null||s(),l),cancelRetry:i,continueRetry:d,canStart:f,start:()=>(f()?x():m().then(x),l)}}function wD(){let e=[],t=0,n=f=>{f()},r=f=>{f()},s=f=>setTimeout(f,0);const o=f=>{s=f},a=f=>{let h;t++;try{h=f()}finally{t--,t||i()}return h},l=f=>{t?e.push(f):s(()=>{n(f)})},c=f=>(...h)=>{l(()=>{f(...h)})},i=()=>{const f=e;e=[],f.length&&s(()=>{r(()=>{f.forEach(h=>{n(h)})})})};return{batch:a,batchCalls:c,schedule:l,setNotifyFunction:f=>{n=f},setBatchNotifyFunction:f=>{r=f},setScheduler:o}}var cn=wD(),ti,xE,WE=(xE=class{constructor(){Ie(this,ti)}destroy(){this.clearGcTimeout()}scheduleGc(){this.clearGcTimeout(),Tv(this.gcTime)&&xe(this,ti,setTimeout(()=>{this.optionalRemove()},this.gcTime))}updateGcTime(e){this.gcTime=Math.max(this.gcTime||0,e??(Kl?1/0:5*60*1e3))}clearGcTimeout(){R(this,ti)&&(clearTimeout(R(this,ti)),xe(this,ti,void 0))}},ti=new WeakMap,xE),Dl,Al,Mr,On,Md,ni,Wr,Js,wE,SD=(wE=class extends WE{constructor(t){super();Ie(this,Wr);Ie(this,Dl);Ie(this,Al);Ie(this,Mr);Ie(this,On);Ie(this,Md);Ie(this,ni);xe(this,ni,!1),xe(this,Md,t.defaultOptions),this.setOptions(t.options),this.observers=[],xe(this,Mr,t.cache),this.queryKey=t.queryKey,this.queryHash=t.queryHash,xe(this,Dl,CD(this.options)),this.state=t.state??R(this,Dl),this.scheduleGc()}get meta(){return this.options.meta}get promise(){var t;return(t=R(this,On))==null?void 0:t.promise}setOptions(t){this.options={...R(this,Md),...t},this.updateGcTime(this.options.gcTime)}optionalRemove(){!this.observers.length&&this.state.fetchStatus==="idle"&&R(this,Mr).remove(this)}setData(t,n){const r=_v(this.state.data,t,this.options);return Je(this,Wr,Js).call(this,{data:r,type:"success",dataUpdatedAt:n==null?void 0:n.updatedAt,manual:n==null?void 0:n.manual}),r}setState(t,n){Je(this,Wr,Js).call(this,{type:"setState",state:t,setStateOptions:n})}cancel(t){var r,s;const n=(r=R(this,On))==null?void 0:r.promise;return(s=R(this,On))==null||s.cancel(t),n?n.then(Or).catch(Or):Promise.resolve()}destroy(){super.destroy(),this.cancel({silent:!0})}reset(){this.destroy(),this.setState(R(this,Dl))}isActive(){return this.observers.some(t=>Qr(t.options.enabled,this)!==!1)}isDisabled(){return this.getObserversCount()>0&&!this.isActive()}isStale(){return this.state.isInvalidated?!0:this.getObserversCount()>0?this.observers.some(t=>t.getCurrentResult().isStale):this.state.data===void 0}isStaleByTime(t=0){return this.state.isInvalidated||this.state.data===void 0||!BE(this.state.dataUpdatedAt,t)}onFocus(){var n;const t=this.observers.find(r=>r.shouldFetchOnWindowFocus());t==null||t.refetch({cancelRefetch:!1}),(n=R(this,On))==null||n.continue()}onOnline(){var n;const t=this.observers.find(r=>r.shouldFetchOnReconnect());t==null||t.refetch({cancelRefetch:!1}),(n=R(this,On))==null||n.continue()}addObserver(t){this.observers.includes(t)||(this.observers.push(t),this.clearGcTimeout(),R(this,Mr).notify({type:"observerAdded",query:this,observer:t}))}removeObserver(t){this.observers.includes(t)&&(this.observers=this.observers.filter(n=>n!==t),this.observers.length||(R(this,On)&&(R(this,ni)?R(this,On).cancel({revert:!0}):R(this,On).cancelRetry()),this.scheduleGc()),R(this,Mr).notify({type:"observerRemoved",query:this,observer:t}))}getObserversCount(){return this.observers.length}invalidate(){this.state.isInvalidated||Je(this,Wr,Js).call(this,{type:"invalidate"})}fetch(t,n){var c,i,d;if(this.state.fetchStatus!=="idle"){if(this.state.data!==void 0&&(n!=null&&n.cancelRefetch))this.cancel({silent:!0});else if(R(this,On))return R(this,On).continueRetry(),R(this,On).promise}if(t&&this.setOptions(t),!this.options.queryFn){const p=this.observers.find(f=>f.options.queryFn);p&&this.setOptions(p.options)}const r=new AbortController,s=p=>{Object.defineProperty(p,"signal",{enumerable:!0,get:()=>(xe(this,ni,!0),r.signal)})},o=()=>{const p=VE(this.options,n),f={queryKey:this.queryKey,meta:this.meta};return s(f),xe(this,ni,!1),this.options.persister?this.options.persister(p,f,this):p(f)},a={fetchOptions:n,options:this.options,queryKey:this.queryKey,state:this.state,fetchFn:o};s(a),(c=this.options.behavior)==null||c.onFetch(a,this),xe(this,Al,this.state),(this.state.fetchStatus==="idle"||this.state.fetchMeta!==((i=a.fetchOptions)==null?void 0:i.meta))&&Je(this,Wr,Js).call(this,{type:"fetch",meta:(d=a.fetchOptions)==null?void 0:d.meta});const l=p=>{var f,h,g,m;am(p)&&p.silent||Je(this,Wr,Js).call(this,{type:"error",error:p}),am(p)||((h=(f=R(this,Mr).config).onError)==null||h.call(f,p,this),(m=(g=R(this,Mr).config).onSettled)==null||m.call(g,this.state.data,p,this)),this.isFetchingOptimistic||this.scheduleGc(),this.isFetchingOptimistic=!1};return xe(this,On,qE({initialPromise:n==null?void 0:n.initialPromise,fn:a.fetchFn,abort:r.abort.bind(r),onSuccess:p=>{var f,h,g,m;if(p===void 0){l(new Error(`${this.queryHash} data is undefined`));return}try{this.setData(p)}catch(x){l(x);return}(h=(f=R(this,Mr).config).onSuccess)==null||h.call(f,p,this),(m=(g=R(this,Mr).config).onSettled)==null||m.call(g,p,this.state.error,this),this.isFetchingOptimistic||this.scheduleGc(),this.isFetchingOptimistic=!1},onError:l,onFail:(p,f)=>{Je(this,Wr,Js).call(this,{type:"failed",failureCount:p,error:f})},onPause:()=>{Je(this,Wr,Js).call(this,{type:"pause"})},onContinue:()=>{Je(this,Wr,Js).call(this,{type:"continue"})},retry:a.options.retry,retryDelay:a.options.retryDelay,networkMode:a.options.networkMode,canRun:()=>!0})),R(this,On).start()}},Dl=new WeakMap,Al=new WeakMap,Mr=new WeakMap,On=new WeakMap,Md=new WeakMap,ni=new WeakMap,Wr=new WeakSet,Js=function(t){const n=r=>{switch(t.type){case"failed":return{...r,fetchFailureCount:t.failureCount,fetchFailureReason:t.error};case"pause":return{...r,fetchStatus:"paused"};case"continue":return{...r,fetchStatus:"fetching"};case"fetch":return{...r,...GE(r.data,this.options),fetchMeta:t.meta??null};case"success":return{...r,data:t.data,dataUpdateCount:r.dataUpdateCount+1,dataUpdatedAt:t.dataUpdatedAt??Date.now(),error:null,isInvalidated:!1,status:"success",...!t.manual&&{fetchStatus:"idle",fetchFailureCount:0,fetchFailureReason:null}};case"error":const s=t.error;return am(s)&&s.revert&&R(this,Al)?{...R(this,Al),fetchStatus:"idle"}:{...r,error:s,errorUpdateCount:r.errorUpdateCount+1,errorUpdatedAt:Date.now(),fetchFailureCount:r.fetchFailureCount+1,fetchFailureReason:s,fetchStatus:"idle",status:"error"};case"invalidate":return{...r,isInvalidated:!0};case"setState":return{...r,...t.state}}};this.state=n(this.state),cn.batch(()=>{this.observers.forEach(r=>{r.onQueryUpdate()}),R(this,Mr).notify({query:this,type:"updated",action:t})})},wE);function GE(e,t){return{fetchFailureCount:0,fetchFailureReason:null,fetchStatus:HE(t.networkMode)?"fetching":"paused",...e===void 0&&{error:null,status:"pending"}}}function CD(e){const t=typeof e.initialData=="function"?e.initialData():e.initialData,n=t!==void 0,r=n?typeof e.initialDataUpdatedAt=="function"?e.initialDataUpdatedAt():e.initialDataUpdatedAt:0;return{data:t,dataUpdateCount:0,dataUpdatedAt:n?r??Date.now():0,error:null,errorUpdateCount:0,errorUpdatedAt:0,fetchFailureCount:0,fetchFailureReason:null,fetchMeta:null,isInvalidated:!1,status:n?"success":"pending",fetchStatus:"idle"}}var Ss,SE,ED=(SE=class extends lu{constructor(t={}){super();Ie(this,Ss);this.config=t,xe(this,Ss,new Map)}build(t,n,r){const s=n.queryKey,o=n.queryHash??Nb(s,n);let a=this.get(o);return a||(a=new SD({cache:this,queryKey:s,queryHash:o,options:t.defaultQueryOptions(n),state:r,defaultOptions:t.getQueryDefaults(s)}),this.add(a)),a}add(t){R(this,Ss).has(t.queryHash)||(R(this,Ss).set(t.queryHash,t),this.notify({type:"added",query:t}))}remove(t){const n=R(this,Ss).get(t.queryHash);n&&(t.destroy(),n===t&&R(this,Ss).delete(t.queryHash),this.notify({type:"removed",query:t}))}clear(){cn.batch(()=>{this.getAll().forEach(t=>{this.remove(t)})})}get(t){return R(this,Ss).get(t)}getAll(){return[...R(this,Ss).values()]}find(t){const n={exact:!0,...t};return this.getAll().find(r=>Zw(n,r))}findAll(t={}){const n=this.getAll();return Object.keys(t).length>0?n.filter(r=>Zw(t,r)):n}notify(t){cn.batch(()=>{this.listeners.forEach(n=>{n(t)})})}onFocus(){cn.batch(()=>{this.getAll().forEach(t=>{t.onFocus()})})}onOnline(){cn.batch(()=>{this.getAll().forEach(t=>{t.onOnline()})})}},Ss=new WeakMap,SE),Cs,Ln,ri,Es,Ao,CE,TD=(CE=class extends WE{constructor(t){super();Ie(this,Es);Ie(this,Cs);Ie(this,Ln);Ie(this,ri);this.mutationId=t.mutationId,xe(this,Ln,t.mutationCache),xe(this,Cs,[]),this.state=t.state||JE(),this.setOptions(t.options),this.scheduleGc()}setOptions(t){this.options=t,this.updateGcTime(this.options.gcTime)}get meta(){return this.options.meta}addObserver(t){R(this,Cs).includes(t)||(R(this,Cs).push(t),this.clearGcTimeout(),R(this,Ln).notify({type:"observerAdded",mutation:this,observer:t}))}removeObserver(t){xe(this,Cs,R(this,Cs).filter(n=>n!==t)),this.scheduleGc(),R(this,Ln).notify({type:"observerRemoved",mutation:this,observer:t})}optionalRemove(){R(this,Cs).length||(this.state.status==="pending"?this.scheduleGc():R(this,Ln).remove(this))}continue(){var t;return((t=R(this,ri))==null?void 0:t.continue())??this.execute(this.state.variables)}async execute(t){var s,o,a,l,c,i,d,p,f,h,g,m,x,b,y,w,S,E,C,k;xe(this,ri,qE({fn:()=>this.options.mutationFn?this.options.mutationFn(t):Promise.reject(new Error("No mutationFn found")),onFail:(T,P)=>{Je(this,Es,Ao).call(this,{type:"failed",failureCount:T,error:P})},onPause:()=>{Je(this,Es,Ao).call(this,{type:"pause"})},onContinue:()=>{Je(this,Es,Ao).call(this,{type:"continue"})},retry:this.options.retry??0,retryDelay:this.options.retryDelay,networkMode:this.options.networkMode,canRun:()=>R(this,Ln).canRun(this)}));const n=this.state.status==="pending",r=!R(this,ri).canStart();try{if(!n){Je(this,Es,Ao).call(this,{type:"pending",variables:t,isPaused:r}),await((o=(s=R(this,Ln).config).onMutate)==null?void 0:o.call(s,t,this));const P=await((l=(a=this.options).onMutate)==null?void 0:l.call(a,t));P!==this.state.context&&Je(this,Es,Ao).call(this,{type:"pending",context:P,variables:t,isPaused:r})}const T=await R(this,ri).start();return await((i=(c=R(this,Ln).config).onSuccess)==null?void 0:i.call(c,T,t,this.state.context,this)),await((p=(d=this.options).onSuccess)==null?void 0:p.call(d,T,t,this.state.context)),await((h=(f=R(this,Ln).config).onSettled)==null?void 0:h.call(f,T,null,this.state.variables,this.state.context,this)),await((m=(g=this.options).onSettled)==null?void 0:m.call(g,T,null,t,this.state.context)),Je(this,Es,Ao).call(this,{type:"success",data:T}),T}catch(T){try{throw await((b=(x=R(this,Ln).config).onError)==null?void 0:b.call(x,T,t,this.state.context,this)),await((w=(y=this.options).onError)==null?void 0:w.call(y,T,t,this.state.context)),await((E=(S=R(this,Ln).config).onSettled)==null?void 0:E.call(S,void 0,T,this.state.variables,this.state.context,this)),await((k=(C=this.options).onSettled)==null?void 0:k.call(C,void 0,T,t,this.state.context)),T}finally{Je(this,Es,Ao).call(this,{type:"error",error:T})}}finally{R(this,Ln).runNext(this)}}},Cs=new WeakMap,Ln=new WeakMap,ri=new WeakMap,Es=new WeakSet,Ao=function(t){const n=r=>{switch(t.type){case"failed":return{...r,failureCount:t.failureCount,failureReason:t.error};case"pause":return{...r,isPaused:!0};case"continue":return{...r,isPaused:!1};case"pending":return{...r,context:t.context,data:void 0,failureCount:0,failureReason:null,error:null,isPaused:t.isPaused,status:"pending",variables:t.variables,submittedAt:Date.now()};case"success":return{...r,data:t.data,failureCount:0,failureReason:null,error:null,status:"success",isPaused:!1};case"error":return{...r,data:void 0,error:t.error,failureCount:r.failureCount+1,failureReason:t.error,isPaused:!1,status:"error"}}};this.state=n(this.state),cn.batch(()=>{R(this,Cs).forEach(r=>{r.onMutationUpdate(t)}),R(this,Ln).notify({mutation:this,type:"updated",action:t})})},CE);function JE(){return{context:void 0,data:void 0,error:null,failureCount:0,failureReason:null,isPaused:!1,status:"idle",variables:void 0,submittedAt:0}}var lr,Od,EE,kD=(EE=class extends lu{constructor(t={}){super();Ie(this,lr);Ie(this,Od);this.config=t,xe(this,lr,new Map),xe(this,Od,Date.now())}build(t,n,r){const s=new TD({mutationCache:this,mutationId:++uf(this,Od)._,options:t.defaultMutationOptions(n),state:r});return this.add(s),s}add(t){const n=df(t),r=R(this,lr).get(n)??[];r.push(t),R(this,lr).set(n,r),this.notify({type:"added",mutation:t})}remove(t){var r;const n=df(t);if(R(this,lr).has(n)){const s=(r=R(this,lr).get(n))==null?void 0:r.filter(o=>o!==t);s&&(s.length===0?R(this,lr).delete(n):R(this,lr).set(n,s))}this.notify({type:"removed",mutation:t})}canRun(t){var r;const n=(r=R(this,lr).get(df(t)))==null?void 0:r.find(s=>s.state.status==="pending");return!n||n===t}runNext(t){var r;const n=(r=R(this,lr).get(df(t)))==null?void 0:r.find(s=>s!==t&&s.state.isPaused);return(n==null?void 0:n.continue())??Promise.resolve()}clear(){cn.batch(()=>{this.getAll().forEach(t=>{this.remove(t)})})}getAll(){return[...R(this,lr).values()].flat()}find(t){const n={exact:!0,...t};return this.getAll().find(r=>Yw(n,r))}findAll(t={}){return this.getAll().filter(n=>Yw(t,n))}notify(t){cn.batch(()=>{this.listeners.forEach(n=>{n(t)})})}resumePausedMutations(){const t=this.getAll().filter(n=>n.state.isPaused);return cn.batch(()=>Promise.all(t.map(n=>n.continue().catch(Or))))}},lr=new WeakMap,Od=new WeakMap,EE);function df(e){var t;return((t=e.options.scope)==null?void 0:t.id)??String(e.mutationId)}function _D(e){return{onFetch:(t,n)=>{const r=async()=>{var g,m,x,b,y;const s=t.options,o=(x=(m=(g=t.fetchOptions)==null?void 0:g.meta)==null?void 0:m.fetchMore)==null?void 0:x.direction,a=((b=t.state.data)==null?void 0:b.pages)||[],l=((y=t.state.data)==null?void 0:y.pageParams)||[],c={pages:[],pageParams:[]};let i=!1;const d=w=>{Object.defineProperty(w,"signal",{enumerable:!0,get:()=>(t.signal.aborted?i=!0:t.signal.addEventListener("abort",()=>{i=!0}),t.signal)})},p=VE(t.options,t.fetchOptions),f=async(w,S,E)=>{if(i)return Promise.reject();if(S==null&&w.pages.length)return Promise.resolve(w);const C={queryKey:t.queryKey,pageParam:S,direction:E?"backward":"forward",meta:t.options.meta};d(C);const k=await p(C),{maxPages:T}=t.options,P=E?vD:mD;return{pages:P(w.pages,k,T),pageParams:P(w.pageParams,S,T)}};let h;if(o&&a.length){const w=o==="backward",S=w?jD:tS,E={pages:a,pageParams:l},C=S(s,E);h=await f(E,C,w)}else{h=await f(c,l[0]??s.initialPageParam);const w=e??a.length;for(let S=1;S{var s,o;return(o=(s=t.options).persister)==null?void 0:o.call(s,r,{queryKey:t.queryKey,meta:t.options.meta,signal:t.signal},n)}:t.fetchFn=r}}}function tS(e,{pages:t,pageParams:n}){const r=t.length-1;return t.length>0?e.getNextPageParam(t[r],t,n[r],n):void 0}function jD(e,{pages:t,pageParams:n}){var r;return t.length>0?(r=e.getPreviousPageParam)==null?void 0:r.call(e,t[0],t,n[0],n):void 0}var Ht,Wo,Go,Fl,Ll,Jo,$l,Bl,TE,RD=(TE=class{constructor(e={}){Ie(this,Ht);Ie(this,Wo);Ie(this,Go);Ie(this,Fl);Ie(this,Ll);Ie(this,Jo);Ie(this,$l);Ie(this,Bl);xe(this,Ht,e.queryCache||new ED),xe(this,Wo,e.mutationCache||new kD),xe(this,Go,e.defaultOptions||{}),xe(this,Fl,new Map),xe(this,Ll,new Map),xe(this,Jo,0)}mount(){uf(this,Jo)._++,R(this,Jo)===1&&(xe(this,$l,Ib.subscribe(async e=>{e&&(await this.resumePausedMutations(),R(this,Ht).onFocus())})),xe(this,Bl,kp.subscribe(async e=>{e&&(await this.resumePausedMutations(),R(this,Ht).onOnline())})))}unmount(){var e,t;uf(this,Jo)._--,R(this,Jo)===0&&((e=R(this,$l))==null||e.call(this),xe(this,$l,void 0),(t=R(this,Bl))==null||t.call(this),xe(this,Bl,void 0))}isFetching(e){return R(this,Ht).findAll({...e,fetchStatus:"fetching"}).length}isMutating(e){return R(this,Wo).findAll({...e,status:"pending"}).length}getQueryData(e){var n;const t=this.defaultQueryOptions({queryKey:e});return(n=R(this,Ht).get(t.queryHash))==null?void 0:n.state.data}ensureQueryData(e){const t=this.getQueryData(e.queryKey);if(t===void 0)return this.fetchQuery(e);{const n=this.defaultQueryOptions(e),r=R(this,Ht).build(this,n);return e.revalidateIfStale&&r.isStaleByTime(bl(n.staleTime,r))&&this.prefetchQuery(n),Promise.resolve(t)}}getQueriesData(e){return R(this,Ht).findAll(e).map(({queryKey:t,state:n})=>{const r=n.data;return[t,r]})}setQueryData(e,t,n){const r=this.defaultQueryOptions({queryKey:e}),s=R(this,Ht).get(r.queryHash),o=s==null?void 0:s.state.data,a=hD(t,o);if(a!==void 0)return R(this,Ht).build(this,r).setData(a,{...n,manual:!0})}setQueriesData(e,t,n){return cn.batch(()=>R(this,Ht).findAll(e).map(({queryKey:r})=>[r,this.setQueryData(r,t,n)]))}getQueryState(e){var n;const t=this.defaultQueryOptions({queryKey:e});return(n=R(this,Ht).get(t.queryHash))==null?void 0:n.state}removeQueries(e){const t=R(this,Ht);cn.batch(()=>{t.findAll(e).forEach(n=>{t.remove(n)})})}resetQueries(e,t){const n=R(this,Ht),r={type:"active",...e};return cn.batch(()=>(n.findAll(e).forEach(s=>{s.reset()}),this.refetchQueries(r,t)))}cancelQueries(e={},t={}){const n={revert:!0,...t},r=cn.batch(()=>R(this,Ht).findAll(e).map(s=>s.cancel(n)));return Promise.all(r).then(Or).catch(Or)}invalidateQueries(e={},t={}){return cn.batch(()=>{if(R(this,Ht).findAll(e).forEach(r=>{r.invalidate()}),e.refetchType==="none")return Promise.resolve();const n={...e,type:e.refetchType??e.type??"active"};return this.refetchQueries(n,t)})}refetchQueries(e={},t){const n={...t,cancelRefetch:(t==null?void 0:t.cancelRefetch)??!0},r=cn.batch(()=>R(this,Ht).findAll(e).filter(s=>!s.isDisabled()).map(s=>{let o=s.fetch(void 0,n);return n.throwOnError||(o=o.catch(Or)),s.state.fetchStatus==="paused"?Promise.resolve():o}));return Promise.all(r).then(Or)}fetchQuery(e){const t=this.defaultQueryOptions(e);t.retry===void 0&&(t.retry=!1);const n=R(this,Ht).build(this,t);return n.isStaleByTime(bl(t.staleTime,n))?n.fetch(t):Promise.resolve(n.state.data)}prefetchQuery(e){return this.fetchQuery(e).then(Or).catch(Or)}fetchInfiniteQuery(e){return e.behavior=_D(e.pages),this.fetchQuery(e)}prefetchInfiniteQuery(e){return this.fetchInfiniteQuery(e).then(Or).catch(Or)}resumePausedMutations(){return kp.isOnline()?R(this,Wo).resumePausedMutations():Promise.resolve()}getQueryCache(){return R(this,Ht)}getMutationCache(){return R(this,Wo)}getDefaultOptions(){return R(this,Go)}setDefaultOptions(e){xe(this,Go,e)}setQueryDefaults(e,t){R(this,Fl).set(gi(e),{queryKey:e,defaultOptions:t})}getQueryDefaults(e){const t=[...R(this,Fl).values()];let n={};return t.forEach(r=>{Dc(e,r.queryKey)&&(n={...n,...r.defaultOptions})}),n}setMutationDefaults(e,t){R(this,Ll).set(gi(e),{mutationKey:e,defaultOptions:t})}getMutationDefaults(e){const t=[...R(this,Ll).values()];let n={};return t.forEach(r=>{Dc(e,r.mutationKey)&&(n={...n,...r.defaultOptions})}),n}defaultQueryOptions(e){if(e._defaulted)return e;const t={...R(this,Go).queries,...this.getQueryDefaults(e.queryKey),...e,_defaulted:!0};return t.queryHash||(t.queryHash=Nb(t.queryKey,t)),t.refetchOnReconnect===void 0&&(t.refetchOnReconnect=t.networkMode!=="always"),t.throwOnError===void 0&&(t.throwOnError=!!t.suspense),!t.networkMode&&t.persister&&(t.networkMode="offlineFirst"),t.enabled!==!0&&t.queryFn===UE&&(t.enabled=!1),t}defaultMutationOptions(e){return e!=null&&e._defaulted?e:{...R(this,Go).mutations,...(e==null?void 0:e.mutationKey)&&this.getMutationDefaults(e.mutationKey),...e,_defaulted:!0}}clear(){R(this,Ht).clear(),R(this,Wo).clear()}},Ht=new WeakMap,Wo=new WeakMap,Go=new WeakMap,Fl=new WeakMap,Ll=new WeakMap,Jo=new WeakMap,$l=new WeakMap,Bl=new WeakMap,TE),Qn,at,Nd,$n,si,zl,Ts,Id,Ul,Vl,oi,ai,Qo,Hl,gt,oc,jv,Rv,Pv,Mv,Ov,Nv,Iv,QE,kE,PD=(kE=class extends lu{constructor(t,n){super();Ie(this,gt);Ie(this,Qn);Ie(this,at);Ie(this,Nd);Ie(this,$n);Ie(this,si);Ie(this,zl);Ie(this,Ts);Ie(this,Id);Ie(this,Ul);Ie(this,Vl);Ie(this,oi);Ie(this,ai);Ie(this,Qo);Ie(this,Hl,new Set);this.options=n,xe(this,Qn,t),xe(this,Ts,null),this.bindMethods(),this.setOptions(n)}bindMethods(){this.refetch=this.refetch.bind(this)}onSubscribe(){this.listeners.size===1&&(R(this,at).addObserver(this),nS(R(this,at),this.options)?Je(this,gt,oc).call(this):this.updateResult(),Je(this,gt,Mv).call(this))}onUnsubscribe(){this.hasListeners()||this.destroy()}shouldFetchOnReconnect(){return Dv(R(this,at),this.options,this.options.refetchOnReconnect)}shouldFetchOnWindowFocus(){return Dv(R(this,at),this.options,this.options.refetchOnWindowFocus)}destroy(){this.listeners=new Set,Je(this,gt,Ov).call(this),Je(this,gt,Nv).call(this),R(this,at).removeObserver(this)}setOptions(t,n){const r=this.options,s=R(this,at);if(this.options=R(this,Qn).defaultQueryOptions(t),this.options.enabled!==void 0&&typeof this.options.enabled!="boolean"&&typeof this.options.enabled!="function"&&typeof Qr(this.options.enabled,R(this,at))!="boolean")throw new Error("Expected enabled to be a boolean or a callback that returns a boolean");Je(this,gt,Iv).call(this),R(this,at).setOptions(this.options),r._defaulted&&!Tp(this.options,r)&&R(this,Qn).getQueryCache().notify({type:"observerOptionsUpdated",query:R(this,at),observer:this});const o=this.hasListeners();o&&rS(R(this,at),s,this.options,r)&&Je(this,gt,oc).call(this),this.updateResult(n),o&&(R(this,at)!==s||Qr(this.options.enabled,R(this,at))!==Qr(r.enabled,R(this,at))||bl(this.options.staleTime,R(this,at))!==bl(r.staleTime,R(this,at)))&&Je(this,gt,jv).call(this);const a=Je(this,gt,Rv).call(this);o&&(R(this,at)!==s||Qr(this.options.enabled,R(this,at))!==Qr(r.enabled,R(this,at))||a!==R(this,Qo))&&Je(this,gt,Pv).call(this,a)}getOptimisticResult(t){const n=R(this,Qn).getQueryCache().build(R(this,Qn),t),r=this.createResult(n,t);return OD(this,r)&&(xe(this,$n,r),xe(this,zl,this.options),xe(this,si,R(this,at).state)),r}getCurrentResult(){return R(this,$n)}trackResult(t,n){const r={};return Object.keys(t).forEach(s=>{Object.defineProperty(r,s,{configurable:!1,enumerable:!0,get:()=>(this.trackProp(s),n==null||n(s),t[s])})}),r}trackProp(t){R(this,Hl).add(t)}getCurrentQuery(){return R(this,at)}refetch({...t}={}){return this.fetch({...t})}fetchOptimistic(t){const n=R(this,Qn).defaultQueryOptions(t),r=R(this,Qn).getQueryCache().build(R(this,Qn),n);return r.isFetchingOptimistic=!0,r.fetch().then(()=>this.createResult(r,n))}fetch(t){return Je(this,gt,oc).call(this,{...t,cancelRefetch:t.cancelRefetch??!0}).then(()=>(this.updateResult(),R(this,$n)))}createResult(t,n){var k;const r=R(this,at),s=this.options,o=R(this,$n),a=R(this,si),l=R(this,zl),i=t!==r?t.state:R(this,Nd),{state:d}=t;let p={...d},f=!1,h;if(n._optimisticResults){const T=this.hasListeners(),P=!T&&nS(t,n),N=T&&rS(t,r,n,s);(P||N)&&(p={...p,...GE(d.data,t.options)}),n._optimisticResults==="isRestoring"&&(p.fetchStatus="idle")}let{error:g,errorUpdatedAt:m,status:x}=p;if(n.select&&p.data!==void 0)if(o&&p.data===(a==null?void 0:a.data)&&n.select===R(this,Id))h=R(this,Ul);else try{xe(this,Id,n.select),h=n.select(p.data),h=_v(o==null?void 0:o.data,h,n),xe(this,Ul,h),xe(this,Ts,null)}catch(T){xe(this,Ts,T)}else h=p.data;if(n.placeholderData!==void 0&&h===void 0&&x==="pending"){let T;if(o!=null&&o.isPlaceholderData&&n.placeholderData===(l==null?void 0:l.placeholderData))T=o.data;else if(T=typeof n.placeholderData=="function"?n.placeholderData((k=R(this,Vl))==null?void 0:k.state.data,R(this,Vl)):n.placeholderData,n.select&&T!==void 0)try{T=n.select(T),xe(this,Ts,null)}catch(P){xe(this,Ts,P)}T!==void 0&&(x="success",h=_v(o==null?void 0:o.data,T,n),f=!0)}R(this,Ts)&&(g=R(this,Ts),h=R(this,Ul),m=Date.now(),x="error");const b=p.fetchStatus==="fetching",y=x==="pending",w=x==="error",S=y&&b,E=h!==void 0;return{status:x,fetchStatus:p.fetchStatus,isPending:y,isSuccess:x==="success",isError:w,isInitialLoading:S,isLoading:S,data:h,dataUpdatedAt:p.dataUpdatedAt,error:g,errorUpdatedAt:m,failureCount:p.fetchFailureCount,failureReason:p.fetchFailureReason,errorUpdateCount:p.errorUpdateCount,isFetched:p.dataUpdateCount>0||p.errorUpdateCount>0,isFetchedAfterMount:p.dataUpdateCount>i.dataUpdateCount||p.errorUpdateCount>i.errorUpdateCount,isFetching:b,isRefetching:b&&!y,isLoadingError:w&&!E,isPaused:p.fetchStatus==="paused",isPlaceholderData:f,isRefetchError:w&&E,isStale:Db(t,n),refetch:this.refetch}}updateResult(t){const n=R(this,$n),r=this.createResult(R(this,at),this.options);if(xe(this,si,R(this,at).state),xe(this,zl,this.options),R(this,si).data!==void 0&&xe(this,Vl,R(this,at)),Tp(r,n))return;xe(this,$n,r);const s={},o=()=>{if(!n)return!0;const{notifyOnChangeProps:a}=this.options,l=typeof a=="function"?a():a;if(l==="all"||!l&&!R(this,Hl).size)return!0;const c=new Set(l??R(this,Hl));return this.options.throwOnError&&c.add("error"),Object.keys(R(this,$n)).some(i=>{const d=i;return R(this,$n)[d]!==n[d]&&c.has(d)})};(t==null?void 0:t.listeners)!==!1&&o()&&(s.listeners=!0),Je(this,gt,QE).call(this,{...s,...t})}onQueryUpdate(){this.updateResult(),this.hasListeners()&&Je(this,gt,Mv).call(this)}},Qn=new WeakMap,at=new WeakMap,Nd=new WeakMap,$n=new WeakMap,si=new WeakMap,zl=new WeakMap,Ts=new WeakMap,Id=new WeakMap,Ul=new WeakMap,Vl=new WeakMap,oi=new WeakMap,ai=new WeakMap,Qo=new WeakMap,Hl=new WeakMap,gt=new WeakSet,oc=function(t){Je(this,gt,Iv).call(this);let n=R(this,at).fetch(this.options,t);return t!=null&&t.throwOnError||(n=n.catch(Or)),n},jv=function(){Je(this,gt,Ov).call(this);const t=bl(this.options.staleTime,R(this,at));if(Kl||R(this,$n).isStale||!Tv(t))return;const r=BE(R(this,$n).dataUpdatedAt,t)+1;xe(this,oi,setTimeout(()=>{R(this,$n).isStale||this.updateResult()},r))},Rv=function(){return(typeof this.options.refetchInterval=="function"?this.options.refetchInterval(R(this,at)):this.options.refetchInterval)??!1},Pv=function(t){Je(this,gt,Nv).call(this),xe(this,Qo,t),!(Kl||Qr(this.options.enabled,R(this,at))===!1||!Tv(R(this,Qo))||R(this,Qo)===0)&&xe(this,ai,setInterval(()=>{(this.options.refetchIntervalInBackground||Ib.isFocused())&&Je(this,gt,oc).call(this)},R(this,Qo)))},Mv=function(){Je(this,gt,jv).call(this),Je(this,gt,Pv).call(this,Je(this,gt,Rv).call(this))},Ov=function(){R(this,oi)&&(clearTimeout(R(this,oi)),xe(this,oi,void 0))},Nv=function(){R(this,ai)&&(clearInterval(R(this,ai)),xe(this,ai,void 0))},Iv=function(){const t=R(this,Qn).getQueryCache().build(R(this,Qn),this.options);if(t===R(this,at))return;const n=R(this,at);xe(this,at,t),xe(this,Nd,t.state),this.hasListeners()&&(n==null||n.removeObserver(this),t.addObserver(this))},QE=function(t){cn.batch(()=>{t.listeners&&this.listeners.forEach(n=>{n(R(this,$n))}),R(this,Qn).getQueryCache().notify({query:R(this,at),type:"observerResultsUpdated"})})},kE);function MD(e,t){return Qr(t.enabled,e)!==!1&&e.state.data===void 0&&!(e.state.status==="error"&&t.retryOnMount===!1)}function nS(e,t){return MD(e,t)||e.state.data!==void 0&&Dv(e,t,t.refetchOnMount)}function Dv(e,t,n){if(Qr(t.enabled,e)!==!1){const r=typeof n=="function"?n(e):n;return r==="always"||r!==!1&&Db(e,t)}return!1}function rS(e,t,n,r){return(e!==t||Qr(r.enabled,e)===!1)&&(!n.suspense||e.state.status!=="error")&&Db(e,n)}function Db(e,t){return Qr(t.enabled,e)!==!1&&e.isStaleByTime(bl(t.staleTime,e))}function OD(e,t){return!Tp(e.getCurrentResult(),t)}var Zo,Yo,Zn,to,co,Xf,Av,_E,ND=(_E=class extends lu{constructor(n,r){super();Ie(this,co);Ie(this,Zo);Ie(this,Yo);Ie(this,Zn);Ie(this,to);xe(this,Zo,n),this.setOptions(r),this.bindMethods(),Je(this,co,Xf).call(this)}bindMethods(){this.mutate=this.mutate.bind(this),this.reset=this.reset.bind(this)}setOptions(n){var s;const r=this.options;this.options=R(this,Zo).defaultMutationOptions(n),Tp(this.options,r)||R(this,Zo).getMutationCache().notify({type:"observerOptionsUpdated",mutation:R(this,Zn),observer:this}),r!=null&&r.mutationKey&&this.options.mutationKey&&gi(r.mutationKey)!==gi(this.options.mutationKey)?this.reset():((s=R(this,Zn))==null?void 0:s.state.status)==="pending"&&R(this,Zn).setOptions(this.options)}onUnsubscribe(){var n;this.hasListeners()||(n=R(this,Zn))==null||n.removeObserver(this)}onMutationUpdate(n){Je(this,co,Xf).call(this),Je(this,co,Av).call(this,n)}getCurrentResult(){return R(this,Yo)}reset(){var n;(n=R(this,Zn))==null||n.removeObserver(this),xe(this,Zn,void 0),Je(this,co,Xf).call(this),Je(this,co,Av).call(this)}mutate(n,r){var s;return xe(this,to,r),(s=R(this,Zn))==null||s.removeObserver(this),xe(this,Zn,R(this,Zo).getMutationCache().build(R(this,Zo),this.options)),R(this,Zn).addObserver(this),R(this,Zn).execute(n)}},Zo=new WeakMap,Yo=new WeakMap,Zn=new WeakMap,to=new WeakMap,co=new WeakSet,Xf=function(){var r;const n=((r=R(this,Zn))==null?void 0:r.state)??JE();xe(this,Yo,{...n,isPending:n.status==="pending",isSuccess:n.status==="success",isError:n.status==="error",isIdle:n.status==="idle",mutate:this.mutate,reset:this.reset})},Av=function(n){cn.batch(()=>{var r,s,o,a,l,c,i,d;if(R(this,to)&&this.hasListeners()){const p=R(this,Yo).variables,f=R(this,Yo).context;(n==null?void 0:n.type)==="success"?((s=(r=R(this,to)).onSuccess)==null||s.call(r,n.data,p,f),(a=(o=R(this,to)).onSettled)==null||a.call(o,n.data,null,p,f)):(n==null?void 0:n.type)==="error"&&((c=(l=R(this,to)).onError)==null||c.call(l,n.error,p,f),(d=(i=R(this,to)).onSettled)==null||d.call(i,void 0,n.error,p,f))}this.listeners.forEach(p=>{p(R(this,Yo))})})},_E),ZE=v.createContext(void 0),Ab=e=>{const t=v.useContext(ZE);if(!t)throw new Error("No QueryClient set, use QueryClientProvider to set one");return t},ID=({client:e,children:t})=>(v.useEffect(()=>(e.mount(),()=>{e.unmount()}),[e]),u.jsx(ZE.Provider,{value:e,children:t})),YE=v.createContext(!1),DD=()=>v.useContext(YE);YE.Provider;function AD(){let e=!1;return{clearReset:()=>{e=!1},reset:()=>{e=!0},isReset:()=>e}}var FD=v.createContext(AD()),LD=()=>v.useContext(FD);function XE(e,t){return typeof e=="function"?e(...t):!!e}function $D(){}var BD=(e,t)=>{(e.suspense||e.throwOnError)&&(t.isReset()||(e.retryOnMount=!1))},zD=e=>{v.useEffect(()=>{e.clearReset()},[e])},UD=({result:e,errorResetBoundary:t,throwOnError:n,query:r})=>e.isError&&!t.isReset()&&!e.isFetching&&r&&XE(n,[e.error,r]),VD=e=>{e.suspense&&(typeof e.staleTime!="number"&&(e.staleTime=1e3),typeof e.gcTime=="number"&&(e.gcTime=Math.max(e.gcTime,1e3)))},HD=(e,t)=>(e==null?void 0:e.suspense)&&t.isPending,KD=(e,t,n)=>t.fetchOptimistic(e).catch(()=>{n.clearReset()});function qD(e,t,n){var i,d,p,f;const r=Ab(),s=DD(),o=LD(),a=r.defaultQueryOptions(e);(d=(i=r.getDefaultOptions().queries)==null?void 0:i._experimental_beforeQuery)==null||d.call(i,a),a._optimisticResults=s?"isRestoring":"optimistic",VD(a),BD(a,o),zD(o);const[l]=v.useState(()=>new t(r,a)),c=l.getOptimisticResult(a);if(v.useSyncExternalStore(v.useCallback(h=>{const g=s?()=>{}:l.subscribe(cn.batchCalls(h));return l.updateResult(),g},[l,s]),()=>l.getCurrentResult(),()=>l.getCurrentResult()),v.useEffect(()=>{l.setOptions(a,{listeners:!1})},[a,l]),HD(a,c))throw KD(a,l,o);if(UD({result:c,errorResetBoundary:o,throwOnError:a.throwOnError,query:r.getQueryCache().get(a.queryHash)}))throw c.error;return(f=(p=r.getDefaultOptions().queries)==null?void 0:p._experimental_afterQuery)==null||f.call(p,a,c),a.notifyOnChangeProps?c:l.trackResult(c)}function lt(e,t){return qD(e,PD)}function WD(e,t){const n=Ab(),[r]=v.useState(()=>new ND(n,e));v.useEffect(()=>{r.setOptions(e)},[r,e]);const s=v.useSyncExternalStore(v.useCallback(a=>r.subscribe(cn.batchCalls(a)),[r]),()=>r.getCurrentResult(),()=>r.getCurrentResult()),o=v.useCallback((a,l)=>{r.mutate(a,l).catch($D)},[r]);if(s.error&&XE(r.options.throwOnError,[s.error]))throw s.error;return{...s,mutate:o,mutateAsync:s.mutate}}var Fv={},eT={exports:{}},Cr={},tT={exports:{}},nT={};/** + * @license React + * scheduler.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */(function(e){function t(F,A){var Y=F.length;F.push(A);e:for(;0>>1,z=F[de];if(0>>1;des(ie,Y))oes(J,ie)?(F[de]=J,F[oe]=Y,de=oe):(F[de]=ie,F[ne]=Y,de=ne);else if(oes(J,Y))F[de]=J,F[oe]=Y,de=oe;else break e}}return A}function s(F,A){var Y=F.sortIndex-A.sortIndex;return Y!==0?Y:F.id-A.id}if(typeof performance=="object"&&typeof performance.now=="function"){var o=performance;e.unstable_now=function(){return o.now()}}else{var a=Date,l=a.now();e.unstable_now=function(){return a.now()-l}}var c=[],i=[],d=1,p=null,f=3,h=!1,g=!1,m=!1,x=typeof setTimeout=="function"?setTimeout:null,b=typeof clearTimeout=="function"?clearTimeout:null,y=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function w(F){for(var A=n(i);A!==null;){if(A.callback===null)r(i);else if(A.startTime<=F)r(i),A.sortIndex=A.expirationTime,t(c,A);else break;A=n(i)}}function S(F){if(m=!1,w(F),!g)if(n(c)!==null)g=!0,ee(E);else{var A=n(i);A!==null&&W(S,A.startTime-F)}}function E(F,A){g=!1,m&&(m=!1,b(T),T=-1),h=!0;var Y=f;try{for(w(A),p=n(c);p!==null&&(!(p.expirationTime>A)||F&&!U());){var de=p.callback;if(typeof de=="function"){p.callback=null,f=p.priorityLevel;var z=de(p.expirationTime<=A);A=e.unstable_now(),typeof z=="function"?p.callback=z:p===n(c)&&r(c),w(A)}else r(c);p=n(c)}if(p!==null)var se=!0;else{var ne=n(i);ne!==null&&W(S,ne.startTime-A),se=!1}return se}finally{p=null,f=Y,h=!1}}var C=!1,k=null,T=-1,P=5,N=-1;function U(){return!(e.unstable_now()-NF||125de?(F.sortIndex=Y,t(i,F),n(c)===null&&F===n(i)&&(m?(b(T),T=-1):m=!0,W(S,Y-de))):(F.sortIndex=z,t(c,F),g||h||(g=!0,ee(E))),F},e.unstable_shouldYield=U,e.unstable_wrapCallback=function(F){var A=f;return function(){var Y=f;f=A;try{return F.apply(this,arguments)}finally{f=Y}}}})(nT);tT.exports=nT;var GD=tT.exports;/** + * @license React + * react-dom.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var JD=v,br=GD;function te(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),Lv=Object.prototype.hasOwnProperty,QD=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,sS={},oS={};function ZD(e){return Lv.call(oS,e)?!0:Lv.call(sS,e)?!1:QD.test(e)?oS[e]=!0:(sS[e]=!0,!1)}function YD(e,t,n,r){if(n!==null&&n.type===0)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return r?!1:n!==null?!n.acceptsBooleans:(e=e.toLowerCase().slice(0,5),e!=="data-"&&e!=="aria-");default:return!1}}function XD(e,t,n,r){if(t===null||typeof t>"u"||YD(e,t,n,r))return!0;if(r)return!1;if(n!==null)switch(n.type){case 3:return!t;case 4:return t===!1;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}function Wn(e,t,n,r,s,o,a){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=r,this.attributeNamespace=s,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=o,this.removeEmptyString=a}var Tn={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){Tn[e]=new Wn(e,0,!1,e,null,!1,!1)});[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0];Tn[t]=new Wn(t,1,!1,e[1],null,!1,!1)});["contentEditable","draggable","spellCheck","value"].forEach(function(e){Tn[e]=new Wn(e,2,!1,e.toLowerCase(),null,!1,!1)});["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){Tn[e]=new Wn(e,2,!1,e,null,!1,!1)});"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){Tn[e]=new Wn(e,3,!1,e.toLowerCase(),null,!1,!1)});["checked","multiple","muted","selected"].forEach(function(e){Tn[e]=new Wn(e,3,!0,e,null,!1,!1)});["capture","download"].forEach(function(e){Tn[e]=new Wn(e,4,!1,e,null,!1,!1)});["cols","rows","size","span"].forEach(function(e){Tn[e]=new Wn(e,6,!1,e,null,!1,!1)});["rowSpan","start"].forEach(function(e){Tn[e]=new Wn(e,5,!1,e.toLowerCase(),null,!1,!1)});var Fb=/[\-:]([a-z])/g;function Lb(e){return e[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var t=e.replace(Fb,Lb);Tn[t]=new Wn(t,1,!1,e,null,!1,!1)});"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var t=e.replace(Fb,Lb);Tn[t]=new Wn(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)});["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace(Fb,Lb);Tn[t]=new Wn(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)});["tabIndex","crossOrigin"].forEach(function(e){Tn[e]=new Wn(e,1,!1,e.toLowerCase(),null,!1,!1)});Tn.xlinkHref=new Wn("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1);["src","href","action","formAction"].forEach(function(e){Tn[e]=new Wn(e,1,!1,e.toLowerCase(),null,!0,!0)});function $b(e,t,n,r){var s=Tn.hasOwnProperty(t)?Tn[t]:null;(s!==null?s.type!==0:r||!(2l||s[a]!==o[l]){var c=` +`+s[a].replace(" at new "," at ");return e.displayName&&c.includes("")&&(c=c.replace("",e.displayName)),c}while(1<=a&&0<=l);break}}}finally{lm=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?ac(e):""}function eA(e){switch(e.tag){case 5:return ac(e.type);case 16:return ac("Lazy");case 13:return ac("Suspense");case 19:return ac("SuspenseList");case 0:case 2:case 15:return e=um(e.type,!1),e;case 11:return e=um(e.type.render,!1),e;case 1:return e=um(e.type,!0),e;default:return""}}function Uv(e){if(e==null)return null;if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case sl:return"Fragment";case rl:return"Portal";case $v:return"Profiler";case Bb:return"StrictMode";case Bv:return"Suspense";case zv:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case oT:return(e.displayName||"Context")+".Consumer";case sT:return(e._context.displayName||"Context")+".Provider";case zb:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case Ub:return t=e.displayName||null,t!==null?t:Uv(e.type)||"Memo";case $o:t=e._payload,e=e._init;try{return Uv(e(t))}catch{}}return null}function tA(e){var t=e.type;switch(e.tag){case 24:return"Cache";case 9:return(t.displayName||"Context")+".Consumer";case 10:return(t._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=t.render,e=e.displayName||e.name||"",t.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return t;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return Uv(t);case 8:return t===Bb?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof t=="function")return t.displayName||t.name||null;if(typeof t=="string")return t}return null}function da(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function iT(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}function nA(e){var t=iT(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=""+e[t];if(!e.hasOwnProperty(t)&&typeof n<"u"&&typeof n.get=="function"&&typeof n.set=="function"){var s=n.get,o=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return s.call(this)},set:function(a){r=""+a,o.call(this,a)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(a){r=""+a},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function pf(e){e._valueTracker||(e._valueTracker=nA(e))}function lT(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r="";return e&&(r=iT(e)?e.checked?"true":"false":e.value),e=r,e!==n?(t.setValue(e),!0):!1}function _p(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}function Vv(e,t){var n=t.checked;return Bt({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:n??e._wrapperState.initialChecked})}function iS(e,t){var n=t.defaultValue==null?"":t.defaultValue,r=t.checked!=null?t.checked:t.defaultChecked;n=da(t.value!=null?t.value:n),e._wrapperState={initialChecked:r,initialValue:n,controlled:t.type==="checkbox"||t.type==="radio"?t.checked!=null:t.value!=null}}function uT(e,t){t=t.checked,t!=null&&$b(e,"checked",t,!1)}function Hv(e,t){uT(e,t);var n=da(t.value),r=t.type;if(n!=null)r==="number"?(n===0&&e.value===""||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if(r==="submit"||r==="reset"){e.removeAttribute("value");return}t.hasOwnProperty("value")?Kv(e,t.type,n):t.hasOwnProperty("defaultValue")&&Kv(e,t.type,da(t.defaultValue)),t.checked==null&&t.defaultChecked!=null&&(e.defaultChecked=!!t.defaultChecked)}function lS(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var r=t.type;if(!(r!=="submit"&&r!=="reset"||t.value!==void 0&&t.value!==null))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}n=e.name,n!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,n!==""&&(e.name=n)}function Kv(e,t,n){(t!=="number"||_p(e.ownerDocument)!==e)&&(n==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}var ic=Array.isArray;function xl(e,t,n,r){if(e=e.options,t){t={};for(var s=0;s"+t.valueOf().toString()+"",t=hf.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}});function Fc(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&n.nodeType===3){n.nodeValue=t;return}}e.textContent=t}var yc={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},rA=["Webkit","ms","Moz","O"];Object.keys(yc).forEach(function(e){rA.forEach(function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),yc[t]=yc[e]})});function pT(e,t,n){return t==null||typeof t=="boolean"||t===""?"":n||typeof t!="number"||t===0||yc.hasOwnProperty(e)&&yc[e]?(""+t).trim():t+"px"}function hT(e,t){e=e.style;for(var n in t)if(t.hasOwnProperty(n)){var r=n.indexOf("--")===0,s=pT(n,t[n],r);n==="float"&&(n="cssFloat"),r?e.setProperty(n,s):e[n]=s}}var sA=Bt({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function Gv(e,t){if(t){if(sA[e]&&(t.children!=null||t.dangerouslySetInnerHTML!=null))throw Error(te(137,e));if(t.dangerouslySetInnerHTML!=null){if(t.children!=null)throw Error(te(60));if(typeof t.dangerouslySetInnerHTML!="object"||!("__html"in t.dangerouslySetInnerHTML))throw Error(te(61))}if(t.style!=null&&typeof t.style!="object")throw Error(te(62))}}function Jv(e,t){if(e.indexOf("-")===-1)return typeof t.is=="string";switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var Qv=null;function Vb(e){return e=e.target||e.srcElement||window,e.correspondingUseElement&&(e=e.correspondingUseElement),e.nodeType===3?e.parentNode:e}var Zv=null,wl=null,Sl=null;function dS(e){if(e=Ld(e)){if(typeof Zv!="function")throw Error(te(280));var t=e.stateNode;t&&(t=Lh(t),Zv(e.stateNode,e.type,t))}}function gT(e){wl?Sl?Sl.push(e):Sl=[e]:wl=e}function mT(){if(wl){var e=wl,t=Sl;if(Sl=wl=null,dS(e),t)for(e=0;e>>=0,e===0?32:31-(gA(e)/mA|0)|0}var gf=64,mf=4194304;function lc(e){switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e&4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return e&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return e}}function Mp(e,t){var n=e.pendingLanes;if(n===0)return 0;var r=0,s=e.suspendedLanes,o=e.pingedLanes,a=n&268435455;if(a!==0){var l=a&~s;l!==0?r=lc(l):(o&=a,o!==0&&(r=lc(o)))}else a=n&~s,a!==0?r=lc(a):o!==0&&(r=lc(o));if(r===0)return 0;if(t!==0&&t!==r&&!(t&s)&&(s=r&-r,o=t&-t,s>=o||s===16&&(o&4194240)!==0))return t;if(r&4&&(r|=n&16),t=e.entangledLanes,t!==0)for(e=e.entanglements,t&=r;0n;n++)t.push(e);return t}function Ad(e,t,n){e.pendingLanes|=t,t!==536870912&&(e.suspendedLanes=0,e.pingedLanes=0),e=e.eventTimes,t=31-ts(t),e[t]=n}function xA(e,t){var n=e.pendingLanes&~t;e.pendingLanes=t,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=t,e.mutableReadLanes&=t,e.entangledLanes&=t,t=e.entanglements;var r=e.eventTimes;for(e=e.expirationTimes;0=xc),xS=" ",wS=!1;function AT(e,t){switch(e){case"keyup":return GA.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function FT(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var ol=!1;function QA(e,t){switch(e){case"compositionend":return FT(t);case"keypress":return t.which!==32?null:(wS=!0,xS);case"textInput":return e=t.data,e===xS&&wS?null:e;default:return null}}function ZA(e,t){if(ol)return e==="compositionend"||!Zb&&AT(e,t)?(e=IT(),tp=Gb=Xo=null,ol=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}e:{for(;n;){if(n.nextSibling){n=n.nextSibling;break e}n=n.parentNode}n=void 0}n=TS(n)}}function zT(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?zT(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function UT(){for(var e=window,t=_p();t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href=="string"}catch{n=!1}if(n)e=t.contentWindow;else break;t=_p(e.document)}return t}function Yb(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}function aF(e){var t=UT(),n=e.focusedElem,r=e.selectionRange;if(t!==n&&n&&n.ownerDocument&&zT(n.ownerDocument.documentElement,n)){if(r!==null&&Yb(n)){if(t=r.start,e=r.end,e===void 0&&(e=t),"selectionStart"in n)n.selectionStart=t,n.selectionEnd=Math.min(e,n.value.length);else if(e=(t=n.ownerDocument||document)&&t.defaultView||window,e.getSelection){e=e.getSelection();var s=n.textContent.length,o=Math.min(r.start,s);r=r.end===void 0?o:Math.min(r.end,s),!e.extend&&o>r&&(s=r,r=o,o=s),s=kS(n,o);var a=kS(n,r);s&&a&&(e.rangeCount!==1||e.anchorNode!==s.node||e.anchorOffset!==s.offset||e.focusNode!==a.node||e.focusOffset!==a.offset)&&(t=t.createRange(),t.setStart(s.node,s.offset),e.removeAllRanges(),o>r?(e.addRange(t),e.extend(a.node,a.offset)):(t.setEnd(a.node,a.offset),e.addRange(t)))}}for(t=[],e=n;e=e.parentNode;)e.nodeType===1&&t.push({element:e,left:e.scrollLeft,top:e.scrollTop});for(typeof n.focus=="function"&&n.focus(),n=0;n=document.documentMode,al=null,ry=null,Sc=null,sy=!1;function _S(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;sy||al==null||al!==_p(r)||(r=al,"selectionStart"in r&&Yb(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),Sc&&Vc(Sc,r)||(Sc=r,r=Ip(ry,"onSelect"),0ul||(e.current=cy[ul],cy[ul]=null,ul--)}function Et(e,t){ul++,cy[ul]=e.current,e.current=t}var fa={},In=Ea(fa),tr=Ea(!1),mi=fa;function Wl(e,t){var n=e.type.contextTypes;if(!n)return fa;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var s={},o;for(o in n)s[o]=t[o];return r&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=s),s}function nr(e){return e=e.childContextTypes,e!=null}function Ap(){Pt(tr),Pt(In)}function IS(e,t,n){if(In.current!==fa)throw Error(te(168));Et(In,t),Et(tr,n)}function ZT(e,t,n){var r=e.stateNode;if(t=t.childContextTypes,typeof r.getChildContext!="function")return n;r=r.getChildContext();for(var s in r)if(!(s in t))throw Error(te(108,tA(e)||"Unknown",s));return Bt({},n,r)}function Fp(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||fa,mi=In.current,Et(In,e),Et(tr,tr.current),!0}function DS(e,t,n){var r=e.stateNode;if(!r)throw Error(te(169));n?(e=ZT(e,t,mi),r.__reactInternalMemoizedMergedChildContext=e,Pt(tr),Pt(In),Et(In,e)):Pt(tr),Et(tr,n)}var eo=null,$h=!1,Cm=!1;function YT(e){eo===null?eo=[e]:eo.push(e)}function yF(e){$h=!0,YT(e)}function Ta(){if(!Cm&&eo!==null){Cm=!0;var e=0,t=vt;try{var n=eo;for(vt=1;e>=a,s-=a,ro=1<<32-ts(t)+s|n<T?(P=k,k=null):P=k.sibling;var N=f(b,k,w[T],S);if(N===null){k===null&&(k=P);break}e&&k&&N.alternate===null&&t(b,k),y=o(N,y,T),C===null?E=N:C.sibling=N,C=N,k=P}if(T===w.length)return n(b,k),Ot&&$a(b,T),E;if(k===null){for(;TT?(P=k,k=null):P=k.sibling;var U=f(b,k,N.value,S);if(U===null){k===null&&(k=P);break}e&&k&&U.alternate===null&&t(b,k),y=o(U,y,T),C===null?E=U:C.sibling=U,C=U,k=P}if(N.done)return n(b,k),Ot&&$a(b,T),E;if(k===null){for(;!N.done;T++,N=w.next())N=p(b,N.value,S),N!==null&&(y=o(N,y,T),C===null?E=N:C.sibling=N,C=N);return Ot&&$a(b,T),E}for(k=r(b,k);!N.done;T++,N=w.next())N=h(k,b,T,N.value,S),N!==null&&(e&&N.alternate!==null&&k.delete(N.key===null?T:N.key),y=o(N,y,T),C===null?E=N:C.sibling=N,C=N);return e&&k.forEach(function(I){return t(b,I)}),Ot&&$a(b,T),E}function x(b,y,w,S){if(typeof w=="object"&&w!==null&&w.type===sl&&w.key===null&&(w=w.props.children),typeof w=="object"&&w!==null){switch(w.$$typeof){case ff:e:{for(var E=w.key,C=y;C!==null;){if(C.key===E){if(E=w.type,E===sl){if(C.tag===7){n(b,C.sibling),y=s(C,w.props.children),y.return=b,b=y;break e}}else if(C.elementType===E||typeof E=="object"&&E!==null&&E.$$typeof===$o&&LS(E)===C.type){n(b,C.sibling),y=s(C,w.props),y.ref=Uu(b,C,w),y.return=b,b=y;break e}n(b,C);break}else t(b,C);C=C.sibling}w.type===sl?(y=li(w.props.children,b.mode,S,w.key),y.return=b,b=y):(S=up(w.type,w.key,w.props,null,b.mode,S),S.ref=Uu(b,y,w),S.return=b,b=S)}return a(b);case rl:e:{for(C=w.key;y!==null;){if(y.key===C)if(y.tag===4&&y.stateNode.containerInfo===w.containerInfo&&y.stateNode.implementation===w.implementation){n(b,y.sibling),y=s(y,w.children||[]),y.return=b,b=y;break e}else{n(b,y);break}else t(b,y);y=y.sibling}y=Mm(w,b.mode,S),y.return=b,b=y}return a(b);case $o:return C=w._init,x(b,y,C(w._payload),S)}if(ic(w))return g(b,y,w,S);if(Fu(w))return m(b,y,w,S);Cf(b,w)}return typeof w=="string"&&w!==""||typeof w=="number"?(w=""+w,y!==null&&y.tag===6?(n(b,y.sibling),y=s(y,w),y.return=b,b=y):(n(b,y),y=Pm(w,b.mode,S),y.return=b,b=y),a(b)):n(b,y)}return x}var Jl=nk(!0),rk=nk(!1),Bp=Ea(null),zp=null,fl=null,nx=null;function rx(){nx=fl=zp=null}function sx(e){var t=Bp.current;Pt(Bp),e._currentValue=t}function py(e,t,n){for(;e!==null;){var r=e.alternate;if((e.childLanes&t)!==t?(e.childLanes|=t,r!==null&&(r.childLanes|=t)):r!==null&&(r.childLanes&t)!==t&&(r.childLanes|=t),e===n)break;e=e.return}}function El(e,t){zp=e,nx=fl=null,e=e.dependencies,e!==null&&e.firstContext!==null&&(e.lanes&t&&(er=!0),e.firstContext=null)}function Br(e){var t=e._currentValue;if(nx!==e)if(e={context:e,memoizedValue:t,next:null},fl===null){if(zp===null)throw Error(te(308));fl=e,zp.dependencies={lanes:0,firstContext:e}}else fl=fl.next=e;return t}var Ha=null;function ox(e){Ha===null?Ha=[e]:Ha.push(e)}function sk(e,t,n,r){var s=t.interleaved;return s===null?(n.next=n,ox(t)):(n.next=s.next,s.next=n),t.interleaved=n,ho(e,r)}function ho(e,t){e.lanes|=t;var n=e.alternate;for(n!==null&&(n.lanes|=t),n=e,e=e.return;e!==null;)e.childLanes|=t,n=e.alternate,n!==null&&(n.childLanes|=t),n=e,e=e.return;return n.tag===3?n.stateNode:null}var Bo=!1;function ax(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,interleaved:null,lanes:0},effects:null}}function ok(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,effects:e.effects})}function lo(e,t){return{eventTime:e,lane:t,tag:0,payload:null,callback:null,next:null}}function ia(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,ct&2){var s=r.pending;return s===null?t.next=t:(t.next=s.next,s.next=t),r.pending=t,ho(e,n)}return s=r.interleaved,s===null?(t.next=t,ox(r)):(t.next=s.next,s.next=t),r.interleaved=t,ho(e,n)}function rp(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,(n&4194240)!==0)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,Kb(e,n)}}function $S(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var s=null,o=null;if(n=n.firstBaseUpdate,n!==null){do{var a={eventTime:n.eventTime,lane:n.lane,tag:n.tag,payload:n.payload,callback:n.callback,next:null};o===null?s=o=a:o=o.next=a,n=n.next}while(n!==null);o===null?s=o=t:o=o.next=t}else s=o=t;n={baseState:r.baseState,firstBaseUpdate:s,lastBaseUpdate:o,shared:r.shared,effects:r.effects},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}function Up(e,t,n,r){var s=e.updateQueue;Bo=!1;var o=s.firstBaseUpdate,a=s.lastBaseUpdate,l=s.shared.pending;if(l!==null){s.shared.pending=null;var c=l,i=c.next;c.next=null,a===null?o=i:a.next=i,a=c;var d=e.alternate;d!==null&&(d=d.updateQueue,l=d.lastBaseUpdate,l!==a&&(l===null?d.firstBaseUpdate=i:l.next=i,d.lastBaseUpdate=c))}if(o!==null){var p=s.baseState;a=0,d=i=c=null,l=o;do{var f=l.lane,h=l.eventTime;if((r&f)===f){d!==null&&(d=d.next={eventTime:h,lane:0,tag:l.tag,payload:l.payload,callback:l.callback,next:null});e:{var g=e,m=l;switch(f=t,h=n,m.tag){case 1:if(g=m.payload,typeof g=="function"){p=g.call(h,p,f);break e}p=g;break e;case 3:g.flags=g.flags&-65537|128;case 0:if(g=m.payload,f=typeof g=="function"?g.call(h,p,f):g,f==null)break e;p=Bt({},p,f);break e;case 2:Bo=!0}}l.callback!==null&&l.lane!==0&&(e.flags|=64,f=s.effects,f===null?s.effects=[l]:f.push(l))}else h={eventTime:h,lane:f,tag:l.tag,payload:l.payload,callback:l.callback,next:null},d===null?(i=d=h,c=p):d=d.next=h,a|=f;if(l=l.next,l===null){if(l=s.shared.pending,l===null)break;f=l,l=f.next,f.next=null,s.lastBaseUpdate=f,s.shared.pending=null}}while(!0);if(d===null&&(c=p),s.baseState=c,s.firstBaseUpdate=i,s.lastBaseUpdate=d,t=s.shared.interleaved,t!==null){s=t;do a|=s.lane,s=s.next;while(s!==t)}else o===null&&(s.shared.lanes=0);bi|=a,e.lanes=a,e.memoizedState=p}}function BS(e,t,n){if(e=t.effects,t.effects=null,e!==null)for(t=0;tn?n:4,e(!0);var r=Tm.transition;Tm.transition={};try{e(!1),t()}finally{vt=n,Tm.transition=r}}function Sk(){return zr().memoizedState}function SF(e,t,n){var r=ua(e);if(n={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null},Ck(e))Ek(t,n);else if(n=sk(e,t,n,r),n!==null){var s=Hn();ns(n,e,r,s),Tk(n,t,r)}}function CF(e,t,n){var r=ua(e),s={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null};if(Ck(e))Ek(t,s);else{var o=e.alternate;if(e.lanes===0&&(o===null||o.lanes===0)&&(o=t.lastRenderedReducer,o!==null))try{var a=t.lastRenderedState,l=o(a,n);if(s.hasEagerState=!0,s.eagerState=l,us(l,a)){var c=t.interleaved;c===null?(s.next=s,ox(t)):(s.next=c.next,c.next=s),t.interleaved=s;return}}catch{}finally{}n=sk(e,t,s,r),n!==null&&(s=Hn(),ns(n,e,r,s),Tk(n,t,r))}}function Ck(e){var t=e.alternate;return e===Lt||t!==null&&t===Lt}function Ek(e,t){Cc=Hp=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function Tk(e,t,n){if(n&4194240){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,Kb(e,n)}}var Kp={readContext:Br,useCallback:jn,useContext:jn,useEffect:jn,useImperativeHandle:jn,useInsertionEffect:jn,useLayoutEffect:jn,useMemo:jn,useReducer:jn,useRef:jn,useState:jn,useDebugValue:jn,useDeferredValue:jn,useTransition:jn,useMutableSource:jn,useSyncExternalStore:jn,useId:jn,unstable_isNewReconciler:!1},EF={readContext:Br,useCallback:function(e,t){return ws().memoizedState=[e,t===void 0?null:t],e},useContext:Br,useEffect:US,useImperativeHandle:function(e,t,n){return n=n!=null?n.concat([e]):null,op(4194308,4,vk.bind(null,t,e),n)},useLayoutEffect:function(e,t){return op(4194308,4,e,t)},useInsertionEffect:function(e,t){return op(4,2,e,t)},useMemo:function(e,t){var n=ws();return t=t===void 0?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var r=ws();return t=n!==void 0?n(t):t,r.memoizedState=r.baseState=t,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:t},r.queue=e,e=e.dispatch=SF.bind(null,Lt,e),[r.memoizedState,e]},useRef:function(e){var t=ws();return e={current:e},t.memoizedState=e},useState:zS,useDebugValue:hx,useDeferredValue:function(e){return ws().memoizedState=e},useTransition:function(){var e=zS(!1),t=e[0];return e=wF.bind(null,e[1]),ws().memoizedState=e,[t,e]},useMutableSource:function(){},useSyncExternalStore:function(e,t,n){var r=Lt,s=ws();if(Ot){if(n===void 0)throw Error(te(407));n=n()}else{if(n=t(),vn===null)throw Error(te(349));yi&30||uk(r,t,n)}s.memoizedState=n;var o={value:n,getSnapshot:t};return s.queue=o,US(dk.bind(null,r,o,e),[e]),r.flags|=2048,Zc(9,ck.bind(null,r,o,n,t),void 0,null),n},useId:function(){var e=ws(),t=vn.identifierPrefix;if(Ot){var n=so,r=ro;n=(r&~(1<<32-ts(r)-1)).toString(32)+n,t=":"+t+"R"+n,n=Jc++,0<\/script>",e=e.removeChild(e.firstChild)):typeof r.is=="string"?e=a.createElement(n,{is:r.is}):(e=a.createElement(n),n==="select"&&(a=e,r.multiple?a.multiple=!0:r.size&&(a.size=r.size))):e=a.createElementNS(e,n),e[ks]=t,e[qc]=r,Dk(e,t,!1,!1),t.stateNode=e;e:{switch(a=Jv(n,r),n){case"dialog":jt("cancel",e),jt("close",e),s=r;break;case"iframe":case"object":case"embed":jt("load",e),s=r;break;case"video":case"audio":for(s=0;sYl&&(t.flags|=128,r=!0,Vu(o,!1),t.lanes=4194304)}else{if(!r)if(e=Vp(a),e!==null){if(t.flags|=128,r=!0,n=e.updateQueue,n!==null&&(t.updateQueue=n,t.flags|=4),Vu(o,!0),o.tail===null&&o.tailMode==="hidden"&&!a.alternate&&!Ot)return Rn(t),null}else 2*Jt()-o.renderingStartTime>Yl&&n!==1073741824&&(t.flags|=128,r=!0,Vu(o,!1),t.lanes=4194304);o.isBackwards?(a.sibling=t.child,t.child=a):(n=o.last,n!==null?n.sibling=a:t.child=a,o.last=a)}return o.tail!==null?(t=o.tail,o.rendering=t,o.tail=t.sibling,o.renderingStartTime=Jt(),t.sibling=null,n=Ft.current,Et(Ft,r?n&1|2:n&1),t):(Rn(t),null);case 22:case 23:return xx(),r=t.memoizedState!==null,e!==null&&e.memoizedState!==null!==r&&(t.flags|=8192),r&&t.mode&1?cr&1073741824&&(Rn(t),t.subtreeFlags&6&&(t.flags|=8192)):Rn(t),null;case 24:return null;case 25:return null}throw Error(te(156,t.tag))}function OF(e,t){switch(ex(t),t.tag){case 1:return nr(t.type)&&Ap(),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return Ql(),Pt(tr),Pt(In),ux(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 5:return lx(t),null;case 13:if(Pt(Ft),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(te(340));Gl()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return Pt(Ft),null;case 4:return Ql(),null;case 10:return sx(t.type._context),null;case 22:case 23:return xx(),null;case 24:return null;default:return null}}var Tf=!1,Nn=!1,NF=typeof WeakSet=="function"?WeakSet:Set,we=null;function pl(e,t){var n=e.ref;if(n!==null)if(typeof n=="function")try{n(null)}catch(r){Kt(e,t,r)}else n.current=null}function Sy(e,t,n){try{n()}catch(r){Kt(e,t,r)}}var XS=!1;function IF(e,t){if(oy=Op,e=UT(),Yb(e)){if("selectionStart"in e)var n={start:e.selectionStart,end:e.selectionEnd};else e:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var s=r.anchorOffset,o=r.focusNode;r=r.focusOffset;try{n.nodeType,o.nodeType}catch{n=null;break e}var a=0,l=-1,c=-1,i=0,d=0,p=e,f=null;t:for(;;){for(var h;p!==n||s!==0&&p.nodeType!==3||(l=a+s),p!==o||r!==0&&p.nodeType!==3||(c=a+r),p.nodeType===3&&(a+=p.nodeValue.length),(h=p.firstChild)!==null;)f=p,p=h;for(;;){if(p===e)break t;if(f===n&&++i===s&&(l=a),f===o&&++d===r&&(c=a),(h=p.nextSibling)!==null)break;p=f,f=p.parentNode}p=h}n=l===-1||c===-1?null:{start:l,end:c}}else n=null}n=n||{start:0,end:0}}else n=null;for(ay={focusedElem:e,selectionRange:n},Op=!1,we=t;we!==null;)if(t=we,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,we=e;else for(;we!==null;){t=we;try{var g=t.alternate;if(t.flags&1024)switch(t.tag){case 0:case 11:case 15:break;case 1:if(g!==null){var m=g.memoizedProps,x=g.memoizedState,b=t.stateNode,y=b.getSnapshotBeforeUpdate(t.elementType===t.type?m:qr(t.type,m),x);b.__reactInternalSnapshotBeforeUpdate=y}break;case 3:var w=t.stateNode.containerInfo;w.nodeType===1?w.textContent="":w.nodeType===9&&w.documentElement&&w.removeChild(w.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(te(163))}}catch(S){Kt(t,t.return,S)}if(e=t.sibling,e!==null){e.return=t.return,we=e;break}we=t.return}return g=XS,XS=!1,g}function Ec(e,t,n){var r=t.updateQueue;if(r=r!==null?r.lastEffect:null,r!==null){var s=r=r.next;do{if((s.tag&e)===e){var o=s.destroy;s.destroy=void 0,o!==void 0&&Sy(t,n,o)}s=s.next}while(s!==r)}}function Uh(e,t){if(t=t.updateQueue,t=t!==null?t.lastEffect:null,t!==null){var n=t=t.next;do{if((n.tag&e)===e){var r=n.create;n.destroy=r()}n=n.next}while(n!==t)}}function Cy(e){var t=e.ref;if(t!==null){var n=e.stateNode;switch(e.tag){case 5:e=n;break;default:e=n}typeof t=="function"?t(e):t.current=e}}function Lk(e){var t=e.alternate;t!==null&&(e.alternate=null,Lk(t)),e.child=null,e.deletions=null,e.sibling=null,e.tag===5&&(t=e.stateNode,t!==null&&(delete t[ks],delete t[qc],delete t[uy],delete t[mF],delete t[vF])),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function $k(e){return e.tag===5||e.tag===3||e.tag===4}function e0(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||$k(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function Ey(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.nodeType===8?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(n.nodeType===8?(t=n.parentNode,t.insertBefore(e,n)):(t=n,t.appendChild(e)),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=Dp));else if(r!==4&&(e=e.child,e!==null))for(Ey(e,t,n),e=e.sibling;e!==null;)Ey(e,t,n),e=e.sibling}function Ty(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(e=e.child,e!==null))for(Ty(e,t,n),e=e.sibling;e!==null;)Ty(e,t,n),e=e.sibling}var Sn=null,Gr=!1;function Mo(e,t,n){for(n=n.child;n!==null;)Bk(e,t,n),n=n.sibling}function Bk(e,t,n){if(Ds&&typeof Ds.onCommitFiberUnmount=="function")try{Ds.onCommitFiberUnmount(Ih,n)}catch{}switch(n.tag){case 5:Nn||pl(n,t);case 6:var r=Sn,s=Gr;Sn=null,Mo(e,t,n),Sn=r,Gr=s,Sn!==null&&(Gr?(e=Sn,n=n.stateNode,e.nodeType===8?e.parentNode.removeChild(n):e.removeChild(n)):Sn.removeChild(n.stateNode));break;case 18:Sn!==null&&(Gr?(e=Sn,n=n.stateNode,e.nodeType===8?Sm(e.parentNode,n):e.nodeType===1&&Sm(e,n),zc(e)):Sm(Sn,n.stateNode));break;case 4:r=Sn,s=Gr,Sn=n.stateNode.containerInfo,Gr=!0,Mo(e,t,n),Sn=r,Gr=s;break;case 0:case 11:case 14:case 15:if(!Nn&&(r=n.updateQueue,r!==null&&(r=r.lastEffect,r!==null))){s=r=r.next;do{var o=s,a=o.destroy;o=o.tag,a!==void 0&&(o&2||o&4)&&Sy(n,t,a),s=s.next}while(s!==r)}Mo(e,t,n);break;case 1:if(!Nn&&(pl(n,t),r=n.stateNode,typeof r.componentWillUnmount=="function"))try{r.props=n.memoizedProps,r.state=n.memoizedState,r.componentWillUnmount()}catch(l){Kt(n,t,l)}Mo(e,t,n);break;case 21:Mo(e,t,n);break;case 22:n.mode&1?(Nn=(r=Nn)||n.memoizedState!==null,Mo(e,t,n),Nn=r):Mo(e,t,n);break;default:Mo(e,t,n)}}function t0(e){var t=e.updateQueue;if(t!==null){e.updateQueue=null;var n=e.stateNode;n===null&&(n=e.stateNode=new NF),t.forEach(function(r){var s=VF.bind(null,e,r);n.has(r)||(n.add(r),r.then(s,s))})}}function Kr(e,t){var n=t.deletions;if(n!==null)for(var r=0;rs&&(s=a),r&=~o}if(r=s,r=Jt()-r,r=(120>r?120:480>r?480:1080>r?1080:1920>r?1920:3e3>r?3e3:4320>r?4320:1960*AF(r/1960))-r,10e?16:e,ea===null)var r=!1;else{if(e=ea,ea=null,Gp=0,ct&6)throw Error(te(331));var s=ct;for(ct|=4,we=e.current;we!==null;){var o=we,a=o.child;if(we.flags&16){var l=o.deletions;if(l!==null){for(var c=0;cJt()-yx?ii(e,0):vx|=n),rr(e,t)}function Gk(e,t){t===0&&(e.mode&1?(t=mf,mf<<=1,!(mf&130023424)&&(mf=4194304)):t=1);var n=Hn();e=ho(e,t),e!==null&&(Ad(e,t,n),rr(e,n))}function UF(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),Gk(e,n)}function VF(e,t){var n=0;switch(e.tag){case 13:var r=e.stateNode,s=e.memoizedState;s!==null&&(n=s.retryLane);break;case 19:r=e.stateNode;break;default:throw Error(te(314))}r!==null&&r.delete(t),Gk(e,n)}var Jk;Jk=function(e,t,n){if(e!==null)if(e.memoizedProps!==t.pendingProps||tr.current)er=!0;else{if(!(e.lanes&n)&&!(t.flags&128))return er=!1,PF(e,t,n);er=!!(e.flags&131072)}else er=!1,Ot&&t.flags&1048576&&XT(t,$p,t.index);switch(t.lanes=0,t.tag){case 2:var r=t.type;ap(e,t),e=t.pendingProps;var s=Wl(t,In.current);El(t,n),s=dx(null,t,r,e,s,n);var o=fx();return t.flags|=1,typeof s=="object"&&s!==null&&typeof s.render=="function"&&s.$$typeof===void 0?(t.tag=1,t.memoizedState=null,t.updateQueue=null,nr(r)?(o=!0,Fp(t)):o=!1,t.memoizedState=s.state!==null&&s.state!==void 0?s.state:null,ax(t),s.updater=zh,t.stateNode=s,s._reactInternals=t,gy(t,r,e,n),t=yy(null,t,r,!0,o,n)):(t.tag=0,Ot&&o&&Xb(t),zn(null,t,s,n),t=t.child),t;case 16:r=t.elementType;e:{switch(ap(e,t),e=t.pendingProps,s=r._init,r=s(r._payload),t.type=r,s=t.tag=KF(r),e=qr(r,e),s){case 0:t=vy(null,t,r,e,n);break e;case 1:t=QS(null,t,r,e,n);break e;case 11:t=GS(null,t,r,e,n);break e;case 14:t=JS(null,t,r,qr(r.type,e),n);break e}throw Error(te(306,r,""))}return t;case 0:return r=t.type,s=t.pendingProps,s=t.elementType===r?s:qr(r,s),vy(e,t,r,s,n);case 1:return r=t.type,s=t.pendingProps,s=t.elementType===r?s:qr(r,s),QS(e,t,r,s,n);case 3:e:{if(Ok(t),e===null)throw Error(te(387));r=t.pendingProps,o=t.memoizedState,s=o.element,ok(e,t),Up(t,r,null,n);var a=t.memoizedState;if(r=a.element,o.isDehydrated)if(o={element:r,isDehydrated:!1,cache:a.cache,pendingSuspenseBoundaries:a.pendingSuspenseBoundaries,transitions:a.transitions},t.updateQueue.baseState=o,t.memoizedState=o,t.flags&256){s=Zl(Error(te(423)),t),t=ZS(e,t,r,n,s);break e}else if(r!==s){s=Zl(Error(te(424)),t),t=ZS(e,t,r,n,s);break e}else for(hr=aa(t.stateNode.containerInfo.firstChild),mr=t,Ot=!0,Zr=null,n=rk(t,null,r,n),t.child=n;n;)n.flags=n.flags&-3|4096,n=n.sibling;else{if(Gl(),r===s){t=go(e,t,n);break e}zn(e,t,r,n)}t=t.child}return t;case 5:return ak(t),e===null&&fy(t),r=t.type,s=t.pendingProps,o=e!==null?e.memoizedProps:null,a=s.children,iy(r,s)?a=null:o!==null&&iy(r,o)&&(t.flags|=32),Mk(e,t),zn(e,t,a,n),t.child;case 6:return e===null&&fy(t),null;case 13:return Nk(e,t,n);case 4:return ix(t,t.stateNode.containerInfo),r=t.pendingProps,e===null?t.child=Jl(t,null,r,n):zn(e,t,r,n),t.child;case 11:return r=t.type,s=t.pendingProps,s=t.elementType===r?s:qr(r,s),GS(e,t,r,s,n);case 7:return zn(e,t,t.pendingProps,n),t.child;case 8:return zn(e,t,t.pendingProps.children,n),t.child;case 12:return zn(e,t,t.pendingProps.children,n),t.child;case 10:e:{if(r=t.type._context,s=t.pendingProps,o=t.memoizedProps,a=s.value,Et(Bp,r._currentValue),r._currentValue=a,o!==null)if(us(o.value,a)){if(o.children===s.children&&!tr.current){t=go(e,t,n);break e}}else for(o=t.child,o!==null&&(o.return=t);o!==null;){var l=o.dependencies;if(l!==null){a=o.child;for(var c=l.firstContext;c!==null;){if(c.context===r){if(o.tag===1){c=lo(-1,n&-n),c.tag=2;var i=o.updateQueue;if(i!==null){i=i.shared;var d=i.pending;d===null?c.next=c:(c.next=d.next,d.next=c),i.pending=c}}o.lanes|=n,c=o.alternate,c!==null&&(c.lanes|=n),py(o.return,n,t),l.lanes|=n;break}c=c.next}}else if(o.tag===10)a=o.type===t.type?null:o.child;else if(o.tag===18){if(a=o.return,a===null)throw Error(te(341));a.lanes|=n,l=a.alternate,l!==null&&(l.lanes|=n),py(a,n,t),a=o.sibling}else a=o.child;if(a!==null)a.return=o;else for(a=o;a!==null;){if(a===t){a=null;break}if(o=a.sibling,o!==null){o.return=a.return,a=o;break}a=a.return}o=a}zn(e,t,s.children,n),t=t.child}return t;case 9:return s=t.type,r=t.pendingProps.children,El(t,n),s=Br(s),r=r(s),t.flags|=1,zn(e,t,r,n),t.child;case 14:return r=t.type,s=qr(r,t.pendingProps),s=qr(r.type,s),JS(e,t,r,s,n);case 15:return Rk(e,t,t.type,t.pendingProps,n);case 17:return r=t.type,s=t.pendingProps,s=t.elementType===r?s:qr(r,s),ap(e,t),t.tag=1,nr(r)?(e=!0,Fp(t)):e=!1,El(t,n),kk(t,r,s),gy(t,r,s,n),yy(null,t,r,!0,e,n);case 19:return Ik(e,t,n);case 22:return Pk(e,t,n)}throw Error(te(156,t.tag))};function Qk(e,t){return CT(e,t)}function HF(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function Ar(e,t,n,r){return new HF(e,t,n,r)}function Sx(e){return e=e.prototype,!(!e||!e.isReactComponent)}function KF(e){if(typeof e=="function")return Sx(e)?1:0;if(e!=null){if(e=e.$$typeof,e===zb)return 11;if(e===Ub)return 14}return 2}function ca(e,t){var n=e.alternate;return n===null?(n=Ar(e.tag,t,e.key,e.mode),n.elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.subtreeFlags=0,n.deletions=null),n.flags=e.flags&14680064,n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=t===null?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function up(e,t,n,r,s,o){var a=2;if(r=e,typeof e=="function")Sx(e)&&(a=1);else if(typeof e=="string")a=5;else e:switch(e){case sl:return li(n.children,s,o,t);case Bb:a=8,s|=8;break;case $v:return e=Ar(12,n,t,s|2),e.elementType=$v,e.lanes=o,e;case Bv:return e=Ar(13,n,t,s),e.elementType=Bv,e.lanes=o,e;case zv:return e=Ar(19,n,t,s),e.elementType=zv,e.lanes=o,e;case aT:return Hh(n,s,o,t);default:if(typeof e=="object"&&e!==null)switch(e.$$typeof){case sT:a=10;break e;case oT:a=9;break e;case zb:a=11;break e;case Ub:a=14;break e;case $o:a=16,r=null;break e}throw Error(te(130,e==null?e:typeof e,""))}return t=Ar(a,n,t,s),t.elementType=e,t.type=r,t.lanes=o,t}function li(e,t,n,r){return e=Ar(7,e,r,t),e.lanes=n,e}function Hh(e,t,n,r){return e=Ar(22,e,r,t),e.elementType=aT,e.lanes=n,e.stateNode={isHidden:!1},e}function Pm(e,t,n){return e=Ar(6,e,null,t),e.lanes=n,e}function Mm(e,t,n){return t=Ar(4,e.children!==null?e.children:[],e.key,t),t.lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function qF(e,t,n,r,s){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=dm(0),this.expirationTimes=dm(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=dm(0),this.identifierPrefix=r,this.onRecoverableError=s,this.mutableSourceEagerHydrationData=null}function Cx(e,t,n,r,s,o,a,l,c){return e=new qF(e,t,n,l,c),t===1?(t=1,o===!0&&(t|=8)):t=0,o=Ar(3,null,null,t),e.current=o,o.stateNode=e,o.memoizedState={element:r,isDehydrated:n,cache:null,transitions:null,pendingSuspenseBoundaries:null},ax(o),e}function WF(e,t,n){var r=3"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(e_)}catch(e){console.error(e)}}e_(),eT.exports=Cr;var ka=eT.exports;const t_=jb(ka),YF=jE({__proto__:null,default:t_},[ka]);var u0=ka;Fv.createRoot=u0.createRoot,Fv.hydrateRoot=u0.hydrateRoot;const XF=(...e)=>{console!=null&&console.warn&&(ui(e[0])&&(e[0]=`react-i18next:: ${e[0]}`),console.warn(...e))},c0={},Py=(...e)=>{ui(e[0])&&c0[e[0]]||(ui(e[0])&&(c0[e[0]]=new Date),XF(...e))},n_=(e,t)=>()=>{if(e.isInitialized)t();else{const n=()=>{setTimeout(()=>{e.off("initialized",n)},0),t()};e.on("initialized",n)}},d0=(e,t,n)=>{e.loadNamespaces(t,n_(e,n))},f0=(e,t,n,r)=>{ui(n)&&(n=[n]),n.forEach(s=>{e.options.ns.indexOf(s)<0&&e.options.ns.push(s)}),e.loadLanguages(t,n_(e,r))},e2=(e,t,n={})=>!t.languages||!t.languages.length?(Py("i18n.languages were undefined or empty",t.languages),!0):t.hasLoadedNamespace(e,{lng:n.lng,precheck:(r,s)=>{var o;if(((o=n.bindI18n)==null?void 0:o.indexOf("languageChanging"))>-1&&r.services.backendConnector.backend&&r.isLanguageChangingTo&&!s(r.isLanguageChangingTo,e))return!1}}),ui=e=>typeof e=="string",t2=e=>typeof e=="object"&&e!==null,n2=/&(?:amp|#38|lt|#60|gt|#62|apos|#39|quot|#34|nbsp|#160|copy|#169|reg|#174|hellip|#8230|#x2F|#47);/g,r2={"&":"&","&":"&","<":"<","<":"<",">":">",">":">","'":"'","'":"'",""":'"',""":'"'," ":" "," ":" ","©":"©","©":"©","®":"®","®":"®","…":"…","…":"…","/":"/","/":"/"},s2=e=>r2[e],o2=e=>e.replace(n2,s2);let My={bindI18n:"languageChanged",bindI18nStore:"",transEmptyNodeValue:"",transSupportBasicHtmlNodes:!0,transWrapTextNodes:"",transKeepBasicHtmlNodesFor:["br","strong","i","p"],useSuspense:!0,unescape:o2};const a2=(e={})=>{My={...My,...e}},i2=()=>My;let r_;const l2=e=>{r_=e},u2=()=>r_,c2={type:"3rdParty",init(e){a2(e.options.react),l2(e)}},s_=v.createContext();class d2{constructor(){this.usedNamespaces={}}addUsedNamespaces(t){t.forEach(n=>{var r;(r=this.usedNamespaces)[n]??(r[n]=!0)})}getUsedNamespaces(){return Object.keys(this.usedNamespaces)}}const f2=(e,t)=>{const n=v.useRef();return v.useEffect(()=>{n.current=e},[e,t]),n.current},o_=(e,t,n,r)=>e.getFixedT(t,n,r),p2=(e,t,n,r)=>v.useCallback(o_(e,t,n,r),[e,t,n,r]),ze=(e,t={})=>{var S,E,C,k;const{i18n:n}=t,{i18n:r,defaultNS:s}=v.useContext(s_)||{},o=n||r||u2();if(o&&!o.reportNamespaces&&(o.reportNamespaces=new d2),!o){Py("You will need to pass in an i18next instance by using initReactI18next");const T=(N,U)=>ui(U)?U:t2(U)&&ui(U.defaultValue)?U.defaultValue:Array.isArray(N)?N[N.length-1]:N,P=[T,{},!1];return P.t=T,P.i18n={},P.ready=!1,P}(S=o.options.react)!=null&&S.wait&&Py("It seems you are still using the old wait option, you may migrate to the new useSuspense behaviour.");const a={...i2(),...o.options.react,...t},{useSuspense:l,keyPrefix:c}=a;let i=s||((E=o.options)==null?void 0:E.defaultNS);i=ui(i)?[i]:i||["translation"],(k=(C=o.reportNamespaces).addUsedNamespaces)==null||k.call(C,i);const d=(o.isInitialized||o.initializedStoreOnce)&&i.every(T=>e2(T,o,a)),p=p2(o,t.lng||null,a.nsMode==="fallback"?i:i[0],c),f=()=>p,h=()=>o_(o,t.lng||null,a.nsMode==="fallback"?i:i[0],c),[g,m]=v.useState(f);let x=i.join();t.lng&&(x=`${t.lng}${x}`);const b=f2(x),y=v.useRef(!0);v.useEffect(()=>{const{bindI18n:T,bindI18nStore:P}=a;y.current=!0,!d&&!l&&(t.lng?f0(o,t.lng,i,()=>{y.current&&m(h)}):d0(o,i,()=>{y.current&&m(h)})),d&&b&&b!==x&&y.current&&m(h);const N=()=>{y.current&&m(h)};return T&&(o==null||o.on(T,N)),P&&(o==null||o.store.on(P,N)),()=>{y.current=!1,o&&(T==null||T.split(" ").forEach(U=>o.off(U,N))),P&&o&&P.split(" ").forEach(U=>o.store.off(U,N))}},[o,x]),v.useEffect(()=>{y.current&&d&&m(f)},[o,c,d]);const w=[g,o,d];if(w.t=g,w.i18n=o,w.ready=d,d||!d&&!l)return w;throw new Promise(T=>{t.lng?f0(o,t.lng,i,()=>T()):d0(o,i,()=>T())})};function h2({i18n:e,defaultNS:t,children:n}){const r=v.useMemo(()=>({i18n:e,defaultNS:t}),[e,t]);return v.createElement(s_.Provider,{value:r},n)}/** + * @remix-run/router v1.18.0 + * + * Copyright (c) Remix Software Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE.md file in the root directory of this source tree. + * + * @license MIT + */function At(){return At=Object.assign?Object.assign.bind():function(e){for(var t=1;t"u")throw new Error(t)}function Xl(e,t){if(!e){typeof console<"u"&&console.warn(t);try{throw new Error(t)}catch{}}}function m2(){return Math.random().toString(36).substr(2,8)}function h0(e,t){return{usr:e.state,key:e.key,idx:t}}function Xc(e,t,n,r){return n===void 0&&(n=null),At({pathname:typeof e=="string"?e:e.pathname,search:"",hash:""},typeof t=="string"?_a(t):t,{state:n,key:t&&t.key||r||m2()})}function wi(e){let{pathname:t="/",search:n="",hash:r=""}=e;return n&&n!=="?"&&(t+=n.charAt(0)==="?"?n:"?"+n),r&&r!=="#"&&(t+=r.charAt(0)==="#"?r:"#"+r),t}function _a(e){let t={};if(e){let n=e.indexOf("#");n>=0&&(t.hash=e.substr(n),e=e.substr(0,n));let r=e.indexOf("?");r>=0&&(t.search=e.substr(r),e=e.substr(0,r)),e&&(t.pathname=e)}return t}function v2(e,t,n,r){r===void 0&&(r={});let{window:s=document.defaultView,v5Compat:o=!1}=r,a=s.history,l=en.Pop,c=null,i=d();i==null&&(i=0,a.replaceState(At({},a.state,{idx:i}),""));function d(){return(a.state||{idx:null}).idx}function p(){l=en.Pop;let x=d(),b=x==null?null:x-i;i=x,c&&c({action:l,location:m.location,delta:b})}function f(x,b){l=en.Push;let y=Xc(m.location,x,b);i=d()+1;let w=h0(y,i),S=m.createHref(y);try{a.pushState(w,"",S)}catch(E){if(E instanceof DOMException&&E.name==="DataCloneError")throw E;s.location.assign(S)}o&&c&&c({action:l,location:m.location,delta:1})}function h(x,b){l=en.Replace;let y=Xc(m.location,x,b);i=d();let w=h0(y,i),S=m.createHref(y);a.replaceState(w,"",S),o&&c&&c({action:l,location:m.location,delta:0})}function g(x){let b=s.location.origin!=="null"?s.location.origin:s.location.href,y=typeof x=="string"?x:wi(x);return y=y.replace(/ $/,"%20"),Ze(b,"No window.location.(origin|href) available to create URL for href: "+y),new URL(y,b)}let m={get action(){return l},get location(){return e(s,a)},listen(x){if(c)throw new Error("A history only accepts one active listener");return s.addEventListener(p0,p),c=x,()=>{s.removeEventListener(p0,p),c=null}},createHref(x){return t(s,x)},createURL:g,encodeLocation(x){let b=g(x);return{pathname:b.pathname,search:b.search,hash:b.hash}},push:f,replace:h,go(x){return a.go(x)}};return m}var Ct;(function(e){e.data="data",e.deferred="deferred",e.redirect="redirect",e.error="error"})(Ct||(Ct={}));const y2=new Set(["lazy","caseSensitive","path","id","index","children"]);function b2(e){return e.index===!0}function ed(e,t,n,r){return n===void 0&&(n=[]),r===void 0&&(r={}),e.map((s,o)=>{let a=[...n,String(o)],l=typeof s.id=="string"?s.id:a.join("-");if(Ze(s.index!==!0||!s.children,"Cannot specify children on an index route"),Ze(!r[l],'Found a route id collision on id "'+l+`". Route id's must be globally unique within Data Router usages`),b2(s)){let c=At({},s,t(s),{id:l});return r[l]=c,c}else{let c=At({},s,t(s),{id:l,children:void 0});return r[l]=c,s.children&&(c.children=ed(s.children,t,a,r)),c}})}function Ua(e,t,n){return n===void 0&&(n="/"),cp(e,t,n,!1)}function cp(e,t,n,r){let s=typeof t=="string"?_a(t):t,o=du(s.pathname||"/",n);if(o==null)return null;let a=a_(e);w2(a);let l=null;for(let c=0;l==null&&c{let c={relativePath:l===void 0?o.path||"":l,caseSensitive:o.caseSensitive===!0,childrenIndex:a,route:o};c.relativePath.startsWith("/")&&(Ze(c.relativePath.startsWith(r),'Absolute route path "'+c.relativePath+'" nested under path '+('"'+r+'" is not valid. An absolute child route path ')+"must start with the combined path of all its parent routes."),c.relativePath=c.relativePath.slice(r.length));let i=uo([r,c.relativePath]),d=n.concat(c);o.children&&o.children.length>0&&(Ze(o.index!==!0,"Index routes must not have child routes. Please remove "+('all child routes from route path "'+i+'".')),a_(o.children,t,d,i)),!(o.path==null&&!o.index)&&t.push({path:i,score:j2(i,o.index),routesMeta:d})};return e.forEach((o,a)=>{var l;if(o.path===""||!((l=o.path)!=null&&l.includes("?")))s(o,a);else for(let c of i_(o.path))s(o,a,c)}),t}function i_(e){let t=e.split("/");if(t.length===0)return[];let[n,...r]=t,s=n.endsWith("?"),o=n.replace(/\?$/,"");if(r.length===0)return s?[o,""]:[o];let a=i_(r.join("/")),l=[];return l.push(...a.map(c=>c===""?o:[o,c].join("/"))),s&&l.push(...a),l.map(c=>e.startsWith("/")&&c===""?"/":c)}function w2(e){e.sort((t,n)=>t.score!==n.score?n.score-t.score:R2(t.routesMeta.map(r=>r.childrenIndex),n.routesMeta.map(r=>r.childrenIndex)))}const S2=/^:[\w-]+$/,C2=3,E2=2,T2=1,k2=10,_2=-2,g0=e=>e==="*";function j2(e,t){let n=e.split("/"),r=n.length;return n.some(g0)&&(r+=_2),t&&(r+=E2),n.filter(s=>!g0(s)).reduce((s,o)=>s+(S2.test(o)?C2:o===""?T2:k2),r)}function R2(e,t){return e.length===t.length&&e.slice(0,-1).every((r,s)=>r===t[s])?e[e.length-1]-t[t.length-1]:0}function P2(e,t,n){n===void 0&&(n=!1);let{routesMeta:r}=e,s={},o="/",a=[];for(let l=0;l{let{paramName:f,isOptional:h}=d;if(f==="*"){let m=l[p]||"";a=o.slice(0,o.length-m.length).replace(/(.)\/+$/,"$1")}const g=l[p];return h&&!g?i[f]=void 0:i[f]=(g||"").replace(/%2F/g,"/"),i},{}),pathname:o,pathnameBase:a,pattern:e}}function M2(e,t,n){t===void 0&&(t=!1),n===void 0&&(n=!0),Xl(e==="*"||!e.endsWith("*")||e.endsWith("/*"),'Route path "'+e+'" will be treated as if it were '+('"'+e.replace(/\*$/,"/*")+'" because the `*` character must ')+"always follow a `/` in the pattern. To get rid of this warning, "+('please change the route path to "'+e.replace(/\*$/,"/*")+'".'));let r=[],s="^"+e.replace(/\/*\*?$/,"").replace(/^\/*/,"/").replace(/[\\.*+^${}|()[\]]/g,"\\$&").replace(/\/:([\w-]+)(\?)?/g,(a,l,c)=>(r.push({paramName:l,isOptional:c!=null}),c?"/?([^\\/]+)?":"/([^\\/]+)"));return e.endsWith("*")?(r.push({paramName:"*"}),s+=e==="*"||e==="/*"?"(.*)$":"(?:\\/(.+)|\\/*)$"):n?s+="\\/*$":e!==""&&e!=="/"&&(s+="(?:(?=\\/|$))"),[new RegExp(s,t?void 0:"i"),r]}function O2(e){try{return e.split("/").map(t=>decodeURIComponent(t).replace(/\//g,"%2F")).join("/")}catch(t){return Xl(!1,'The URL path "'+e+'" could not be decoded because it is is a malformed URL segment. This is probably due to a bad percent '+("encoding ("+t+").")),e}}function du(e,t){if(t==="/")return e;if(!e.toLowerCase().startsWith(t.toLowerCase()))return null;let n=t.endsWith("/")?t.length-1:t.length,r=e.charAt(n);return r&&r!=="/"?null:e.slice(n)||"/"}function N2(e,t){t===void 0&&(t="/");let{pathname:n,search:r="",hash:s=""}=typeof e=="string"?_a(e):e;return{pathname:n?n.startsWith("/")?n:I2(n,t):t,search:A2(r),hash:F2(s)}}function I2(e,t){let n=t.replace(/\/+$/,"").split("/");return e.split("/").forEach(s=>{s===".."?n.length>1&&n.pop():s!=="."&&n.push(s)}),n.length>1?n.join("/"):"/"}function Om(e,t,n,r){return"Cannot include a '"+e+"' character in a manually specified "+("`to."+t+"` field ["+JSON.stringify(r)+"]. Please separate it out to the ")+("`to."+n+"` field. Alternatively you may provide the full path as ")+'a string in and the router will parse it for you.'}function l_(e){return e.filter((t,n)=>n===0||t.route.path&&t.route.path.length>0)}function Jh(e,t){let n=l_(e);return t?n.map((r,s)=>s===n.length-1?r.pathname:r.pathnameBase):n.map(r=>r.pathnameBase)}function Qh(e,t,n,r){r===void 0&&(r=!1);let s;typeof e=="string"?s=_a(e):(s=At({},e),Ze(!s.pathname||!s.pathname.includes("?"),Om("?","pathname","search",s)),Ze(!s.pathname||!s.pathname.includes("#"),Om("#","pathname","hash",s)),Ze(!s.search||!s.search.includes("#"),Om("#","search","hash",s)));let o=e===""||s.pathname==="",a=o?"/":s.pathname,l;if(a==null)l=n;else{let p=t.length-1;if(!r&&a.startsWith("..")){let f=a.split("/");for(;f[0]==="..";)f.shift(),p-=1;s.pathname=f.join("/")}l=p>=0?t[p]:"/"}let c=N2(s,l),i=a&&a!=="/"&&a.endsWith("/"),d=(o||a===".")&&n.endsWith("/");return!c.pathname.endsWith("/")&&(i||d)&&(c.pathname+="/"),c}const uo=e=>e.join("/").replace(/\/\/+/g,"/"),D2=e=>e.replace(/\/+$/,"").replace(/^\/*/,"/"),A2=e=>!e||e==="?"?"":e.startsWith("?")?e:"?"+e,F2=e=>!e||e==="#"?"":e.startsWith("#")?e:"#"+e;class _x{constructor(t,n,r,s){s===void 0&&(s=!1),this.status=t,this.statusText=n||"",this.internal=s,r instanceof Error?(this.data=r.toString(),this.error=r):this.data=r}}function Zh(e){return e!=null&&typeof e.status=="number"&&typeof e.statusText=="string"&&typeof e.internal=="boolean"&&"data"in e}const u_=["post","put","patch","delete"],L2=new Set(u_),$2=["get",...u_],B2=new Set($2),z2=new Set([301,302,303,307,308]),U2=new Set([307,308]),Nm={state:"idle",location:void 0,formMethod:void 0,formAction:void 0,formEncType:void 0,formData:void 0,json:void 0,text:void 0},V2={state:"idle",data:void 0,formMethod:void 0,formAction:void 0,formEncType:void 0,formData:void 0,json:void 0,text:void 0},Ku={state:"unblocked",proceed:void 0,reset:void 0,location:void 0},jx=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i,H2=e=>({hasErrorBoundary:!!e.hasErrorBoundary}),c_="remix-router-transitions";function K2(e){const t=e.window?e.window:typeof window<"u"?window:void 0,n=typeof t<"u"&&typeof t.document<"u"&&typeof t.document.createElement<"u",r=!n;Ze(e.routes.length>0,"You must provide a non-empty routes array to createRouter");let s;if(e.mapRouteProperties)s=e.mapRouteProperties;else if(e.detectErrorBoundary){let M=e.detectErrorBoundary;s=O=>({hasErrorBoundary:M(O)})}else s=H2;let o={},a=ed(e.routes,s,void 0,o),l,c=e.basename||"/",i=e.unstable_dataStrategy||Q2,d=e.unstable_patchRoutesOnMiss,p=At({v7_fetcherPersist:!1,v7_normalizeFormMethod:!1,v7_partialHydration:!1,v7_prependBasename:!1,v7_relativeSplatPath:!1,v7_skipActionErrorRevalidation:!1},e.future),f=null,h=new Set,g=null,m=null,x=null,b=e.hydrationData!=null,y=Ua(a,e.history.location,c),w=null;if(y==null&&!d){let M=Bn(404,{pathname:e.history.location.pathname}),{matches:O,route:L}=k0(a);y=O,w={[L.id]:M}}y&&d&&!e.hydrationData&&rm(y,a,e.history.location.pathname).active&&(y=null);let S;if(!y)S=!1,y=[];else if(y.some(M=>M.route.lazy))S=!1;else if(!y.some(M=>M.route.loader))S=!0;else if(p.v7_partialHydration){let M=e.hydrationData?e.hydrationData.loaderData:null,O=e.hydrationData?e.hydrationData.errors:null,L=H=>H.route.loader?typeof H.route.loader=="function"&&H.route.loader.hydrate===!0?!1:M&&M[H.route.id]!==void 0||O&&O[H.route.id]!==void 0:!0;if(O){let H=y.findIndex(ye=>O[ye.route.id]!==void 0);S=y.slice(0,H+1).every(L)}else S=y.every(L)}else S=e.hydrationData!=null;let E,C={historyAction:e.history.action,location:e.history.location,matches:y,initialized:S,navigation:Nm,restoreScrollPosition:e.hydrationData!=null?!1:null,preventScrollReset:!1,revalidation:"idle",loaderData:e.hydrationData&&e.hydrationData.loaderData||{},actionData:e.hydrationData&&e.hydrationData.actionData||null,errors:e.hydrationData&&e.hydrationData.errors||w,fetchers:new Map,blockers:new Map},k=en.Pop,T=!1,P,N=!1,U=new Map,I=null,Z=!1,V=!1,Q=[],ee=[],W=new Map,F=0,A=-1,Y=new Map,de=new Set,z=new Map,se=new Map,ne=new Set,ie=new Map,oe=new Map,J=new Map,Ce=!1;function Pe(){if(f=e.history.listen(M=>{let{action:O,location:L,delta:H}=M;if(Ce){Ce=!1;return}Xl(oe.size===0||H!=null,"You are trying to use a blocker on a POP navigation to a location that was not created by @remix-run/router. This will fail silently in production. This can happen if you are navigating outside the router via `window.history.pushState`/`window.location.hash` instead of using router navigation APIs. This can also happen if you are using createHashRouter and the user manually changes the URL.");let ye=Ro({currentLocation:C.location,nextLocation:L,historyAction:O});if(ye&&H!=null){Ce=!0,e.history.go(H*-1),ms(ye,{state:"blocked",location:L,proceed(){ms(ye,{state:"proceeding",proceed:void 0,reset:void 0,location:L}),e.history.go(H)},reset(){let _e=new Map(C.blockers);_e.set(ye,Ku),me({blockers:_e})}});return}return Wt(O,L)}),n){uL(t,U);let M=()=>cL(t,U);t.addEventListener("pagehide",M),I=()=>t.removeEventListener("pagehide",M)}return C.initialized||Wt(en.Pop,C.location,{initialHydration:!0}),E}function Le(){f&&f(),I&&I(),h.clear(),P&&P.abort(),C.fetchers.forEach((M,O)=>gs(O)),C.blockers.forEach((M,O)=>_n(O))}function Me(M){return h.add(M),()=>h.delete(M)}function me(M,O){O===void 0&&(O={}),C=At({},C,M);let L=[],H=[];p.v7_fetcherPersist&&C.fetchers.forEach((ye,_e)=>{ye.state==="idle"&&(ne.has(_e)?H.push(_e):L.push(_e))}),[...h].forEach(ye=>ye(C,{deletedFetchers:H,unstable_viewTransitionOpts:O.viewTransitionOpts,unstable_flushSync:O.flushSync===!0})),p.v7_fetcherPersist&&(L.forEach(ye=>C.fetchers.delete(ye)),H.forEach(ye=>gs(ye)))}function rt(M,O,L){var H,ye;let{flushSync:_e}=L===void 0?{}:L,$e=C.actionData!=null&&C.navigation.formMethod!=null&&Jr(C.navigation.formMethod)&&C.navigation.state==="loading"&&((H=M.state)==null?void 0:H._isRedirect)!==!0,fe;O.actionData?Object.keys(O.actionData).length>0?fe=O.actionData:fe=null:$e?fe=C.actionData:fe=null;let qe=O.loaderData?E0(C.loaderData,O.loaderData,O.matches||[],O.errors):C.loaderData,Re=C.blockers;Re.size>0&&(Re=new Map(Re),Re.forEach((mt,bt)=>Re.set(bt,Ku)));let Oe=T===!0||C.navigation.formMethod!=null&&Jr(C.navigation.formMethod)&&((ye=M.state)==null?void 0:ye._isRedirect)!==!0;l&&(a=l,l=void 0),Z||k===en.Pop||(k===en.Push?e.history.push(M,M.state):k===en.Replace&&e.history.replace(M,M.state));let yt;if(k===en.Pop){let mt=U.get(C.location.pathname);mt&&mt.has(M.pathname)?yt={currentLocation:C.location,nextLocation:M}:U.has(M.pathname)&&(yt={currentLocation:M,nextLocation:C.location})}else if(N){let mt=U.get(C.location.pathname);mt?mt.add(M.pathname):(mt=new Set([M.pathname]),U.set(C.location.pathname,mt)),yt={currentLocation:C.location,nextLocation:M}}me(At({},O,{actionData:fe,loaderData:qe,historyAction:k,location:M,initialized:!0,navigation:Nm,revalidation:"idle",restoreScrollPosition:Kw(M,O.matches||C.matches),preventScrollReset:Oe,blockers:Re}),{viewTransitionOpts:yt,flushSync:_e===!0}),k=en.Pop,T=!1,N=!1,Z=!1,V=!1,Q=[],ee=[]}async function It(M,O){if(typeof M=="number"){e.history.go(M);return}let L=Oy(C.location,C.matches,c,p.v7_prependBasename,M,p.v7_relativeSplatPath,O==null?void 0:O.fromRouteId,O==null?void 0:O.relative),{path:H,submission:ye,error:_e}=v0(p.v7_normalizeFormMethod,!1,L,O),$e=C.location,fe=Xc(C.location,H,O&&O.state);fe=At({},fe,e.history.encodeLocation(fe));let qe=O&&O.replace!=null?O.replace:void 0,Re=en.Push;qe===!0?Re=en.Replace:qe===!1||ye!=null&&Jr(ye.formMethod)&&ye.formAction===C.location.pathname+C.location.search&&(Re=en.Replace);let Oe=O&&"preventScrollReset"in O?O.preventScrollReset===!0:void 0,yt=(O&&O.unstable_flushSync)===!0,mt=Ro({currentLocation:$e,nextLocation:fe,historyAction:Re});if(mt){ms(mt,{state:"blocked",location:fe,proceed(){ms(mt,{state:"proceeding",proceed:void 0,reset:void 0,location:fe}),It(M,O)},reset(){let bt=new Map(C.blockers);bt.set(mt,Ku),me({blockers:bt})}});return}return await Wt(Re,fe,{submission:ye,pendingError:_e,preventScrollReset:Oe,replace:O&&O.replace,enableViewTransition:O&&O.unstable_viewTransition,flushSync:yt})}function Zt(){if(hn(),me({revalidation:"loading"}),C.navigation.state!=="submitting"){if(C.navigation.state==="idle"){Wt(C.historyAction,C.location,{startUninterruptedRevalidation:!0});return}Wt(k||C.historyAction,C.navigation.location,{overrideNavigation:C.navigation})}}async function Wt(M,O,L){P&&P.abort(),P=null,k=M,Z=(L&&L.startUninterruptedRevalidation)===!0,UI(C.location,C.matches),T=(L&&L.preventScrollReset)===!0,N=(L&&L.enableViewTransition)===!0;let H=l||a,ye=L&&L.overrideNavigation,_e=Ua(H,O,c),$e=(L&&L.flushSync)===!0,fe=rm(_e,H,O.pathname);if(fe.active&&fe.matches&&(_e=fe.matches),!_e){let{error:pt,notFoundMatches:bn,route:Yt}=Iu(O.pathname);rt(O,{matches:bn,loaderData:{},errors:{[Yt.id]:pt}},{flushSync:$e});return}if(C.initialized&&!V&&nL(C.location,O)&&!(L&&L.submission&&Jr(L.submission.formMethod))){rt(O,{matches:_e},{flushSync:$e});return}P=new AbortController;let qe=Hi(e.history,O,P.signal,L&&L.submission),Re;if(L&&L.pendingError)Re=[gl(_e).route.id,{type:Ct.error,error:L.pendingError}];else if(L&&L.submission&&Jr(L.submission.formMethod)){let pt=await an(qe,O,L.submission,_e,fe.active,{replace:L.replace,flushSync:$e});if(pt.shortCircuited)return;if(pt.pendingActionResult){let[bn,Yt]=pt.pendingActionResult;if(fr(Yt)&&Zh(Yt.error)&&Yt.error.status===404){P=null,rt(O,{matches:pt.matches,loaderData:{},errors:{[bn]:Yt.error}});return}}_e=pt.matches||_e,Re=pt.pendingActionResult,ye=Im(O,L.submission),$e=!1,fe.active=!1,qe=Hi(e.history,qe.url,qe.signal)}let{shortCircuited:Oe,matches:yt,loaderData:mt,errors:bt}=await j(qe,O,_e,fe.active,ye,L&&L.submission,L&&L.fetcherSubmission,L&&L.replace,L&&L.initialHydration===!0,$e,Re);Oe||(P=null,rt(O,At({matches:yt||_e},T0(Re),{loaderData:mt,errors:bt})))}async function an(M,O,L,H,ye,_e){_e===void 0&&(_e={}),hn();let $e=iL(O,L);if(me({navigation:$e},{flushSync:_e.flushSync===!0}),ye){let Re=await sf(H,O.pathname,M.signal);if(Re.type==="aborted")return{shortCircuited:!0};if(Re.type==="error"){let{boundaryId:Oe,error:yt}=$i(O.pathname,Re);return{matches:Re.partialMatches,pendingActionResult:[Oe,{type:Ct.error,error:yt}]}}else if(Re.matches)H=Re.matches;else{let{notFoundMatches:Oe,error:yt,route:mt}=Iu(O.pathname);return{matches:Oe,pendingActionResult:[mt.id,{type:Ct.error,error:yt}]}}}let fe,qe=cc(H,O);if(!qe.route.action&&!qe.route.lazy)fe={type:Ct.error,error:Bn(405,{method:M.method,pathname:O.pathname,routeId:qe.route.id})};else if(fe=(await et("action",M,[qe],H))[0],M.signal.aborted)return{shortCircuited:!0};if(Wa(fe)){let Re;return _e&&_e.replace!=null?Re=_e.replace:Re=w0(fe.response.headers.get("Location"),new URL(M.url),c)===C.location.pathname+C.location.search,await Ee(M,fe,{submission:L,replace:Re}),{shortCircuited:!0}}if(qa(fe))throw Bn(400,{type:"defer-action"});if(fr(fe)){let Re=gl(H,qe.route.id);return(_e&&_e.replace)!==!0&&(k=en.Push),{matches:H,pendingActionResult:[Re.route.id,fe]}}return{matches:H,pendingActionResult:[qe.route.id,fe]}}async function j(M,O,L,H,ye,_e,$e,fe,qe,Re,Oe){let yt=ye||Im(O,_e),mt=_e||$e||R0(yt),bt=!Z&&(!p.v7_partialHydration||!qe);if(H){if(bt){let Vt=D(Oe);me(At({navigation:yt},Vt!==void 0?{actionData:Vt}:{}),{flushSync:Re})}let Ge=await sf(L,O.pathname,M.signal);if(Ge.type==="aborted")return{shortCircuited:!0};if(Ge.type==="error"){let{boundaryId:Vt,error:ar}=$i(O.pathname,Ge);return{matches:Ge.partialMatches,loaderData:{},errors:{[Vt]:ar}}}else if(Ge.matches)L=Ge.matches;else{let{error:Vt,notFoundMatches:ar,route:Mt}=Iu(O.pathname);return{matches:ar,loaderData:{},errors:{[Mt.id]:Vt}}}}let pt=l||a,[bn,Yt]=y0(e.history,C,L,mt,O,p.v7_partialHydration&&qe===!0,p.v7_skipActionErrorRevalidation,V,Q,ee,ne,z,de,pt,c,Oe);if(vs(Ge=>!(L&&L.some(Vt=>Vt.route.id===Ge))||bn&&bn.some(Vt=>Vt.route.id===Ge)),A=++F,bn.length===0&&Yt.length===0){let Ge=Ue();return rt(O,At({matches:L,loaderData:{},errors:Oe&&fr(Oe[1])?{[Oe[0]]:Oe[1].error}:null},T0(Oe),Ge?{fetchers:new Map(C.fetchers)}:{}),{flushSync:Re}),{shortCircuited:!0}}if(bt){let Ge={};if(!H){Ge.navigation=yt;let Vt=D(Oe);Vt!==void 0&&(Ge.actionData=Vt)}Yt.length>0&&(Ge.fetchers=B(Yt)),me(Ge,{flushSync:Re})}Yt.forEach(Ge=>{W.has(Ge.key)&&Fn(Ge.key),Ge.controller&&W.set(Ge.key,Ge.controller)});let Au=()=>Yt.forEach(Ge=>Fn(Ge.key));P&&P.signal.addEventListener("abort",Au);let{loaderResults:Po,fetcherResults:Bi}=await kt(C.matches,L,bn,Yt,M);if(M.signal.aborted)return{shortCircuited:!0};P&&P.signal.removeEventListener("abort",Au),Yt.forEach(Ge=>W.delete(Ge.key));let zi=_0([...Po,...Bi]);if(zi){if(zi.idx>=bn.length){let Ge=Yt[zi.idx-bn.length].key;de.add(Ge)}return await Ee(M,zi.result,{replace:fe}),{shortCircuited:!0}}let{loaderData:Ui,errors:ys}=C0(C,L,bn,Po,Oe,Yt,Bi,ie);ie.forEach((Ge,Vt)=>{Ge.subscribe(ar=>{(ar||Ge.done)&&ie.delete(Vt)})}),p.v7_partialHydration&&qe&&C.errors&&Object.entries(C.errors).filter(Ge=>{let[Vt]=Ge;return!bn.some(ar=>ar.route.id===Vt)}).forEach(Ge=>{let[Vt,ar]=Ge;ys=Object.assign(ys||{},{[Vt]:ar})});let of=Ue(),af=St(A),lf=of||af||Yt.length>0;return At({matches:L,loaderData:Ui,errors:ys},lf?{fetchers:new Map(C.fetchers)}:{})}function D(M){if(M&&!fr(M[1]))return{[M[0]]:M[1].data};if(C.actionData)return Object.keys(C.actionData).length===0?null:C.actionData}function B(M){return M.forEach(O=>{let L=C.fetchers.get(O.key),H=qu(void 0,L?L.data:void 0);C.fetchers.set(O.key,H)}),new Map(C.fetchers)}function pe(M,O,L,H){if(r)throw new Error("router.fetch() was called during the server render, but it shouldn't be. You are likely calling a useFetcher() method in the body of your component. Try moving it to a useEffect or a callback.");W.has(M)&&Fn(M);let ye=(H&&H.unstable_flushSync)===!0,_e=l||a,$e=Oy(C.location,C.matches,c,p.v7_prependBasename,L,p.v7_relativeSplatPath,O,H==null?void 0:H.relative),fe=Ua(_e,$e,c),qe=rm(fe,_e,$e);if(qe.active&&qe.matches&&(fe=qe.matches),!fe){gn(M,O,Bn(404,{pathname:$e}),{flushSync:ye});return}let{path:Re,submission:Oe,error:yt}=v0(p.v7_normalizeFormMethod,!0,$e,H);if(yt){gn(M,O,yt,{flushSync:ye});return}let mt=cc(fe,Re);if(T=(H&&H.preventScrollReset)===!0,Oe&&Jr(Oe.formMethod)){le(M,O,Re,mt,fe,qe.active,ye,Oe);return}z.set(M,{routeId:O,path:Re}),ae(M,O,Re,mt,fe,qe.active,ye,Oe)}async function le(M,O,L,H,ye,_e,$e,fe){hn(),z.delete(M);function qe(Mt){if(!Mt.route.action&&!Mt.route.lazy){let Ks=Bn(405,{method:fe.formMethod,pathname:L,routeId:O});return gn(M,O,Ks,{flushSync:$e}),!0}return!1}if(!_e&&qe(H))return;let Re=C.fetchers.get(M);yn(M,lL(fe,Re),{flushSync:$e});let Oe=new AbortController,yt=Hi(e.history,L,Oe.signal,fe);if(_e){let Mt=await sf(ye,L,yt.signal);if(Mt.type==="aborted")return;if(Mt.type==="error"){let{error:Ks}=$i(L,Mt);gn(M,O,Ks,{flushSync:$e});return}else if(Mt.matches){if(ye=Mt.matches,H=cc(ye,L),qe(H))return}else{gn(M,O,Bn(404,{pathname:L}),{flushSync:$e});return}}W.set(M,Oe);let mt=F,pt=(await et("action",yt,[H],ye))[0];if(yt.signal.aborted){W.get(M)===Oe&&W.delete(M);return}if(p.v7_fetcherPersist&&ne.has(M)){if(Wa(pt)||fr(pt)){yn(M,Fo(void 0));return}}else{if(Wa(pt))if(W.delete(M),A>mt){yn(M,Fo(void 0));return}else return de.add(M),yn(M,qu(fe)),Ee(yt,pt,{fetcherSubmission:fe});if(fr(pt)){gn(M,O,pt.error);return}}if(qa(pt))throw Bn(400,{type:"defer-action"});let bn=C.navigation.location||C.location,Yt=Hi(e.history,bn,Oe.signal),Au=l||a,Po=C.navigation.state!=="idle"?Ua(Au,C.navigation.location,c):C.matches;Ze(Po,"Didn't find any matches after fetcher action");let Bi=++F;Y.set(M,Bi);let zi=qu(fe,pt.data);C.fetchers.set(M,zi);let[Ui,ys]=y0(e.history,C,Po,fe,bn,!1,p.v7_skipActionErrorRevalidation,V,Q,ee,ne,z,de,Au,c,[H.route.id,pt]);ys.filter(Mt=>Mt.key!==M).forEach(Mt=>{let Ks=Mt.key,qw=C.fetchers.get(Ks),KI=qu(void 0,qw?qw.data:void 0);C.fetchers.set(Ks,KI),W.has(Ks)&&Fn(Ks),Mt.controller&&W.set(Ks,Mt.controller)}),me({fetchers:new Map(C.fetchers)});let of=()=>ys.forEach(Mt=>Fn(Mt.key));Oe.signal.addEventListener("abort",of);let{loaderResults:af,fetcherResults:lf}=await kt(C.matches,Po,Ui,ys,Yt);if(Oe.signal.aborted)return;Oe.signal.removeEventListener("abort",of),Y.delete(M),W.delete(M),ys.forEach(Mt=>W.delete(Mt.key));let Ge=_0([...af,...lf]);if(Ge){if(Ge.idx>=Ui.length){let Mt=ys[Ge.idx-Ui.length].key;de.add(Mt)}return Ee(Yt,Ge.result)}let{loaderData:Vt,errors:ar}=C0(C,C.matches,Ui,af,void 0,ys,lf,ie);if(C.fetchers.has(M)){let Mt=Fo(pt.data);C.fetchers.set(M,Mt)}St(Bi),C.navigation.state==="loading"&&Bi>A?(Ze(k,"Expected pending action"),P&&P.abort(),rt(C.navigation.location,{matches:Po,loaderData:Vt,errors:ar,fetchers:new Map(C.fetchers)})):(me({errors:ar,loaderData:E0(C.loaderData,Vt,Po,ar),fetchers:new Map(C.fetchers)}),V=!1)}async function ae(M,O,L,H,ye,_e,$e,fe){let qe=C.fetchers.get(M);yn(M,qu(fe,qe?qe.data:void 0),{flushSync:$e});let Re=new AbortController,Oe=Hi(e.history,L,Re.signal);if(_e){let pt=await sf(ye,L,Oe.signal);if(pt.type==="aborted")return;if(pt.type==="error"){let{error:bn}=$i(L,pt);gn(M,O,bn,{flushSync:$e});return}else if(pt.matches)ye=pt.matches,H=cc(ye,L);else{gn(M,O,Bn(404,{pathname:L}),{flushSync:$e});return}}W.set(M,Re);let yt=F,bt=(await et("loader",Oe,[H],ye))[0];if(qa(bt)&&(bt=await g_(bt,Oe.signal,!0)||bt),W.get(M)===Re&&W.delete(M),!Oe.signal.aborted){if(ne.has(M)){yn(M,Fo(void 0));return}if(Wa(bt))if(A>yt){yn(M,Fo(void 0));return}else{de.add(M),await Ee(Oe,bt);return}if(fr(bt)){gn(M,O,bt.error);return}Ze(!qa(bt),"Unhandled fetcher deferred data"),yn(M,Fo(bt.data))}}async function Ee(M,O,L){let{submission:H,fetcherSubmission:ye,replace:_e}=L===void 0?{}:L;O.response.headers.has("X-Remix-Revalidate")&&(V=!0);let $e=O.response.headers.get("Location");Ze($e,"Expected a Location header on the redirect Response"),$e=w0($e,new URL(M.url),c);let fe=Xc(C.location,$e,{_isRedirect:!0});if(n){let bt=!1;if(O.response.headers.has("X-Remix-Reload-Document"))bt=!0;else if(jx.test($e)){const pt=e.history.createURL($e);bt=pt.origin!==t.location.origin||du(pt.pathname,c)==null}if(bt){_e?t.location.replace($e):t.location.assign($e);return}}P=null;let qe=_e===!0?en.Replace:en.Push,{formMethod:Re,formAction:Oe,formEncType:yt}=C.navigation;!H&&!ye&&Re&&Oe&&yt&&(H=R0(C.navigation));let mt=H||ye;if(U2.has(O.response.status)&&mt&&Jr(mt.formMethod))await Wt(qe,fe,{submission:At({},mt,{formAction:$e}),preventScrollReset:T});else{let bt=Im(fe,H);await Wt(qe,fe,{overrideNavigation:bt,fetcherSubmission:ye,preventScrollReset:T})}}async function et(M,O,L,H){try{let ye=await Z2(i,M,O,L,H,o,s);return await Promise.all(ye.map((_e,$e)=>{if(sL(_e)){let fe=_e.result;return{type:Ct.redirect,response:eL(fe,O,L[$e].route.id,H,c,p.v7_relativeSplatPath)}}return X2(_e)}))}catch(ye){return L.map(()=>({type:Ct.error,error:ye}))}}async function kt(M,O,L,H,ye){let[_e,...$e]=await Promise.all([L.length?et("loader",ye,L,O):[],...H.map(fe=>{if(fe.matches&&fe.match&&fe.controller){let qe=Hi(e.history,fe.path,fe.controller.signal);return et("loader",qe,[fe.match],fe.matches).then(Re=>Re[0])}else return Promise.resolve({type:Ct.error,error:Bn(404,{pathname:fe.path})})})]);return await Promise.all([j0(M,L,_e,_e.map(()=>ye.signal),!1,C.loaderData),j0(M,H.map(fe=>fe.match),$e,H.map(fe=>fe.controller?fe.controller.signal:null),!0)]),{loaderResults:_e,fetcherResults:$e}}function hn(){V=!0,Q.push(...vs()),z.forEach((M,O)=>{W.has(O)&&(ee.push(O),Fn(O))})}function yn(M,O,L){L===void 0&&(L={}),C.fetchers.set(M,O),me({fetchers:new Map(C.fetchers)},{flushSync:(L&&L.flushSync)===!0})}function gn(M,O,L,H){H===void 0&&(H={});let ye=gl(C.matches,O);gs(M),me({errors:{[ye.route.id]:L},fetchers:new Map(C.fetchers)},{flushSync:(H&&H.flushSync)===!0})}function jo(M){return p.v7_fetcherPersist&&(se.set(M,(se.get(M)||0)+1),ne.has(M)&&ne.delete(M)),C.fetchers.get(M)||V2}function gs(M){let O=C.fetchers.get(M);W.has(M)&&!(O&&O.state==="loading"&&Y.has(M))&&Fn(M),z.delete(M),Y.delete(M),de.delete(M),ne.delete(M),C.fetchers.delete(M)}function Aa(M){if(p.v7_fetcherPersist){let O=(se.get(M)||0)-1;O<=0?(se.delete(M),ne.add(M)):se.set(M,O)}else gs(M);me({fetchers:new Map(C.fetchers)})}function Fn(M){let O=W.get(M);Ze(O,"Expected fetch controller: "+M),O.abort(),W.delete(M)}function ue(M){for(let O of M){let L=jo(O),H=Fo(L.data);C.fetchers.set(O,H)}}function Ue(){let M=[],O=!1;for(let L of de){let H=C.fetchers.get(L);Ze(H,"Expected fetcher: "+L),H.state==="loading"&&(de.delete(L),M.push(L),O=!0)}return ue(M),O}function St(M){let O=[];for(let[L,H]of Y)if(H0}function dt(M,O){let L=C.blockers.get(M)||Ku;return oe.get(M)!==O&&oe.set(M,O),L}function _n(M){C.blockers.delete(M),oe.delete(M)}function ms(M,O){let L=C.blockers.get(M)||Ku;Ze(L.state==="unblocked"&&O.state==="blocked"||L.state==="blocked"&&O.state==="blocked"||L.state==="blocked"&&O.state==="proceeding"||L.state==="blocked"&&O.state==="unblocked"||L.state==="proceeding"&&O.state==="unblocked","Invalid blocker state transition: "+L.state+" -> "+O.state);let H=new Map(C.blockers);H.set(M,O),me({blockers:H})}function Ro(M){let{currentLocation:O,nextLocation:L,historyAction:H}=M;if(oe.size===0)return;oe.size>1&&Xl(!1,"A router only supports one blocker at a time");let ye=Array.from(oe.entries()),[_e,$e]=ye[ye.length-1],fe=C.blockers.get(_e);if(!(fe&&fe.state==="proceeding")&&$e({currentLocation:O,nextLocation:L,historyAction:H}))return _e}function Iu(M){let O=Bn(404,{pathname:M}),L=l||a,{matches:H,route:ye}=k0(L);return vs(),{notFoundMatches:H,route:ye,error:O}}function $i(M,O){return{boundaryId:gl(O.partialMatches).route.id,error:Bn(400,{type:"route-discovery",pathname:M,message:O.error!=null&&"message"in O.error?O.error:String(O.error)})}}function vs(M){let O=[];return ie.forEach((L,H)=>{(!M||M(H))&&(L.cancel(),O.push(H),ie.delete(H))}),O}function Du(M,O,L){if(g=M,x=O,m=L||null,!b&&C.navigation===Nm){b=!0;let H=Kw(C.location,C.matches);H!=null&&me({restoreScrollPosition:H})}return()=>{g=null,x=null,m=null}}function Hw(M,O){return m&&m(M,O.map(H=>x2(H,C.loaderData)))||M.key}function UI(M,O){if(g&&x){let L=Hw(M,O);g[L]=x()}}function Kw(M,O){if(g){let L=Hw(M,O),H=g[L];if(typeof H=="number")return H}return null}function rm(M,O,L){if(d)if(M){let H=M[M.length-1].route;if(H.path&&(H.path==="*"||H.path.endsWith("/*")))return{active:!0,matches:cp(O,L,c,!0)}}else return{active:!0,matches:cp(O,L,c,!0)||[]};return{active:!1,matches:null}}async function sf(M,O,L){let H=M,ye=H.length>0?H[H.length-1].route:null;for(;;){let _e=l==null,$e=l||a;try{await J2(d,O,H,$e,o,s,J,L)}catch(Oe){return{type:"error",error:Oe,partialMatches:H}}finally{_e&&(a=[...a])}if(L.aborted)return{type:"aborted"};let fe=Ua($e,O,c),qe=!1;if(fe){let Oe=fe[fe.length-1].route;if(Oe.index)return{type:"success",matches:fe};if(Oe.path&&Oe.path.length>0)if(Oe.path==="*")qe=!0;else return{type:"success",matches:fe}}let Re=cp($e,O,c,!0);if(!Re||H.map(Oe=>Oe.route.id).join("-")===Re.map(Oe=>Oe.route.id).join("-"))return{type:"success",matches:qe?fe:null};if(H=Re,ye=H[H.length-1].route,ye.path==="*")return{type:"success",matches:H}}}function VI(M){o={},l=ed(M,s,void 0,o)}function HI(M,O){let L=l==null;f_(M,O,l||a,o,s),L&&(a=[...a],me({}))}return E={get basename(){return c},get future(){return p},get state(){return C},get routes(){return a},get window(){return t},initialize:Pe,subscribe:Me,enableScrollRestoration:Du,navigate:It,fetch:pe,revalidate:Zt,createHref:M=>e.history.createHref(M),encodeLocation:M=>e.history.encodeLocation(M),getFetcher:jo,deleteFetcher:Aa,dispose:Le,getBlocker:dt,deleteBlocker:_n,patchRoutes:HI,_internalFetchControllers:W,_internalActiveDeferreds:ie,_internalSetRoutes:VI},E}function q2(e){return e!=null&&("formData"in e&&e.formData!=null||"body"in e&&e.body!==void 0)}function Oy(e,t,n,r,s,o,a,l){let c,i;if(a){c=[];for(let p of t)if(c.push(p),p.route.id===a){i=p;break}}else c=t,i=t[t.length-1];let d=Qh(s||".",Jh(c,o),du(e.pathname,n)||e.pathname,l==="path");return s==null&&(d.search=e.search,d.hash=e.hash),(s==null||s===""||s===".")&&i&&i.route.index&&!Rx(d.search)&&(d.search=d.search?d.search.replace(/^\?/,"?index&"):"?index"),r&&n!=="/"&&(d.pathname=d.pathname==="/"?n:uo([n,d.pathname])),wi(d)}function v0(e,t,n,r){if(!r||!q2(r))return{path:n};if(r.formMethod&&!aL(r.formMethod))return{path:n,error:Bn(405,{method:r.formMethod})};let s=()=>({path:n,error:Bn(400,{type:"invalid-body"})}),o=r.formMethod||"get",a=e?o.toUpperCase():o.toLowerCase(),l=p_(n);if(r.body!==void 0){if(r.formEncType==="text/plain"){if(!Jr(a))return s();let f=typeof r.body=="string"?r.body:r.body instanceof FormData||r.body instanceof URLSearchParams?Array.from(r.body.entries()).reduce((h,g)=>{let[m,x]=g;return""+h+m+"="+x+` +`},""):String(r.body);return{path:n,submission:{formMethod:a,formAction:l,formEncType:r.formEncType,formData:void 0,json:void 0,text:f}}}else if(r.formEncType==="application/json"){if(!Jr(a))return s();try{let f=typeof r.body=="string"?JSON.parse(r.body):r.body;return{path:n,submission:{formMethod:a,formAction:l,formEncType:r.formEncType,formData:void 0,json:f,text:void 0}}}catch{return s()}}}Ze(typeof FormData=="function","FormData is not available in this environment");let c,i;if(r.formData)c=Ny(r.formData),i=r.formData;else if(r.body instanceof FormData)c=Ny(r.body),i=r.body;else if(r.body instanceof URLSearchParams)c=r.body,i=S0(c);else if(r.body==null)c=new URLSearchParams,i=new FormData;else try{c=new URLSearchParams(r.body),i=S0(c)}catch{return s()}let d={formMethod:a,formAction:l,formEncType:r&&r.formEncType||"application/x-www-form-urlencoded",formData:i,json:void 0,text:void 0};if(Jr(d.formMethod))return{path:n,submission:d};let p=_a(n);return t&&p.search&&Rx(p.search)&&c.append("index",""),p.search="?"+c,{path:wi(p),submission:d}}function W2(e,t){let n=e;if(t){let r=e.findIndex(s=>s.route.id===t);r>=0&&(n=e.slice(0,r))}return n}function y0(e,t,n,r,s,o,a,l,c,i,d,p,f,h,g,m){let x=m?fr(m[1])?m[1].error:m[1].data:void 0,b=e.createURL(t.location),y=e.createURL(s),w=m&&fr(m[1])?m[0]:void 0,S=w?W2(n,w):n,E=m?m[1].statusCode:void 0,C=a&&E&&E>=400,k=S.filter((P,N)=>{let{route:U}=P;if(U.lazy)return!0;if(U.loader==null)return!1;if(o)return typeof U.loader!="function"||U.loader.hydrate?!0:t.loaderData[U.id]===void 0&&(!t.errors||t.errors[U.id]===void 0);if(G2(t.loaderData,t.matches[N],P)||c.some(V=>V===P.route.id))return!0;let I=t.matches[N],Z=P;return b0(P,At({currentUrl:b,currentParams:I.params,nextUrl:y,nextParams:Z.params},r,{actionResult:x,actionStatus:E,defaultShouldRevalidate:C?!1:l||b.pathname+b.search===y.pathname+y.search||b.search!==y.search||d_(I,Z)}))}),T=[];return p.forEach((P,N)=>{if(o||!n.some(Q=>Q.route.id===P.routeId)||d.has(N))return;let U=Ua(h,P.path,g);if(!U){T.push({key:N,routeId:P.routeId,path:P.path,matches:null,match:null,controller:null});return}let I=t.fetchers.get(N),Z=cc(U,P.path),V=!1;f.has(N)?V=!1:i.includes(N)?V=!0:I&&I.state!=="idle"&&I.data===void 0?V=l:V=b0(Z,At({currentUrl:b,currentParams:t.matches[t.matches.length-1].params,nextUrl:y,nextParams:n[n.length-1].params},r,{actionResult:x,actionStatus:E,defaultShouldRevalidate:C?!1:l})),V&&T.push({key:N,routeId:P.routeId,path:P.path,matches:U,match:Z,controller:new AbortController})}),[k,T]}function G2(e,t,n){let r=!t||n.route.id!==t.route.id,s=e[n.route.id]===void 0;return r||s}function d_(e,t){let n=e.route.path;return e.pathname!==t.pathname||n!=null&&n.endsWith("*")&&e.params["*"]!==t.params["*"]}function b0(e,t){if(e.route.shouldRevalidate){let n=e.route.shouldRevalidate(t);if(typeof n=="boolean")return n}return t.defaultShouldRevalidate}async function J2(e,t,n,r,s,o,a,l){let c=[t,...n.map(i=>i.route.id)].join("-");try{let i=a.get(c);i||(i=e({path:t,matches:n,patch:(d,p)=>{l.aborted||f_(d,p,r,s,o)}}),a.set(c,i)),i&&rL(i)&&await i}finally{a.delete(c)}}function f_(e,t,n,r,s){if(e){var o;let a=r[e];Ze(a,"No route found to patch children into: routeId = "+e);let l=ed(t,s,[e,"patch",String(((o=a.children)==null?void 0:o.length)||"0")],r);a.children?a.children.push(...l):a.children=l}else{let a=ed(t,s,["patch",String(n.length||"0")],r);n.push(...a)}}async function x0(e,t,n){if(!e.lazy)return;let r=await e.lazy();if(!e.lazy)return;let s=n[e.id];Ze(s,"No route found in manifest");let o={};for(let a in r){let c=s[a]!==void 0&&a!=="hasErrorBoundary";Xl(!c,'Route "'+s.id+'" has a static property "'+a+'" defined but its lazy function is also returning a value for this property. '+('The lazy route property "'+a+'" will be ignored.')),!c&&!y2.has(a)&&(o[a]=r[a])}Object.assign(s,o),Object.assign(s,At({},t(s),{lazy:void 0}))}function Q2(e){return Promise.all(e.matches.map(t=>t.resolve()))}async function Z2(e,t,n,r,s,o,a,l){let c=r.reduce((p,f)=>p.add(f.route.id),new Set),i=new Set,d=await e({matches:s.map(p=>{let f=c.has(p.route.id);return At({},p,{shouldLoad:f,resolve:g=>(i.add(p.route.id),f?Y2(t,n,p,o,a,g,l):Promise.resolve({type:Ct.data,result:void 0}))})}),request:n,params:s[0].params,context:l});return s.forEach(p=>Ze(i.has(p.route.id),'`match.resolve()` was not called for route id "'+p.route.id+'". You must call `match.resolve()` on every match passed to `dataStrategy` to ensure all routes are properly loaded.')),d.filter((p,f)=>c.has(s[f].route.id))}async function Y2(e,t,n,r,s,o,a){let l,c,i=d=>{let p,f=new Promise((m,x)=>p=x);c=()=>p(),t.signal.addEventListener("abort",c);let h=m=>typeof d!="function"?Promise.reject(new Error("You cannot call the handler for a route which defines a boolean "+('"'+e+'" [routeId: '+n.route.id+"]"))):d({request:t,params:n.params,context:a},...m!==void 0?[m]:[]),g;return o?g=o(m=>h(m)):g=(async()=>{try{return{type:"data",result:await h()}}catch(m){return{type:"error",result:m}}})(),Promise.race([g,f])};try{let d=n.route[e];if(n.route.lazy)if(d){let p,[f]=await Promise.all([i(d).catch(h=>{p=h}),x0(n.route,s,r)]);if(p!==void 0)throw p;l=f}else if(await x0(n.route,s,r),d=n.route[e],d)l=await i(d);else if(e==="action"){let p=new URL(t.url),f=p.pathname+p.search;throw Bn(405,{method:t.method,pathname:f,routeId:n.route.id})}else return{type:Ct.data,result:void 0};else if(d)l=await i(d);else{let p=new URL(t.url),f=p.pathname+p.search;throw Bn(404,{pathname:f})}Ze(l.result!==void 0,"You defined "+(e==="action"?"an action":"a loader")+" for route "+('"'+n.route.id+"\" but didn't return anything from your `"+e+"` ")+"function. Please return a value or `null`.")}catch(d){return{type:Ct.error,result:d}}finally{c&&t.signal.removeEventListener("abort",c)}return l}async function X2(e){let{result:t,type:n,status:r}=e;if(h_(t)){let a;try{let l=t.headers.get("Content-Type");l&&/\bapplication\/json\b/.test(l)?t.body==null?a=null:a=await t.json():a=await t.text()}catch(l){return{type:Ct.error,error:l}}return n===Ct.error?{type:Ct.error,error:new _x(t.status,t.statusText,a),statusCode:t.status,headers:t.headers}:{type:Ct.data,data:a,statusCode:t.status,headers:t.headers}}if(n===Ct.error)return{type:Ct.error,error:t,statusCode:Zh(t)?t.status:r};if(oL(t)){var s,o;return{type:Ct.deferred,deferredData:t,statusCode:(s=t.init)==null?void 0:s.status,headers:((o=t.init)==null?void 0:o.headers)&&new Headers(t.init.headers)}}return{type:Ct.data,data:t,statusCode:r}}function eL(e,t,n,r,s,o){let a=e.headers.get("Location");if(Ze(a,"Redirects returned/thrown from loaders/actions must have a Location header"),!jx.test(a)){let l=r.slice(0,r.findIndex(c=>c.route.id===n)+1);a=Oy(new URL(t.url),l,s,!0,a,o),e.headers.set("Location",a)}return e}function w0(e,t,n){if(jx.test(e)){let r=e,s=r.startsWith("//")?new URL(t.protocol+r):new URL(r),o=du(s.pathname,n)!=null;if(s.origin===t.origin&&o)return s.pathname+s.search+s.hash}return e}function Hi(e,t,n,r){let s=e.createURL(p_(t)).toString(),o={signal:n};if(r&&Jr(r.formMethod)){let{formMethod:a,formEncType:l}=r;o.method=a.toUpperCase(),l==="application/json"?(o.headers=new Headers({"Content-Type":l}),o.body=JSON.stringify(r.json)):l==="text/plain"?o.body=r.text:l==="application/x-www-form-urlencoded"&&r.formData?o.body=Ny(r.formData):o.body=r.formData}return new Request(s,o)}function Ny(e){let t=new URLSearchParams;for(let[n,r]of e.entries())t.append(n,typeof r=="string"?r:r.name);return t}function S0(e){let t=new FormData;for(let[n,r]of e.entries())t.append(n,r);return t}function tL(e,t,n,r,s,o){let a={},l=null,c,i=!1,d={},p=r&&fr(r[1])?r[1].error:void 0;return n.forEach((f,h)=>{let g=t[h].route.id;if(Ze(!Wa(f),"Cannot handle redirect results in processLoaderData"),fr(f)){let m=f.error;p!==void 0&&(m=p,p=void 0),l=l||{};{let x=gl(e,g);l[x.route.id]==null&&(l[x.route.id]=m)}a[g]=void 0,i||(i=!0,c=Zh(f.error)?f.error.status:500),f.headers&&(d[g]=f.headers)}else qa(f)?(s.set(g,f.deferredData),a[g]=f.deferredData.data,f.statusCode!=null&&f.statusCode!==200&&!i&&(c=f.statusCode),f.headers&&(d[g]=f.headers)):(a[g]=f.data,f.statusCode&&f.statusCode!==200&&!i&&(c=f.statusCode),f.headers&&(d[g]=f.headers))}),p!==void 0&&r&&(l={[r[0]]:p},a[r[0]]=void 0),{loaderData:a,errors:l,statusCode:c||200,loaderHeaders:d}}function C0(e,t,n,r,s,o,a,l){let{loaderData:c,errors:i}=tL(t,n,r,s,l);for(let d=0;dr.route.id===t)+1):[...e]).reverse().find(r=>r.route.hasErrorBoundary===!0)||e[0]}function k0(e){let t=e.length===1?e[0]:e.find(n=>n.index||!n.path||n.path==="/")||{id:"__shim-error-route__"};return{matches:[{params:{},pathname:"",pathnameBase:"",route:t}],route:t}}function Bn(e,t){let{pathname:n,routeId:r,method:s,type:o,message:a}=t===void 0?{}:t,l="Unknown Server Error",c="Unknown @remix-run/router error";return e===400?(l="Bad Request",o==="route-discovery"?c='Unable to match URL "'+n+'" - the `unstable_patchRoutesOnMiss()` '+(`function threw the following error: +`+a):s&&n&&r?c="You made a "+s+' request to "'+n+'" but '+('did not provide a `loader` for route "'+r+'", ')+"so there is no way to handle the request.":o==="defer-action"?c="defer() is not supported in actions":o==="invalid-body"&&(c="Unable to encode submission body")):e===403?(l="Forbidden",c='Route "'+r+'" does not match URL "'+n+'"'):e===404?(l="Not Found",c='No route matches URL "'+n+'"'):e===405&&(l="Method Not Allowed",s&&n&&r?c="You made a "+s.toUpperCase()+' request to "'+n+'" but '+('did not provide an `action` for route "'+r+'", ')+"so there is no way to handle the request.":s&&(c='Invalid request method "'+s.toUpperCase()+'"')),new _x(e||500,l,new Error(c),!0)}function _0(e){for(let t=e.length-1;t>=0;t--){let n=e[t];if(Wa(n))return{result:n,idx:t}}}function p_(e){let t=typeof e=="string"?_a(e):e;return wi(At({},t,{hash:""}))}function nL(e,t){return e.pathname!==t.pathname||e.search!==t.search?!1:e.hash===""?t.hash!=="":e.hash===t.hash?!0:t.hash!==""}function rL(e){return typeof e=="object"&&e!=null&&"then"in e}function sL(e){return h_(e.result)&&z2.has(e.result.status)}function qa(e){return e.type===Ct.deferred}function fr(e){return e.type===Ct.error}function Wa(e){return(e&&e.type)===Ct.redirect}function oL(e){let t=e;return t&&typeof t=="object"&&typeof t.data=="object"&&typeof t.subscribe=="function"&&typeof t.cancel=="function"&&typeof t.resolveData=="function"}function h_(e){return e!=null&&typeof e.status=="number"&&typeof e.statusText=="string"&&typeof e.headers=="object"&&typeof e.body<"u"}function aL(e){return B2.has(e.toLowerCase())}function Jr(e){return L2.has(e.toLowerCase())}async function j0(e,t,n,r,s,o){for(let a=0;ap.route.id===c.route.id),d=i!=null&&!d_(i,c)&&(o&&o[c.route.id])!==void 0;if(qa(l)&&(s||d)){let p=r[a];Ze(p,"Expected an AbortSignal for revalidating fetcher deferred result"),await g_(l,p,s).then(f=>{f&&(n[a]=f||n[a])})}}}async function g_(e,t,n){if(n===void 0&&(n=!1),!await e.deferredData.resolveData(t)){if(n)try{return{type:Ct.data,data:e.deferredData.unwrappedData}}catch(s){return{type:Ct.error,error:s}}return{type:Ct.data,data:e.deferredData.data}}}function Rx(e){return new URLSearchParams(e).getAll("index").some(t=>t==="")}function cc(e,t){let n=typeof t=="string"?_a(t).search:t.search;if(e[e.length-1].route.index&&Rx(n||""))return e[e.length-1];let r=l_(e);return r[r.length-1]}function R0(e){let{formMethod:t,formAction:n,formEncType:r,text:s,formData:o,json:a}=e;if(!(!t||!n||!r)){if(s!=null)return{formMethod:t,formAction:n,formEncType:r,formData:void 0,json:void 0,text:s};if(o!=null)return{formMethod:t,formAction:n,formEncType:r,formData:o,json:void 0,text:void 0};if(a!==void 0)return{formMethod:t,formAction:n,formEncType:r,formData:void 0,json:a,text:void 0}}}function Im(e,t){return t?{state:"loading",location:e,formMethod:t.formMethod,formAction:t.formAction,formEncType:t.formEncType,formData:t.formData,json:t.json,text:t.text}:{state:"loading",location:e,formMethod:void 0,formAction:void 0,formEncType:void 0,formData:void 0,json:void 0,text:void 0}}function iL(e,t){return{state:"submitting",location:e,formMethod:t.formMethod,formAction:t.formAction,formEncType:t.formEncType,formData:t.formData,json:t.json,text:t.text}}function qu(e,t){return e?{state:"loading",formMethod:e.formMethod,formAction:e.formAction,formEncType:e.formEncType,formData:e.formData,json:e.json,text:e.text,data:t}:{state:"loading",formMethod:void 0,formAction:void 0,formEncType:void 0,formData:void 0,json:void 0,text:void 0,data:t}}function lL(e,t){return{state:"submitting",formMethod:e.formMethod,formAction:e.formAction,formEncType:e.formEncType,formData:e.formData,json:e.json,text:e.text,data:t?t.data:void 0}}function Fo(e){return{state:"idle",formMethod:void 0,formAction:void 0,formEncType:void 0,formData:void 0,json:void 0,text:void 0,data:e}}function uL(e,t){try{let n=e.sessionStorage.getItem(c_);if(n){let r=JSON.parse(n);for(let[s,o]of Object.entries(r||{}))o&&Array.isArray(o)&&t.set(s,new Set(o||[]))}}catch{}}function cL(e,t){if(t.size>0){let n={};for(let[r,s]of t)n[r]=[...s];try{e.sessionStorage.setItem(c_,JSON.stringify(n))}catch(r){Xl(!1,"Failed to save applied view transitions in sessionStorage ("+r+").")}}}/** + * React Router v6.25.1 + * + * Copyright (c) Remix Software Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE.md file in the root directory of this source tree. + * + * @license MIT + */function Zp(){return Zp=Object.assign?Object.assign.bind():function(e){for(var t=1;t{l.current=!0}),v.useCallback(function(i,d){if(d===void 0&&(d={}),!l.current)return;if(typeof i=="number"){r.go(i);return}let p=Qh(i,JSON.parse(a),o,d.relative==="path");e==null&&t!=="/"&&(p.pathname=p.pathname==="/"?t:uo([t,p.pathname])),(d.replace?r.replace:r.push)(p,d.state,d)},[t,r,a,o,e])}function So(){let{matches:e}=v.useContext(wo),t=e[e.length-1];return t?t.params:{}}function b_(e,t){let{relative:n}=t===void 0?{}:t,{future:r}=v.useContext(ja),{matches:s}=v.useContext(wo),{pathname:o}=pu(),a=JSON.stringify(Jh(s,r.v7_relativeSplatPath));return v.useMemo(()=>Qh(e,JSON.parse(a),o,n==="path"),[e,a,o,n])}function pL(e,t,n,r){fu()||Ze(!1);let{navigator:s}=v.useContext(ja),{matches:o}=v.useContext(wo),a=o[o.length-1],l=a?a.params:{};a&&a.pathname;let c=a?a.pathnameBase:"/";a&&a.route;let i=pu(),d;d=i;let p=d.pathname||"/",f=p;if(c!=="/"){let m=c.replace(/^\//,"").split("/");f="/"+p.replace(/^\//,"").split("/").slice(m.length).join("/")}let h=Ua(e,{pathname:f});return yL(h&&h.map(m=>Object.assign({},m,{params:Object.assign({},l,m.params),pathname:uo([c,s.encodeLocation?s.encodeLocation(m.pathname).pathname:m.pathname]),pathnameBase:m.pathnameBase==="/"?c:uo([c,s.encodeLocation?s.encodeLocation(m.pathnameBase).pathname:m.pathnameBase])})),o,n,r)}function hL(){let e=SL(),t=Zh(e)?e.status+" "+e.statusText:e instanceof Error?e.message:JSON.stringify(e),n=e instanceof Error?e.stack:null,s={padding:"0.5rem",backgroundColor:"rgba(200,200,200, 0.5)"};return v.createElement(v.Fragment,null,v.createElement("h2",null,"Unexpected Application Error!"),v.createElement("h3",{style:{fontStyle:"italic"}},t),n?v.createElement("pre",{style:s},n):null,null)}const gL=v.createElement(hL,null);class mL extends v.Component{constructor(t){super(t),this.state={location:t.location,revalidation:t.revalidation,error:t.error}}static getDerivedStateFromError(t){return{error:t}}static getDerivedStateFromProps(t,n){return n.location!==t.location||n.revalidation!=="idle"&&t.revalidation==="idle"?{error:t.error,location:t.location,revalidation:t.revalidation}:{error:t.error!==void 0?t.error:n.error,location:n.location,revalidation:t.revalidation||n.revalidation}}componentDidCatch(t,n){console.error("React Router caught the following error during render",t,n)}render(){return this.state.error!==void 0?v.createElement(wo.Provider,{value:this.props.routeContext},v.createElement(v_.Provider,{value:this.state.error,children:this.props.component})):this.props.children}}function vL(e){let{routeContext:t,match:n,children:r}=e,s=v.useContext(Yh);return s&&s.static&&s.staticContext&&(n.route.errorElement||n.route.ErrorBoundary)&&(s.staticContext._deepestRenderedBoundaryId=n.route.id),v.createElement(wo.Provider,{value:t},r)}function yL(e,t,n,r){var s;if(t===void 0&&(t=[]),n===void 0&&(n=null),r===void 0&&(r=null),e==null){var o;if((o=n)!=null&&o.errors)e=n.matches;else return null}let a=e,l=(s=n)==null?void 0:s.errors;if(l!=null){let d=a.findIndex(p=>p.route.id&&(l==null?void 0:l[p.route.id])!==void 0);d>=0||Ze(!1),a=a.slice(0,Math.min(a.length,d+1))}let c=!1,i=-1;if(n&&r&&r.v7_partialHydration)for(let d=0;d=0?a=a.slice(0,i+1):a=[a[0]];break}}}return a.reduceRight((d,p,f)=>{let h,g=!1,m=null,x=null;n&&(h=l&&p.route.id?l[p.route.id]:void 0,m=p.route.errorElement||gL,c&&(i<0&&f===0?(EL("route-fallback"),g=!0,x=null):i===f&&(g=!0,x=p.route.hydrateFallbackElement||null)));let b=t.concat(a.slice(0,f+1)),y=()=>{let w;return h?w=m:g?w=x:p.route.Component?w=v.createElement(p.route.Component,null):p.route.element?w=p.route.element:w=d,v.createElement(vL,{match:p,routeContext:{outlet:d,matches:b,isDataRoute:n!=null},children:w})};return n&&(p.route.ErrorBoundary||p.route.errorElement||f===0)?v.createElement(mL,{location:n.location,revalidation:n.revalidation,component:m,error:h,children:y(),routeContext:{outlet:null,matches:b,isDataRoute:!0}}):y()},null)}var x_=function(e){return e.UseBlocker="useBlocker",e.UseRevalidator="useRevalidator",e.UseNavigateStable="useNavigate",e}(x_||{}),Yp=function(e){return e.UseBlocker="useBlocker",e.UseLoaderData="useLoaderData",e.UseActionData="useActionData",e.UseRouteError="useRouteError",e.UseNavigation="useNavigation",e.UseRouteLoaderData="useRouteLoaderData",e.UseMatches="useMatches",e.UseRevalidator="useRevalidator",e.UseNavigateStable="useNavigate",e.UseRouteId="useRouteId",e}(Yp||{});function bL(e){let t=v.useContext(Yh);return t||Ze(!1),t}function xL(e){let t=v.useContext(m_);return t||Ze(!1),t}function wL(e){let t=v.useContext(wo);return t||Ze(!1),t}function w_(e){let t=wL(),n=t.matches[t.matches.length-1];return n.route.id||Ze(!1),n.route.id}function SL(){var e;let t=v.useContext(v_),n=xL(Yp.UseRouteError),r=w_(Yp.UseRouteError);return t!==void 0?t:(e=n.errors)==null?void 0:e[r]}function CL(){let{router:e}=bL(x_.UseNavigateStable),t=w_(Yp.UseNavigateStable),n=v.useRef(!1);return y_(()=>{n.current=!0}),v.useCallback(function(s,o){o===void 0&&(o={}),n.current&&(typeof s=="number"?e.navigate(s):e.navigate(s,Zp({fromRouteId:t},o)))},[e,t])}const P0={};function EL(e,t,n){P0[e]||(P0[e]=!0)}function S_(e){let{to:t,replace:n,state:r,relative:s}=e;fu()||Ze(!1);let{future:o,static:a}=v.useContext(ja),{matches:l}=v.useContext(wo),{pathname:c}=pu(),i=An(),d=Qh(t,Jh(l,o.v7_relativeSplatPath),c,s==="path"),p=JSON.stringify(d);return v.useEffect(()=>i(JSON.parse(p),{replace:n,state:r,relative:s}),[i,p,s,n,r]),null}function TL(e){let{basename:t="/",children:n=null,location:r,navigationType:s=en.Pop,navigator:o,static:a=!1,future:l}=e;fu()&&Ze(!1);let c=t.replace(/^\/*/,"/"),i=v.useMemo(()=>({basename:c,navigator:o,static:a,future:Zp({v7_relativeSplatPath:!1},l)}),[c,l,o,a]);typeof r=="string"&&(r=_a(r));let{pathname:d="/",search:p="",hash:f="",state:h=null,key:g="default"}=r,m=v.useMemo(()=>{let x=du(d,c);return x==null?null:{location:{pathname:x,search:p,hash:f,state:h,key:g},navigationType:s}},[c,d,p,f,h,g,s]);return m==null?null:v.createElement(ja.Provider,{value:i},v.createElement(Px.Provider,{children:n,value:m}))}new Promise(()=>{});function kL(e){let t={hasErrorBoundary:e.ErrorBoundary!=null||e.errorElement!=null};return e.Component&&Object.assign(t,{element:v.createElement(e.Component),Component:void 0}),e.HydrateFallback&&Object.assign(t,{hydrateFallbackElement:v.createElement(e.HydrateFallback),HydrateFallback:void 0}),e.ErrorBoundary&&Object.assign(t,{errorElement:v.createElement(e.ErrorBoundary),ErrorBoundary:void 0}),t}/** + * React Router DOM v6.25.1 + * + * Copyright (c) Remix Software Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE.md file in the root directory of this source tree. + * + * @license MIT + */function td(){return td=Object.assign?Object.assign.bind():function(e){for(var t=1;t=0)&&(n[s]=e[s]);return n}function jL(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}function RL(e,t){return e.button===0&&(!t||t==="_self")&&!jL(e)}const PL=["onClick","relative","reloadDocument","replace","state","target","to","preventScrollReset","unstable_viewTransition"],ML="6";try{window.__reactRouterVersion=ML}catch{}function OL(e,t){return K2({basename:void 0,future:td({},void 0,{v7_prependBasename:!0}),history:g2({window:void 0}),hydrationData:NL(),routes:e,mapRouteProperties:kL,unstable_dataStrategy:void 0,unstable_patchRoutesOnMiss:void 0,window:void 0}).initialize()}function NL(){var e;let t=(e=window)==null?void 0:e.__staticRouterHydrationData;return t&&t.errors&&(t=td({},t,{errors:IL(t.errors)})),t}function IL(e){if(!e)return null;let t=Object.entries(e),n={};for(let[r,s]of t)if(s&&s.__type==="RouteErrorResponse")n[r]=new _x(s.status,s.statusText,s.data,s.internal===!0);else if(s&&s.__type==="Error"){if(s.__subType){let o=window[s.__subType];if(typeof o=="function")try{let a=new o(s.message);a.stack="",n[r]=a}catch{}}if(n[r]==null){let o=new Error(s.message);o.stack="",n[r]=o}}else n[r]=s;return n}const DL=v.createContext({isTransitioning:!1}),AL=v.createContext(new Map),FL="startTransition",M0=Nh[FL],LL="flushSync",O0=YF[LL];function $L(e){M0?M0(e):e()}function Wu(e){O0?O0(e):e()}class BL{constructor(){this.status="pending",this.promise=new Promise((t,n)=>{this.resolve=r=>{this.status==="pending"&&(this.status="resolved",t(r))},this.reject=r=>{this.status==="pending"&&(this.status="rejected",n(r))}})}}function zL(e){let{fallbackElement:t,router:n,future:r}=e,[s,o]=v.useState(n.state),[a,l]=v.useState(),[c,i]=v.useState({isTransitioning:!1}),[d,p]=v.useState(),[f,h]=v.useState(),[g,m]=v.useState(),x=v.useRef(new Map),{v7_startTransition:b}=r||{},y=v.useCallback(T=>{b?$L(T):T()},[b]),w=v.useCallback((T,P)=>{let{deletedFetchers:N,unstable_flushSync:U,unstable_viewTransitionOpts:I}=P;N.forEach(V=>x.current.delete(V)),T.fetchers.forEach((V,Q)=>{V.data!==void 0&&x.current.set(Q,V.data)});let Z=n.window==null||n.window.document==null||typeof n.window.document.startViewTransition!="function";if(!I||Z){U?Wu(()=>o(T)):y(()=>o(T));return}if(U){Wu(()=>{f&&(d&&d.resolve(),f.skipTransition()),i({isTransitioning:!0,flushSync:!0,currentLocation:I.currentLocation,nextLocation:I.nextLocation})});let V=n.window.document.startViewTransition(()=>{Wu(()=>o(T))});V.finished.finally(()=>{Wu(()=>{p(void 0),h(void 0),l(void 0),i({isTransitioning:!1})})}),Wu(()=>h(V));return}f?(d&&d.resolve(),f.skipTransition(),m({state:T,currentLocation:I.currentLocation,nextLocation:I.nextLocation})):(l(T),i({isTransitioning:!0,flushSync:!1,currentLocation:I.currentLocation,nextLocation:I.nextLocation}))},[n.window,f,d,x,y]);v.useLayoutEffect(()=>n.subscribe(w),[n,w]),v.useEffect(()=>{c.isTransitioning&&!c.flushSync&&p(new BL)},[c]),v.useEffect(()=>{if(d&&a&&n.window){let T=a,P=d.promise,N=n.window.document.startViewTransition(async()=>{y(()=>o(T)),await P});N.finished.finally(()=>{p(void 0),h(void 0),l(void 0),i({isTransitioning:!1})}),h(N)}},[y,a,d,n.window]),v.useEffect(()=>{d&&a&&s.location.key===a.location.key&&d.resolve()},[d,f,s.location,a]),v.useEffect(()=>{!c.isTransitioning&&g&&(l(g.state),i({isTransitioning:!0,flushSync:!1,currentLocation:g.currentLocation,nextLocation:g.nextLocation}),m(void 0))},[c.isTransitioning,g]),v.useEffect(()=>{},[]);let S=v.useMemo(()=>({createHref:n.createHref,encodeLocation:n.encodeLocation,go:T=>n.navigate(T),push:(T,P,N)=>n.navigate(T,{state:P,preventScrollReset:N==null?void 0:N.preventScrollReset}),replace:(T,P,N)=>n.navigate(T,{replace:!0,state:P,preventScrollReset:N==null?void 0:N.preventScrollReset})}),[n]),E=n.basename||"/",C=v.useMemo(()=>({router:n,navigator:S,static:!1,basename:E}),[n,S,E]),k=v.useMemo(()=>({v7_relativeSplatPath:n.future.v7_relativeSplatPath}),[n.future.v7_relativeSplatPath]);return v.createElement(v.Fragment,null,v.createElement(Yh.Provider,{value:C},v.createElement(m_.Provider,{value:s},v.createElement(AL.Provider,{value:x.current},v.createElement(DL.Provider,{value:c},v.createElement(TL,{basename:E,location:s.location,navigationType:s.historyAction,navigator:S,future:k},s.initialized||n.future.v7_partialHydration?v.createElement(UL,{routes:n.routes,future:n.future,state:s}):t))))),null)}const UL=v.memo(VL);function VL(e){let{routes:t,future:n,state:r}=e;return pL(t,void 0,r,n)}const HL=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u",KL=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i,nd=v.forwardRef(function(t,n){let{onClick:r,relative:s,reloadDocument:o,replace:a,state:l,target:c,to:i,preventScrollReset:d,unstable_viewTransition:p}=t,f=_L(t,PL),{basename:h}=v.useContext(ja),g,m=!1;if(typeof i=="string"&&KL.test(i)&&(g=i,HL))try{let w=new URL(window.location.href),S=i.startsWith("//")?new URL(w.protocol+i):new URL(i),E=du(S.pathname,h);S.origin===w.origin&&E!=null?i=E+S.search+S.hash:m=!0}catch{}let x=dL(i,{relative:s}),b=qL(i,{replace:a,state:l,target:c,preventScrollReset:d,relative:s,unstable_viewTransition:p});function y(w){r&&r(w),w.defaultPrevented||b(w)}return v.createElement("a",td({},f,{href:g||x,onClick:m||o?r:y,ref:n,target:c}))});var N0;(function(e){e.UseScrollRestoration="useScrollRestoration",e.UseSubmit="useSubmit",e.UseSubmitFetcher="useSubmitFetcher",e.UseFetcher="useFetcher",e.useViewTransitionState="useViewTransitionState"})(N0||(N0={}));var I0;(function(e){e.UseFetcher="useFetcher",e.UseFetchers="useFetchers",e.UseScrollRestoration="useScrollRestoration"})(I0||(I0={}));function qL(e,t){let{target:n,replace:r,state:s,preventScrollReset:o,relative:a,unstable_viewTransition:l}=t===void 0?{}:t,c=An(),i=pu(),d=b_(e,{relative:a});return v.useCallback(p=>{if(RL(p,n)){p.preventDefault();let f=r!==void 0?r:wi(i)===wi(d);c(e,{replace:f,state:s,preventScrollReset:o,relative:a,unstable_viewTransition:l})}},[i,c,d,r,s,n,e,o,a,l])}function C_(e){var t,n,r="";if(typeof e=="string"||typeof e=="number")r+=e;else if(typeof e=="object")if(Array.isArray(e)){var s=e.length;for(t=0;ttypeof e=="number"&&!isNaN(e),ci=e=>typeof e=="string",gr=e=>typeof e=="function",dp=e=>ci(e)||gr(e)?e:null,Iy=e=>v.isValidElement(e)||ci(e)||gr(e)||rd(e);function WL(e,t,n){n===void 0&&(n=300);const{scrollHeight:r,style:s}=e;requestAnimationFrame(()=>{s.minHeight="initial",s.height=r+"px",s.transition=`all ${n}ms`,requestAnimationFrame(()=>{s.height="0",s.padding="0",s.margin="0",setTimeout(t,n)})})}function Xh(e){let{enter:t,exit:n,appendPosition:r=!1,collapse:s=!0,collapseDuration:o=300}=e;return function(a){let{children:l,position:c,preventExitTransition:i,done:d,nodeRef:p,isIn:f,playToast:h}=a;const g=r?`${t}--${c}`:t,m=r?`${n}--${c}`:n,x=v.useRef(0);return v.useLayoutEffect(()=>{const b=p.current,y=g.split(" "),w=S=>{S.target===p.current&&(h(),b.removeEventListener("animationend",w),b.removeEventListener("animationcancel",w),x.current===0&&S.type!=="animationcancel"&&b.classList.remove(...y))};b.classList.add(...y),b.addEventListener("animationend",w),b.addEventListener("animationcancel",w)},[]),v.useEffect(()=>{const b=p.current,y=()=>{b.removeEventListener("animationend",y),s?WL(b,d,o):d()};f||(i?y():(x.current=1,b.className+=` ${m}`,b.addEventListener("animationend",y)))},[f]),Te.createElement(Te.Fragment,null,l)}}function D0(e,t){return e!=null?{content:e.content,containerId:e.props.containerId,id:e.props.toastId,theme:e.props.theme,type:e.props.type,data:e.props.data||{},isLoading:e.props.isLoading,icon:e.props.icon,status:t}:{}}const Vn=new Map;let sd=[];const Dy=new Set,GL=e=>Dy.forEach(t=>t(e)),E_=()=>Vn.size>0;function T_(e,t){var n;if(t)return!((n=Vn.get(t))==null||!n.isToastActive(e));let r=!1;return Vn.forEach(s=>{s.isToastActive(e)&&(r=!0)}),r}function k_(e,t){Iy(e)&&(E_()||sd.push({content:e,options:t}),Vn.forEach(n=>{n.buildToast(e,t)}))}function A0(e,t){Vn.forEach(n=>{t!=null&&t!=null&&t.containerId?(t==null?void 0:t.containerId)===n.id&&n.toggle(e,t==null?void 0:t.id):n.toggle(e,t==null?void 0:t.id)})}function JL(e){const{subscribe:t,getSnapshot:n,setProps:r}=v.useRef(function(o){const a=o.containerId||1;return{subscribe(l){const c=function(d,p,f){let h=1,g=0,m=[],x=[],b=[],y=p;const w=new Map,S=new Set,E=()=>{b=Array.from(w.values()),S.forEach(T=>T())},C=T=>{x=T==null?[]:x.filter(P=>P!==T),E()},k=T=>{const{toastId:P,onOpen:N,updateId:U,children:I}=T.props,Z=U==null;T.staleId&&w.delete(T.staleId),w.set(P,T),x=[...x,T.props.toastId].filter(V=>V!==T.staleId),E(),f(D0(T,Z?"added":"updated")),Z&&gr(N)&&N(v.isValidElement(I)&&I.props)};return{id:d,props:y,observe:T=>(S.add(T),()=>S.delete(T)),toggle:(T,P)=>{w.forEach(N=>{P!=null&&P!==N.props.toastId||gr(N.toggle)&&N.toggle(T)})},removeToast:C,toasts:w,clearQueue:()=>{g-=m.length,m=[]},buildToast:(T,P)=>{if((z=>{let{containerId:se,toastId:ne,updateId:ie}=z;const oe=se?se!==d:d!==1,J=w.has(ne)&&ie==null;return oe||J})(P))return;const{toastId:N,updateId:U,data:I,staleId:Z,delay:V}=P,Q=()=>{C(N)},ee=U==null;ee&&g++;const W={...y,style:y.toastStyle,key:h++,...Object.fromEntries(Object.entries(P).filter(z=>{let[se,ne]=z;return ne!=null})),toastId:N,updateId:U,data:I,closeToast:Q,isIn:!1,className:dp(P.className||y.toastClassName),bodyClassName:dp(P.bodyClassName||y.bodyClassName),progressClassName:dp(P.progressClassName||y.progressClassName),autoClose:!P.isLoading&&(F=P.autoClose,A=y.autoClose,F===!1||rd(F)&&F>0?F:A),deleteToast(){const z=w.get(N),{onClose:se,children:ne}=z.props;gr(se)&&se(v.isValidElement(ne)&&ne.props),f(D0(z,"removed")),w.delete(N),g--,g<0&&(g=0),m.length>0?k(m.shift()):E()}};var F,A;W.closeButton=y.closeButton,P.closeButton===!1||Iy(P.closeButton)?W.closeButton=P.closeButton:P.closeButton===!0&&(W.closeButton=!Iy(y.closeButton)||y.closeButton);let Y=T;v.isValidElement(T)&&!ci(T.type)?Y=v.cloneElement(T,{closeToast:Q,toastProps:W,data:I}):gr(T)&&(Y=T({closeToast:Q,toastProps:W,data:I}));const de={content:Y,props:W,staleId:Z};y.limit&&y.limit>0&&g>y.limit&&ee?m.push(de):rd(V)?setTimeout(()=>{k(de)},V):k(de)},setProps(T){y=T},setToggle:(T,P)=>{w.get(T).toggle=P},isToastActive:T=>x.some(P=>P===T),getSnapshot:()=>y.newestOnTop?b.reverse():b}}(a,o,GL);Vn.set(a,c);const i=c.observe(l);return sd.forEach(d=>k_(d.content,d.options)),sd=[],()=>{i(),Vn.delete(a)}},setProps(l){var c;(c=Vn.get(a))==null||c.setProps(l)},getSnapshot(){var l;return(l=Vn.get(a))==null?void 0:l.getSnapshot()}}}(e)).current;r(e);const s=v.useSyncExternalStore(t,n,n);return{getToastToRender:function(o){if(!s)return[];const a=new Map;return s.forEach(l=>{const{position:c}=l.props;a.has(c)||a.set(c,[]),a.get(c).push(l)}),Array.from(a,l=>o(l[0],l[1]))},isToastActive:T_,count:s==null?void 0:s.length}}function QL(e){const[t,n]=v.useState(!1),[r,s]=v.useState(!1),o=v.useRef(null),a=v.useRef({start:0,delta:0,removalDistance:0,canCloseOnClick:!0,canDrag:!1,didMove:!1}).current,{autoClose:l,pauseOnHover:c,closeToast:i,onClick:d,closeOnClick:p}=e;var f,h;function g(){n(!0)}function m(){n(!1)}function x(w){const S=o.current;a.canDrag&&S&&(a.didMove=!0,t&&m(),a.delta=e.draggableDirection==="x"?w.clientX-a.start:w.clientY-a.start,a.start!==w.clientX&&(a.canCloseOnClick=!1),S.style.transform=`translate3d(${e.draggableDirection==="x"?`${a.delta}px, var(--y)`:`0, calc(${a.delta}px + var(--y))`},0)`,S.style.opacity=""+(1-Math.abs(a.delta/a.removalDistance)))}function b(){document.removeEventListener("pointermove",x),document.removeEventListener("pointerup",b);const w=o.current;if(a.canDrag&&a.didMove&&w){if(a.canDrag=!1,Math.abs(a.delta)>a.removalDistance)return s(!0),e.closeToast(),void e.collapseAll();w.style.transition="transform 0.2s, opacity 0.2s",w.style.removeProperty("transform"),w.style.removeProperty("opacity")}}(h=Vn.get((f={id:e.toastId,containerId:e.containerId,fn:n}).containerId||1))==null||h.setToggle(f.id,f.fn),v.useEffect(()=>{if(e.pauseOnFocusLoss)return document.hasFocus()||m(),window.addEventListener("focus",g),window.addEventListener("blur",m),()=>{window.removeEventListener("focus",g),window.removeEventListener("blur",m)}},[e.pauseOnFocusLoss]);const y={onPointerDown:function(w){if(e.draggable===!0||e.draggable===w.pointerType){a.didMove=!1,document.addEventListener("pointermove",x),document.addEventListener("pointerup",b);const S=o.current;a.canCloseOnClick=!0,a.canDrag=!0,S.style.transition="none",e.draggableDirection==="x"?(a.start=w.clientX,a.removalDistance=S.offsetWidth*(e.draggablePercent/100)):(a.start=w.clientY,a.removalDistance=S.offsetHeight*(e.draggablePercent===80?1.5*e.draggablePercent:e.draggablePercent)/100)}},onPointerUp:function(w){const{top:S,bottom:E,left:C,right:k}=o.current.getBoundingClientRect();w.nativeEvent.type!=="touchend"&&e.pauseOnHover&&w.clientX>=C&&w.clientX<=k&&w.clientY>=S&&w.clientY<=E?m():g()}};return l&&c&&(y.onMouseEnter=m,e.stacked||(y.onMouseLeave=g)),p&&(y.onClick=w=>{d&&d(w),a.canCloseOnClick&&i()}),{playToast:g,pauseToast:m,isRunning:t,preventExitTransition:r,toastRef:o,eventHandlers:y}}function ZL(e){let{delay:t,isRunning:n,closeToast:r,type:s="default",hide:o,className:a,style:l,controlledProgress:c,progress:i,rtl:d,isIn:p,theme:f}=e;const h=o||c&&i===0,g={...l,animationDuration:`${t}ms`,animationPlayState:n?"running":"paused"};c&&(g.transform=`scaleX(${i})`);const m=oo("Toastify__progress-bar",c?"Toastify__progress-bar--controlled":"Toastify__progress-bar--animated",`Toastify__progress-bar-theme--${f}`,`Toastify__progress-bar--${s}`,{"Toastify__progress-bar--rtl":d}),x=gr(a)?a({rtl:d,type:s,defaultClassName:m}):oo(m,a),b={[c&&i>=1?"onTransitionEnd":"onAnimationEnd"]:c&&i<1?null:()=>{p&&r()}};return Te.createElement("div",{className:"Toastify__progress-bar--wrp","data-hidden":h},Te.createElement("div",{className:`Toastify__progress-bar--bg Toastify__progress-bar-theme--${f} Toastify__progress-bar--${s}`}),Te.createElement("div",{role:"progressbar","aria-hidden":h?"true":"false","aria-label":"notification timer",className:x,style:g,...b}))}let YL=1;const __=()=>""+YL++;function XL(e){return e&&(ci(e.toastId)||rd(e.toastId))?e.toastId:__()}function _c(e,t){return k_(e,t),t.toastId}function Xp(e,t){return{...t,type:t&&t.type||e,toastId:XL(t)}}function jf(e){return(t,n)=>_c(t,Xp(e,n))}function X(e,t){return _c(e,Xp("default",t))}X.loading=(e,t)=>_c(e,Xp("default",{isLoading:!0,autoClose:!1,closeOnClick:!1,closeButton:!1,draggable:!1,...t})),X.promise=function(e,t,n){let r,{pending:s,error:o,success:a}=t;s&&(r=ci(s)?X.loading(s,n):X.loading(s.render,{...n,...s}));const l={isLoading:null,autoClose:null,closeOnClick:null,closeButton:null,draggable:null},c=(d,p,f)=>{if(p==null)return void X.dismiss(r);const h={type:d,...l,...n,data:f},g=ci(p)?{render:p}:p;return r?X.update(r,{...h,...g}):X(g.render,{...h,...g}),f},i=gr(e)?e():e;return i.then(d=>c("success",a,d)).catch(d=>c("error",o,d)),i},X.success=jf("success"),X.info=jf("info"),X.error=jf("error"),X.warning=jf("warning"),X.warn=X.warning,X.dark=(e,t)=>_c(e,Xp("default",{theme:"dark",...t})),X.dismiss=function(e){(function(t){var n;if(E_()){if(t==null||ci(n=t)||rd(n))Vn.forEach(r=>{r.removeToast(t)});else if(t&&("containerId"in t||"id"in t)){const r=Vn.get(t.containerId);r?r.removeToast(t.id):Vn.forEach(s=>{s.removeToast(t.id)})}}else sd=sd.filter(r=>t!=null&&r.options.toastId!==t)})(e)},X.clearWaitingQueue=function(e){e===void 0&&(e={}),Vn.forEach(t=>{!t.props.limit||e.containerId&&t.id!==e.containerId||t.clearQueue()})},X.isActive=T_,X.update=function(e,t){t===void 0&&(t={});const n=((r,s)=>{var o;let{containerId:a}=s;return(o=Vn.get(a||1))==null?void 0:o.toasts.get(r)})(e,t);if(n){const{props:r,content:s}=n,o={delay:100,...r,...t,toastId:t.toastId||e,updateId:__()};o.toastId!==e&&(o.staleId=e);const a=o.render||s;delete o.render,_c(a,o)}},X.done=e=>{X.update(e,{progress:1})},X.onChange=function(e){return Dy.add(e),()=>{Dy.delete(e)}},X.play=e=>A0(!0,e),X.pause=e=>A0(!1,e);const e$=typeof window<"u"?v.useLayoutEffect:v.useEffect,Rf=e=>{let{theme:t,type:n,isLoading:r,...s}=e;return Te.createElement("svg",{viewBox:"0 0 24 24",width:"100%",height:"100%",fill:t==="colored"?"currentColor":`var(--toastify-icon-color-${n})`,...s})},Dm={info:function(e){return Te.createElement(Rf,{...e},Te.createElement("path",{d:"M12 0a12 12 0 1012 12A12.013 12.013 0 0012 0zm.25 5a1.5 1.5 0 11-1.5 1.5 1.5 1.5 0 011.5-1.5zm2.25 13.5h-4a1 1 0 010-2h.75a.25.25 0 00.25-.25v-4.5a.25.25 0 00-.25-.25h-.75a1 1 0 010-2h1a2 2 0 012 2v4.75a.25.25 0 00.25.25h.75a1 1 0 110 2z"}))},warning:function(e){return Te.createElement(Rf,{...e},Te.createElement("path",{d:"M23.32 17.191L15.438 2.184C14.728.833 13.416 0 11.996 0c-1.42 0-2.733.833-3.443 2.184L.533 17.448a4.744 4.744 0 000 4.368C1.243 23.167 2.555 24 3.975 24h16.05C22.22 24 24 22.044 24 19.632c0-.904-.251-1.746-.68-2.44zm-9.622 1.46c0 1.033-.724 1.823-1.698 1.823s-1.698-.79-1.698-1.822v-.043c0-1.028.724-1.822 1.698-1.822s1.698.79 1.698 1.822v.043zm.039-12.285l-.84 8.06c-.057.581-.408.943-.897.943-.49 0-.84-.367-.896-.942l-.84-8.065c-.057-.624.25-1.095.779-1.095h1.91c.528.005.84.476.784 1.1z"}))},success:function(e){return Te.createElement(Rf,{...e},Te.createElement("path",{d:"M12 0a12 12 0 1012 12A12.014 12.014 0 0012 0zm6.927 8.2l-6.845 9.289a1.011 1.011 0 01-1.43.188l-4.888-3.908a1 1 0 111.25-1.562l4.076 3.261 6.227-8.451a1 1 0 111.61 1.183z"}))},error:function(e){return Te.createElement(Rf,{...e},Te.createElement("path",{d:"M11.983 0a12.206 12.206 0 00-8.51 3.653A11.8 11.8 0 000 12.207 11.779 11.779 0 0011.8 24h.214A12.111 12.111 0 0024 11.791 11.766 11.766 0 0011.983 0zM10.5 16.542a1.476 1.476 0 011.449-1.53h.027a1.527 1.527 0 011.523 1.47 1.475 1.475 0 01-1.449 1.53h-.027a1.529 1.529 0 01-1.523-1.47zM11 12.5v-6a1 1 0 012 0v6a1 1 0 11-2 0z"}))},spinner:function(){return Te.createElement("div",{className:"Toastify__spinner"})}},t$=e=>{const{isRunning:t,preventExitTransition:n,toastRef:r,eventHandlers:s,playToast:o}=QL(e),{closeButton:a,children:l,autoClose:c,onClick:i,type:d,hideProgressBar:p,closeToast:f,transition:h,position:g,className:m,style:x,bodyClassName:b,bodyStyle:y,progressClassName:w,progressStyle:S,updateId:E,role:C,progress:k,rtl:T,toastId:P,deleteToast:N,isIn:U,isLoading:I,closeOnClick:Z,theme:V}=e,Q=oo("Toastify__toast",`Toastify__toast-theme--${V}`,`Toastify__toast--${d}`,{"Toastify__toast--rtl":T},{"Toastify__toast--close-on-click":Z}),ee=gr(m)?m({rtl:T,position:g,type:d,defaultClassName:Q}):oo(Q,m),W=function(de){let{theme:z,type:se,isLoading:ne,icon:ie}=de,oe=null;const J={theme:z,type:se};return ie===!1||(gr(ie)?oe=ie({...J,isLoading:ne}):v.isValidElement(ie)?oe=v.cloneElement(ie,J):ne?oe=Dm.spinner():(Ce=>Ce in Dm)(se)&&(oe=Dm[se](J))),oe}(e),F=!!k||!c,A={closeToast:f,type:d,theme:V};let Y=null;return a===!1||(Y=gr(a)?a(A):v.isValidElement(a)?v.cloneElement(a,A):function(de){let{closeToast:z,theme:se,ariaLabel:ne="close"}=de;return Te.createElement("button",{className:`Toastify__close-button Toastify__close-button--${se}`,type:"button",onClick:ie=>{ie.stopPropagation(),z(ie)},"aria-label":ne},Te.createElement("svg",{"aria-hidden":"true",viewBox:"0 0 14 16"},Te.createElement("path",{fillRule:"evenodd",d:"M7.71 8.23l3.75 3.75-1.48 1.48-3.75-3.75-3.75 3.75L1 11.98l3.75-3.75L1 4.48 2.48 3l3.75 3.75L9.98 3l1.48 1.48-3.75 3.75z"})))}(A)),Te.createElement(h,{isIn:U,done:N,position:g,preventExitTransition:n,nodeRef:r,playToast:o},Te.createElement("div",{id:P,onClick:i,"data-in":U,className:ee,...s,style:x,ref:r},Te.createElement("div",{...U&&{role:C},className:gr(b)?b({type:d}):oo("Toastify__toast-body",b),style:y},W!=null&&Te.createElement("div",{className:oo("Toastify__toast-icon",{"Toastify--animate-icon Toastify__zoom-enter":!I})},W),Te.createElement("div",null,l)),Y,Te.createElement(ZL,{...E&&!F?{key:`pb-${E}`}:{},rtl:T,theme:V,delay:c,isRunning:t,isIn:U,closeToast:f,hide:p,type:d,style:S,className:w,controlledProgress:F,progress:k||0})))},eg=function(e,t){return t===void 0&&(t=!1),{enter:`Toastify--animate Toastify__${e}-enter`,exit:`Toastify--animate Toastify__${e}-exit`,appendPosition:t}},n$=Xh(eg("bounce",!0));Xh(eg("slide",!0));Xh(eg("zoom"));Xh(eg("flip"));const r$={position:"top-right",transition:n$,autoClose:5e3,closeButton:!0,pauseOnHover:!0,pauseOnFocusLoss:!0,draggable:"touch",draggablePercent:80,draggableDirection:"x",role:"alert",theme:"light"};function s$(e){let t={...r$,...e};const n=e.stacked,[r,s]=v.useState(!0),o=v.useRef(null),{getToastToRender:a,isToastActive:l,count:c}=JL(t),{className:i,style:d,rtl:p,containerId:f}=t;function h(m){const x=oo("Toastify__toast-container",`Toastify__toast-container--${m}`,{"Toastify__toast-container--rtl":p});return gr(i)?i({position:m,rtl:p,defaultClassName:x}):oo(x,dp(i))}function g(){n&&(s(!0),X.play())}return e$(()=>{if(n){var m;const x=o.current.querySelectorAll('[data-in="true"]'),b=12,y=(m=t.position)==null?void 0:m.includes("top");let w=0,S=0;Array.from(x).reverse().forEach((E,C)=>{const k=E;k.classList.add("Toastify__toast--stacked"),C>0&&(k.dataset.collapsed=`${r}`),k.dataset.pos||(k.dataset.pos=y?"top":"bot");const T=w*(r?.2:1)+(r?0:b*C);k.style.setProperty("--y",`${y?T:-1*T}px`),k.style.setProperty("--g",`${b}`),k.style.setProperty("--s",""+(1-(r?S:0))),w+=k.offsetHeight,S+=.025})}},[r,c,n]),Te.createElement("div",{ref:o,className:"Toastify",id:f,onMouseEnter:()=>{n&&(s(!1),X.pause())},onMouseLeave:g},a((m,x)=>{const b=x.length?{...d}:{...d,pointerEvents:"none"};return Te.createElement("div",{className:h(m),style:b,key:`container-${m}`},x.map(y=>{let{content:w,props:S}=y;return Te.createElement(t$,{...S,stacked:n,collapseAll:g,isIn:l(S.toastId,S.containerId),style:S.style,key:`toast-${S.key}`},w)}))}))}const o$={theme:"system",setTheme:()=>null},j_=v.createContext(o$);function a$({children:e,defaultTheme:t="system",storageKey:n="vite-ui-theme",...r}){const[s,o]=v.useState(()=>localStorage.getItem(n)||t);v.useEffect(()=>{const l=window.document.documentElement;if(l.classList.remove("light","dark"),s==="system"){const c=window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light";l.classList.add(c);return}l.classList.add(s)},[s]);const a={theme:s,setTheme:l=>{localStorage.setItem(n,l),o(l)}};return u.jsx(j_.Provider,{...r,value:a,children:e})}const R_=()=>{const e=v.useContext(j_);if(e===void 0)throw new Error("useTheme must be used within a ThemeProvider");return e};let Am=!1;const i$=new RD({defaultOptions:{queries:{staleTime:1e3*60*5,retry(e){return e>=3?(Am===!1&&(Am=!0,X.error("The application is taking longer than expected to load, please try again in a few minutes.",{onClose:()=>{Am=!1}})),!1):!0}}}});var rs=(e=>(e.API_URL="apiUrl",e.TOKEN="token",e.VERSION="version",e.FACEBOOK_APP_ID="facebookAppId",e.FACEBOOK_CONFIG_ID="facebookConfigId",e.FACEBOOK_USER_TOKEN="facebookUserToken",e.CLIENT_NAME="clientName",e))(rs||{});const P_=async e=>{if(e.url){const t=e.url.endsWith("/")?e.url.slice(0,-1):e.url;localStorage.setItem("apiUrl",t)}e.token&&localStorage.setItem("token",e.token),e.version&&localStorage.setItem("version",e.version),e.facebookAppId&&localStorage.setItem("facebookAppId",e.facebookAppId),e.facebookConfigId&&localStorage.setItem("facebookConfigId",e.facebookConfigId),e.facebookUserToken&&localStorage.setItem("facebookUserToken",e.facebookUserToken),e.clientName&&localStorage.setItem("clientName",e.clientName)},M_=()=>{localStorage.removeItem("apiUrl"),localStorage.removeItem("token"),localStorage.removeItem("version"),localStorage.removeItem("facebookAppId"),localStorage.removeItem("facebookConfigId"),localStorage.removeItem("facebookUserToken"),localStorage.removeItem("clientName")},Fs=e=>localStorage.getItem(e),Gt=({children:e})=>{const t=Fs(rs.API_URL),n=Fs(rs.TOKEN),r=Fs(rs.VERSION);return!t||!n||!r?u.jsx(S_,{to:"/manager/login"}):e},l$=({children:e})=>{const t=Fs(rs.API_URL),n=Fs(rs.TOKEN),r=Fs(rs.VERSION);return t&&n&&r?u.jsx(S_,{to:"/"}):e};function O_(e,t){return function(){return e.apply(t,arguments)}}const{toString:u$}=Object.prototype,{getPrototypeOf:Mx}=Object,tg=(e=>t=>{const n=u$.call(t);return e[n]||(e[n]=n.slice(8,-1).toLowerCase())})(Object.create(null)),fs=e=>(e=e.toLowerCase(),t=>tg(t)===e),ng=e=>t=>typeof t===e,{isArray:hu}=Array,od=ng("undefined");function c$(e){return e!==null&&!od(e)&&e.constructor!==null&&!od(e.constructor)&&Lr(e.constructor.isBuffer)&&e.constructor.isBuffer(e)}const N_=fs("ArrayBuffer");function d$(e){let t;return typeof ArrayBuffer<"u"&&ArrayBuffer.isView?t=ArrayBuffer.isView(e):t=e&&e.buffer&&N_(e.buffer),t}const f$=ng("string"),Lr=ng("function"),I_=ng("number"),rg=e=>e!==null&&typeof e=="object",p$=e=>e===!0||e===!1,fp=e=>{if(tg(e)!=="object")return!1;const t=Mx(e);return(t===null||t===Object.prototype||Object.getPrototypeOf(t)===null)&&!(Symbol.toStringTag in e)&&!(Symbol.iterator in e)},h$=fs("Date"),g$=fs("File"),m$=fs("Blob"),v$=fs("FileList"),y$=e=>rg(e)&&Lr(e.pipe),b$=e=>{let t;return e&&(typeof FormData=="function"&&e instanceof FormData||Lr(e.append)&&((t=tg(e))==="formdata"||t==="object"&&Lr(e.toString)&&e.toString()==="[object FormData]"))},x$=fs("URLSearchParams"),[w$,S$,C$,E$]=["ReadableStream","Request","Response","Headers"].map(fs),T$=e=>e.trim?e.trim():e.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,"");function Bd(e,t,{allOwnKeys:n=!1}={}){if(e===null||typeof e>"u")return;let r,s;if(typeof e!="object"&&(e=[e]),hu(e))for(r=0,s=e.length;r0;)if(s=n[r],t===s.toLowerCase())return s;return null}const A_=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:global,F_=e=>!od(e)&&e!==A_;function Ay(){const{caseless:e}=F_(this)&&this||{},t={},n=(r,s)=>{const o=e&&D_(t,s)||s;fp(t[o])&&fp(r)?t[o]=Ay(t[o],r):fp(r)?t[o]=Ay({},r):hu(r)?t[o]=r.slice():t[o]=r};for(let r=0,s=arguments.length;r(Bd(t,(s,o)=>{n&&Lr(s)?e[o]=O_(s,n):e[o]=s},{allOwnKeys:r}),e),_$=e=>(e.charCodeAt(0)===65279&&(e=e.slice(1)),e),j$=(e,t,n,r)=>{e.prototype=Object.create(t.prototype,r),e.prototype.constructor=e,Object.defineProperty(e,"super",{value:t.prototype}),n&&Object.assign(e.prototype,n)},R$=(e,t,n,r)=>{let s,o,a;const l={};if(t=t||{},e==null)return t;do{for(s=Object.getOwnPropertyNames(e),o=s.length;o-- >0;)a=s[o],(!r||r(a,e,t))&&!l[a]&&(t[a]=e[a],l[a]=!0);e=n!==!1&&Mx(e)}while(e&&(!n||n(e,t))&&e!==Object.prototype);return t},P$=(e,t,n)=>{e=String(e),(n===void 0||n>e.length)&&(n=e.length),n-=t.length;const r=e.indexOf(t,n);return r!==-1&&r===n},M$=e=>{if(!e)return null;if(hu(e))return e;let t=e.length;if(!I_(t))return null;const n=new Array(t);for(;t-- >0;)n[t]=e[t];return n},O$=(e=>t=>e&&t instanceof e)(typeof Uint8Array<"u"&&Mx(Uint8Array)),N$=(e,t)=>{const r=(e&&e[Symbol.iterator]).call(e);let s;for(;(s=r.next())&&!s.done;){const o=s.value;t.call(e,o[0],o[1])}},I$=(e,t)=>{let n;const r=[];for(;(n=e.exec(t))!==null;)r.push(n);return r},D$=fs("HTMLFormElement"),A$=e=>e.toLowerCase().replace(/[-_\s]([a-z\d])(\w*)/g,function(n,r,s){return r.toUpperCase()+s}),F0=(({hasOwnProperty:e})=>(t,n)=>e.call(t,n))(Object.prototype),F$=fs("RegExp"),L_=(e,t)=>{const n=Object.getOwnPropertyDescriptors(e),r={};Bd(n,(s,o)=>{let a;(a=t(s,o,e))!==!1&&(r[o]=a||s)}),Object.defineProperties(e,r)},L$=e=>{L_(e,(t,n)=>{if(Lr(e)&&["arguments","caller","callee"].indexOf(n)!==-1)return!1;const r=e[n];if(Lr(r)){if(t.enumerable=!1,"writable"in t){t.writable=!1;return}t.set||(t.set=()=>{throw Error("Can not rewrite read-only method '"+n+"'")})}})},$$=(e,t)=>{const n={},r=s=>{s.forEach(o=>{n[o]=!0})};return hu(e)?r(e):r(String(e).split(t)),n},B$=()=>{},z$=(e,t)=>e!=null&&Number.isFinite(e=+e)?e:t,Fm="abcdefghijklmnopqrstuvwxyz",L0="0123456789",$_={DIGIT:L0,ALPHA:Fm,ALPHA_DIGIT:Fm+Fm.toUpperCase()+L0},U$=(e=16,t=$_.ALPHA_DIGIT)=>{let n="";const{length:r}=t;for(;e--;)n+=t[Math.random()*r|0];return n};function V$(e){return!!(e&&Lr(e.append)&&e[Symbol.toStringTag]==="FormData"&&e[Symbol.iterator])}const H$=e=>{const t=new Array(10),n=(r,s)=>{if(rg(r)){if(t.indexOf(r)>=0)return;if(!("toJSON"in r)){t[s]=r;const o=hu(r)?[]:{};return Bd(r,(a,l)=>{const c=n(a,s+1);!od(c)&&(o[l]=c)}),t[s]=void 0,o}}return r};return n(e,0)},K$=fs("AsyncFunction"),q$=e=>e&&(rg(e)||Lr(e))&&Lr(e.then)&&Lr(e.catch),$={isArray:hu,isArrayBuffer:N_,isBuffer:c$,isFormData:b$,isArrayBufferView:d$,isString:f$,isNumber:I_,isBoolean:p$,isObject:rg,isPlainObject:fp,isReadableStream:w$,isRequest:S$,isResponse:C$,isHeaders:E$,isUndefined:od,isDate:h$,isFile:g$,isBlob:m$,isRegExp:F$,isFunction:Lr,isStream:y$,isURLSearchParams:x$,isTypedArray:O$,isFileList:v$,forEach:Bd,merge:Ay,extend:k$,trim:T$,stripBOM:_$,inherits:j$,toFlatObject:R$,kindOf:tg,kindOfTest:fs,endsWith:P$,toArray:M$,forEachEntry:N$,matchAll:I$,isHTMLForm:D$,hasOwnProperty:F0,hasOwnProp:F0,reduceDescriptors:L_,freezeMethods:L$,toObjectSet:$$,toCamelCase:A$,noop:B$,toFiniteNumber:z$,findKey:D_,global:A_,isContextDefined:F_,ALPHABET:$_,generateString:U$,isSpecCompliantForm:V$,toJSONObject:H$,isAsyncFn:K$,isThenable:q$};function He(e,t,n,r,s){Error.call(this),Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):this.stack=new Error().stack,this.message=e,this.name="AxiosError",t&&(this.code=t),n&&(this.config=n),r&&(this.request=r),s&&(this.response=s)}$.inherits(He,Error,{toJSON:function(){return{message:this.message,name:this.name,description:this.description,number:this.number,fileName:this.fileName,lineNumber:this.lineNumber,columnNumber:this.columnNumber,stack:this.stack,config:$.toJSONObject(this.config),code:this.code,status:this.response&&this.response.status?this.response.status:null}}});const B_=He.prototype,z_={};["ERR_BAD_OPTION_VALUE","ERR_BAD_OPTION","ECONNABORTED","ETIMEDOUT","ERR_NETWORK","ERR_FR_TOO_MANY_REDIRECTS","ERR_DEPRECATED","ERR_BAD_RESPONSE","ERR_BAD_REQUEST","ERR_CANCELED","ERR_NOT_SUPPORT","ERR_INVALID_URL"].forEach(e=>{z_[e]={value:e}});Object.defineProperties(He,z_);Object.defineProperty(B_,"isAxiosError",{value:!0});He.from=(e,t,n,r,s,o)=>{const a=Object.create(B_);return $.toFlatObject(e,a,function(c){return c!==Error.prototype},l=>l!=="isAxiosError"),He.call(a,e.message,t,n,r,s),a.cause=e,a.name=e.name,o&&Object.assign(a,o),a};const W$=null;function Fy(e){return $.isPlainObject(e)||$.isArray(e)}function U_(e){return $.endsWith(e,"[]")?e.slice(0,-2):e}function $0(e,t,n){return e?e.concat(t).map(function(s,o){return s=U_(s),!n&&o?"["+s+"]":s}).join(n?".":""):t}function G$(e){return $.isArray(e)&&!e.some(Fy)}const J$=$.toFlatObject($,{},null,function(t){return/^is[A-Z]/.test(t)});function sg(e,t,n){if(!$.isObject(e))throw new TypeError("target must be an object");t=t||new FormData,n=$.toFlatObject(n,{metaTokens:!0,dots:!1,indexes:!1},!1,function(m,x){return!$.isUndefined(x[m])});const r=n.metaTokens,s=n.visitor||d,o=n.dots,a=n.indexes,c=(n.Blob||typeof Blob<"u"&&Blob)&&$.isSpecCompliantForm(t);if(!$.isFunction(s))throw new TypeError("visitor must be a function");function i(g){if(g===null)return"";if($.isDate(g))return g.toISOString();if(!c&&$.isBlob(g))throw new He("Blob is not supported. Use a Buffer instead.");return $.isArrayBuffer(g)||$.isTypedArray(g)?c&&typeof Blob=="function"?new Blob([g]):Buffer.from(g):g}function d(g,m,x){let b=g;if(g&&!x&&typeof g=="object"){if($.endsWith(m,"{}"))m=r?m:m.slice(0,-2),g=JSON.stringify(g);else if($.isArray(g)&&G$(g)||($.isFileList(g)||$.endsWith(m,"[]"))&&(b=$.toArray(g)))return m=U_(m),b.forEach(function(w,S){!($.isUndefined(w)||w===null)&&t.append(a===!0?$0([m],S,o):a===null?m:m+"[]",i(w))}),!1}return Fy(g)?!0:(t.append($0(x,m,o),i(g)),!1)}const p=[],f=Object.assign(J$,{defaultVisitor:d,convertValue:i,isVisitable:Fy});function h(g,m){if(!$.isUndefined(g)){if(p.indexOf(g)!==-1)throw Error("Circular reference detected in "+m.join("."));p.push(g),$.forEach(g,function(b,y){(!($.isUndefined(b)||b===null)&&s.call(t,b,$.isString(y)?y.trim():y,m,f))===!0&&h(b,m?m.concat(y):[y])}),p.pop()}}if(!$.isObject(e))throw new TypeError("data must be an object");return h(e),t}function B0(e){const t={"!":"%21","'":"%27","(":"%28",")":"%29","~":"%7E","%20":"+","%00":"\0"};return encodeURIComponent(e).replace(/[!'()~]|%20|%00/g,function(r){return t[r]})}function Ox(e,t){this._pairs=[],e&&sg(e,this,t)}const V_=Ox.prototype;V_.append=function(t,n){this._pairs.push([t,n])};V_.toString=function(t){const n=t?function(r){return t.call(this,r,B0)}:B0;return this._pairs.map(function(s){return n(s[0])+"="+n(s[1])},"").join("&")};function Q$(e){return encodeURIComponent(e).replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+").replace(/%5B/gi,"[").replace(/%5D/gi,"]")}function H_(e,t,n){if(!t)return e;const r=n&&n.encode||Q$,s=n&&n.serialize;let o;if(s?o=s(t,n):o=$.isURLSearchParams(t)?t.toString():new Ox(t,n).toString(r),o){const a=e.indexOf("#");a!==-1&&(e=e.slice(0,a)),e+=(e.indexOf("?")===-1?"?":"&")+o}return e}class z0{constructor(){this.handlers=[]}use(t,n,r){return this.handlers.push({fulfilled:t,rejected:n,synchronous:r?r.synchronous:!1,runWhen:r?r.runWhen:null}),this.handlers.length-1}eject(t){this.handlers[t]&&(this.handlers[t]=null)}clear(){this.handlers&&(this.handlers=[])}forEach(t){$.forEach(this.handlers,function(r){r!==null&&t(r)})}}const K_={silentJSONParsing:!0,forcedJSONParsing:!0,clarifyTimeoutError:!1},Z$=typeof URLSearchParams<"u"?URLSearchParams:Ox,Y$=typeof FormData<"u"?FormData:null,X$=typeof Blob<"u"?Blob:null,e4={isBrowser:!0,classes:{URLSearchParams:Z$,FormData:Y$,Blob:X$},protocols:["http","https","file","blob","url","data"]},Nx=typeof window<"u"&&typeof document<"u",t4=(e=>Nx&&["ReactNative","NativeScript","NS"].indexOf(e)<0)(typeof navigator<"u"&&navigator.product),n4=typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope&&typeof self.importScripts=="function",r4=Nx&&window.location.href||"http://localhost",s4=Object.freeze(Object.defineProperty({__proto__:null,hasBrowserEnv:Nx,hasStandardBrowserEnv:t4,hasStandardBrowserWebWorkerEnv:n4,origin:r4},Symbol.toStringTag,{value:"Module"})),ss={...s4,...e4};function o4(e,t){return sg(e,new ss.classes.URLSearchParams,Object.assign({visitor:function(n,r,s,o){return ss.isNode&&$.isBuffer(n)?(this.append(r,n.toString("base64")),!1):o.defaultVisitor.apply(this,arguments)}},t))}function a4(e){return $.matchAll(/\w+|\[(\w*)]/g,e).map(t=>t[0]==="[]"?"":t[1]||t[0])}function i4(e){const t={},n=Object.keys(e);let r;const s=n.length;let o;for(r=0;r=n.length;return a=!a&&$.isArray(s)?s.length:a,c?($.hasOwnProp(s,a)?s[a]=[s[a],r]:s[a]=r,!l):((!s[a]||!$.isObject(s[a]))&&(s[a]=[]),t(n,r,s[a],o)&&$.isArray(s[a])&&(s[a]=i4(s[a])),!l)}if($.isFormData(e)&&$.isFunction(e.entries)){const n={};return $.forEachEntry(e,(r,s)=>{t(a4(r),s,n,0)}),n}return null}function l4(e,t,n){if($.isString(e))try{return(t||JSON.parse)(e),$.trim(e)}catch(r){if(r.name!=="SyntaxError")throw r}return(n||JSON.stringify)(e)}const zd={transitional:K_,adapter:["xhr","http","fetch"],transformRequest:[function(t,n){const r=n.getContentType()||"",s=r.indexOf("application/json")>-1,o=$.isObject(t);if(o&&$.isHTMLForm(t)&&(t=new FormData(t)),$.isFormData(t))return s?JSON.stringify(q_(t)):t;if($.isArrayBuffer(t)||$.isBuffer(t)||$.isStream(t)||$.isFile(t)||$.isBlob(t)||$.isReadableStream(t))return t;if($.isArrayBufferView(t))return t.buffer;if($.isURLSearchParams(t))return n.setContentType("application/x-www-form-urlencoded;charset=utf-8",!1),t.toString();let l;if(o){if(r.indexOf("application/x-www-form-urlencoded")>-1)return o4(t,this.formSerializer).toString();if((l=$.isFileList(t))||r.indexOf("multipart/form-data")>-1){const c=this.env&&this.env.FormData;return sg(l?{"files[]":t}:t,c&&new c,this.formSerializer)}}return o||s?(n.setContentType("application/json",!1),l4(t)):t}],transformResponse:[function(t){const n=this.transitional||zd.transitional,r=n&&n.forcedJSONParsing,s=this.responseType==="json";if($.isResponse(t)||$.isReadableStream(t))return t;if(t&&$.isString(t)&&(r&&!this.responseType||s)){const a=!(n&&n.silentJSONParsing)&&s;try{return JSON.parse(t)}catch(l){if(a)throw l.name==="SyntaxError"?He.from(l,He.ERR_BAD_RESPONSE,this,null,this.response):l}}return t}],timeout:0,xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",maxContentLength:-1,maxBodyLength:-1,env:{FormData:ss.classes.FormData,Blob:ss.classes.Blob},validateStatus:function(t){return t>=200&&t<300},headers:{common:{Accept:"application/json, text/plain, */*","Content-Type":void 0}}};$.forEach(["delete","get","head","post","put","patch"],e=>{zd.headers[e]={}});const u4=$.toObjectSet(["age","authorization","content-length","content-type","etag","expires","from","host","if-modified-since","if-unmodified-since","last-modified","location","max-forwards","proxy-authorization","referer","retry-after","user-agent"]),c4=e=>{const t={};let n,r,s;return e&&e.split(` +`).forEach(function(a){s=a.indexOf(":"),n=a.substring(0,s).trim().toLowerCase(),r=a.substring(s+1).trim(),!(!n||t[n]&&u4[n])&&(n==="set-cookie"?t[n]?t[n].push(r):t[n]=[r]:t[n]=t[n]?t[n]+", "+r:r)}),t},U0=Symbol("internals");function Gu(e){return e&&String(e).trim().toLowerCase()}function pp(e){return e===!1||e==null?e:$.isArray(e)?e.map(pp):String(e)}function d4(e){const t=Object.create(null),n=/([^\s,;=]+)\s*(?:=\s*([^,;]+))?/g;let r;for(;r=n.exec(e);)t[r[1]]=r[2];return t}const f4=e=>/^[-_a-zA-Z0-9^`|~,!#$%&'*+.]+$/.test(e.trim());function Lm(e,t,n,r,s){if($.isFunction(r))return r.call(this,t,n);if(s&&(t=n),!!$.isString(t)){if($.isString(r))return t.indexOf(r)!==-1;if($.isRegExp(r))return r.test(t)}}function p4(e){return e.trim().toLowerCase().replace(/([a-z\d])(\w*)/g,(t,n,r)=>n.toUpperCase()+r)}function h4(e,t){const n=$.toCamelCase(" "+t);["get","set","has"].forEach(r=>{Object.defineProperty(e,r+n,{value:function(s,o,a){return this[r].call(this,t,s,o,a)},configurable:!0})})}let sr=class{constructor(t){t&&this.set(t)}set(t,n,r){const s=this;function o(l,c,i){const d=Gu(c);if(!d)throw new Error("header name must be a non-empty string");const p=$.findKey(s,d);(!p||s[p]===void 0||i===!0||i===void 0&&s[p]!==!1)&&(s[p||c]=pp(l))}const a=(l,c)=>$.forEach(l,(i,d)=>o(i,d,c));if($.isPlainObject(t)||t instanceof this.constructor)a(t,n);else if($.isString(t)&&(t=t.trim())&&!f4(t))a(c4(t),n);else if($.isHeaders(t))for(const[l,c]of t.entries())o(c,l,r);else t!=null&&o(n,t,r);return this}get(t,n){if(t=Gu(t),t){const r=$.findKey(this,t);if(r){const s=this[r];if(!n)return s;if(n===!0)return d4(s);if($.isFunction(n))return n.call(this,s,r);if($.isRegExp(n))return n.exec(s);throw new TypeError("parser must be boolean|regexp|function")}}}has(t,n){if(t=Gu(t),t){const r=$.findKey(this,t);return!!(r&&this[r]!==void 0&&(!n||Lm(this,this[r],r,n)))}return!1}delete(t,n){const r=this;let s=!1;function o(a){if(a=Gu(a),a){const l=$.findKey(r,a);l&&(!n||Lm(r,r[l],l,n))&&(delete r[l],s=!0)}}return $.isArray(t)?t.forEach(o):o(t),s}clear(t){const n=Object.keys(this);let r=n.length,s=!1;for(;r--;){const o=n[r];(!t||Lm(this,this[o],o,t,!0))&&(delete this[o],s=!0)}return s}normalize(t){const n=this,r={};return $.forEach(this,(s,o)=>{const a=$.findKey(r,o);if(a){n[a]=pp(s),delete n[o];return}const l=t?p4(o):String(o).trim();l!==o&&delete n[o],n[l]=pp(s),r[l]=!0}),this}concat(...t){return this.constructor.concat(this,...t)}toJSON(t){const n=Object.create(null);return $.forEach(this,(r,s)=>{r!=null&&r!==!1&&(n[s]=t&&$.isArray(r)?r.join(", "):r)}),n}[Symbol.iterator](){return Object.entries(this.toJSON())[Symbol.iterator]()}toString(){return Object.entries(this.toJSON()).map(([t,n])=>t+": "+n).join(` +`)}get[Symbol.toStringTag](){return"AxiosHeaders"}static from(t){return t instanceof this?t:new this(t)}static concat(t,...n){const r=new this(t);return n.forEach(s=>r.set(s)),r}static accessor(t){const r=(this[U0]=this[U0]={accessors:{}}).accessors,s=this.prototype;function o(a){const l=Gu(a);r[l]||(h4(s,a),r[l]=!0)}return $.isArray(t)?t.forEach(o):o(t),this}};sr.accessor(["Content-Type","Content-Length","Accept","Accept-Encoding","User-Agent","Authorization"]);$.reduceDescriptors(sr.prototype,({value:e},t)=>{let n=t[0].toUpperCase()+t.slice(1);return{get:()=>e,set(r){this[n]=r}}});$.freezeMethods(sr);function $m(e,t){const n=this||zd,r=t||n,s=sr.from(r.headers);let o=r.data;return $.forEach(e,function(l){o=l.call(n,o,s.normalize(),t?t.status:void 0)}),s.normalize(),o}function W_(e){return!!(e&&e.__CANCEL__)}function gu(e,t,n){He.call(this,e??"canceled",He.ERR_CANCELED,t,n),this.name="CanceledError"}$.inherits(gu,He,{__CANCEL__:!0});function G_(e,t,n){const r=n.config.validateStatus;!n.status||!r||r(n.status)?e(n):t(new He("Request failed with status code "+n.status,[He.ERR_BAD_REQUEST,He.ERR_BAD_RESPONSE][Math.floor(n.status/100)-4],n.config,n.request,n))}function g4(e){const t=/^([-+\w]{1,25})(:?\/\/|:)/.exec(e);return t&&t[1]||""}function m4(e,t){e=e||10;const n=new Array(e),r=new Array(e);let s=0,o=0,a;return t=t!==void 0?t:1e3,function(c){const i=Date.now(),d=r[o];a||(a=i),n[s]=c,r[s]=i;let p=o,f=0;for(;p!==s;)f+=n[p++],p=p%e;if(s=(s+1)%e,s===o&&(o=(o+1)%e),i-ar)return s&&(clearTimeout(s),s=null),n=l,e.apply(null,arguments);s||(s=setTimeout(()=>(s=null,n=Date.now(),e.apply(null,arguments)),r-(l-n)))}}const eh=(e,t,n=3)=>{let r=0;const s=m4(50,250);return v4(o=>{const a=o.loaded,l=o.lengthComputable?o.total:void 0,c=a-r,i=s(c),d=a<=l;r=a;const p={loaded:a,total:l,progress:l?a/l:void 0,bytes:c,rate:i||void 0,estimated:i&&l&&d?(l-a)/i:void 0,event:o,lengthComputable:l!=null};p[t?"download":"upload"]=!0,e(p)},n)},y4=ss.hasStandardBrowserEnv?function(){const t=/(msie|trident)/i.test(navigator.userAgent),n=document.createElement("a");let r;function s(o){let a=o;return t&&(n.setAttribute("href",a),a=n.href),n.setAttribute("href",a),{href:n.href,protocol:n.protocol?n.protocol.replace(/:$/,""):"",host:n.host,search:n.search?n.search.replace(/^\?/,""):"",hash:n.hash?n.hash.replace(/^#/,""):"",hostname:n.hostname,port:n.port,pathname:n.pathname.charAt(0)==="/"?n.pathname:"/"+n.pathname}}return r=s(window.location.href),function(a){const l=$.isString(a)?s(a):a;return l.protocol===r.protocol&&l.host===r.host}}():function(){return function(){return!0}}(),b4=ss.hasStandardBrowserEnv?{write(e,t,n,r,s,o){const a=[e+"="+encodeURIComponent(t)];$.isNumber(n)&&a.push("expires="+new Date(n).toGMTString()),$.isString(r)&&a.push("path="+r),$.isString(s)&&a.push("domain="+s),o===!0&&a.push("secure"),document.cookie=a.join("; ")},read(e){const t=document.cookie.match(new RegExp("(^|;\\s*)("+e+")=([^;]*)"));return t?decodeURIComponent(t[3]):null},remove(e){this.write(e,"",Date.now()-864e5)}}:{write(){},read(){return null},remove(){}};function x4(e){return/^([a-z][a-z\d+\-.]*:)?\/\//i.test(e)}function w4(e,t){return t?e.replace(/\/?\/$/,"")+"/"+t.replace(/^\/+/,""):e}function J_(e,t){return e&&!x4(t)?w4(e,t):t}const V0=e=>e instanceof sr?{...e}:e;function Si(e,t){t=t||{};const n={};function r(i,d,p){return $.isPlainObject(i)&&$.isPlainObject(d)?$.merge.call({caseless:p},i,d):$.isPlainObject(d)?$.merge({},d):$.isArray(d)?d.slice():d}function s(i,d,p){if($.isUndefined(d)){if(!$.isUndefined(i))return r(void 0,i,p)}else return r(i,d,p)}function o(i,d){if(!$.isUndefined(d))return r(void 0,d)}function a(i,d){if($.isUndefined(d)){if(!$.isUndefined(i))return r(void 0,i)}else return r(void 0,d)}function l(i,d,p){if(p in t)return r(i,d);if(p in e)return r(void 0,i)}const c={url:o,method:o,data:o,baseURL:a,transformRequest:a,transformResponse:a,paramsSerializer:a,timeout:a,timeoutMessage:a,withCredentials:a,withXSRFToken:a,adapter:a,responseType:a,xsrfCookieName:a,xsrfHeaderName:a,onUploadProgress:a,onDownloadProgress:a,decompress:a,maxContentLength:a,maxBodyLength:a,beforeRedirect:a,transport:a,httpAgent:a,httpsAgent:a,cancelToken:a,socketPath:a,responseEncoding:a,validateStatus:l,headers:(i,d)=>s(V0(i),V0(d),!0)};return $.forEach(Object.keys(Object.assign({},e,t)),function(d){const p=c[d]||s,f=p(e[d],t[d],d);$.isUndefined(f)&&p!==l||(n[d]=f)}),n}const Q_=e=>{const t=Si({},e);let{data:n,withXSRFToken:r,xsrfHeaderName:s,xsrfCookieName:o,headers:a,auth:l}=t;t.headers=a=sr.from(a),t.url=H_(J_(t.baseURL,t.url),e.params,e.paramsSerializer),l&&a.set("Authorization","Basic "+btoa((l.username||"")+":"+(l.password?unescape(encodeURIComponent(l.password)):"")));let c;if($.isFormData(n)){if(ss.hasStandardBrowserEnv||ss.hasStandardBrowserWebWorkerEnv)a.setContentType(void 0);else if((c=a.getContentType())!==!1){const[i,...d]=c?c.split(";").map(p=>p.trim()).filter(Boolean):[];a.setContentType([i||"multipart/form-data",...d].join("; "))}}if(ss.hasStandardBrowserEnv&&(r&&$.isFunction(r)&&(r=r(t)),r||r!==!1&&y4(t.url))){const i=s&&o&&b4.read(o);i&&a.set(s,i)}return t},S4=typeof XMLHttpRequest<"u",C4=S4&&function(e){return new Promise(function(n,r){const s=Q_(e);let o=s.data;const a=sr.from(s.headers).normalize();let{responseType:l}=s,c;function i(){s.cancelToken&&s.cancelToken.unsubscribe(c),s.signal&&s.signal.removeEventListener("abort",c)}let d=new XMLHttpRequest;d.open(s.method.toUpperCase(),s.url,!0),d.timeout=s.timeout;function p(){if(!d)return;const h=sr.from("getAllResponseHeaders"in d&&d.getAllResponseHeaders()),m={data:!l||l==="text"||l==="json"?d.responseText:d.response,status:d.status,statusText:d.statusText,headers:h,config:e,request:d};G_(function(b){n(b),i()},function(b){r(b),i()},m),d=null}"onloadend"in d?d.onloadend=p:d.onreadystatechange=function(){!d||d.readyState!==4||d.status===0&&!(d.responseURL&&d.responseURL.indexOf("file:")===0)||setTimeout(p)},d.onabort=function(){d&&(r(new He("Request aborted",He.ECONNABORTED,s,d)),d=null)},d.onerror=function(){r(new He("Network Error",He.ERR_NETWORK,s,d)),d=null},d.ontimeout=function(){let g=s.timeout?"timeout of "+s.timeout+"ms exceeded":"timeout exceeded";const m=s.transitional||K_;s.timeoutErrorMessage&&(g=s.timeoutErrorMessage),r(new He(g,m.clarifyTimeoutError?He.ETIMEDOUT:He.ECONNABORTED,s,d)),d=null},o===void 0&&a.setContentType(null),"setRequestHeader"in d&&$.forEach(a.toJSON(),function(g,m){d.setRequestHeader(m,g)}),$.isUndefined(s.withCredentials)||(d.withCredentials=!!s.withCredentials),l&&l!=="json"&&(d.responseType=s.responseType),typeof s.onDownloadProgress=="function"&&d.addEventListener("progress",eh(s.onDownloadProgress,!0)),typeof s.onUploadProgress=="function"&&d.upload&&d.upload.addEventListener("progress",eh(s.onUploadProgress)),(s.cancelToken||s.signal)&&(c=h=>{d&&(r(!h||h.type?new gu(null,e,d):h),d.abort(),d=null)},s.cancelToken&&s.cancelToken.subscribe(c),s.signal&&(s.signal.aborted?c():s.signal.addEventListener("abort",c)));const f=g4(s.url);if(f&&ss.protocols.indexOf(f)===-1){r(new He("Unsupported protocol "+f+":",He.ERR_BAD_REQUEST,e));return}d.send(o||null)})},E4=(e,t)=>{let n=new AbortController,r;const s=function(c){if(!r){r=!0,a();const i=c instanceof Error?c:this.reason;n.abort(i instanceof He?i:new gu(i instanceof Error?i.message:i))}};let o=t&&setTimeout(()=>{s(new He(`timeout ${t} of ms exceeded`,He.ETIMEDOUT))},t);const a=()=>{e&&(o&&clearTimeout(o),o=null,e.forEach(c=>{c&&(c.removeEventListener?c.removeEventListener("abort",s):c.unsubscribe(s))}),e=null)};e.forEach(c=>c&&c.addEventListener&&c.addEventListener("abort",s));const{signal:l}=n;return l.unsubscribe=a,[l,()=>{o&&clearTimeout(o),o=null}]},T4=function*(e,t){let n=e.byteLength;if(!t||n{const o=k4(e,t,s);let a=0;return new ReadableStream({type:"bytes",async pull(l){const{done:c,value:i}=await o.next();if(c){l.close(),r();return}let d=i.byteLength;n&&n(a+=d),l.enqueue(new Uint8Array(i))},cancel(l){return r(l),o.return()}},{highWaterMark:2})},K0=(e,t)=>{const n=e!=null;return r=>setTimeout(()=>t({lengthComputable:n,total:e,loaded:r}))},og=typeof fetch=="function"&&typeof Request=="function"&&typeof Response=="function",Z_=og&&typeof ReadableStream=="function",Ly=og&&(typeof TextEncoder=="function"?(e=>t=>e.encode(t))(new TextEncoder):async e=>new Uint8Array(await new Response(e).arrayBuffer())),_4=Z_&&(()=>{let e=!1;const t=new Request(ss.origin,{body:new ReadableStream,method:"POST",get duplex(){return e=!0,"half"}}).headers.has("Content-Type");return e&&!t})(),q0=64*1024,$y=Z_&&!!(()=>{try{return $.isReadableStream(new Response("").body)}catch{}})(),th={stream:$y&&(e=>e.body)};og&&(e=>{["text","arrayBuffer","blob","formData","stream"].forEach(t=>{!th[t]&&(th[t]=$.isFunction(e[t])?n=>n[t]():(n,r)=>{throw new He(`Response type '${t}' is not supported`,He.ERR_NOT_SUPPORT,r)})})})(new Response);const j4=async e=>{if(e==null)return 0;if($.isBlob(e))return e.size;if($.isSpecCompliantForm(e))return(await new Request(e).arrayBuffer()).byteLength;if($.isArrayBufferView(e))return e.byteLength;if($.isURLSearchParams(e)&&(e=e+""),$.isString(e))return(await Ly(e)).byteLength},R4=async(e,t)=>{const n=$.toFiniteNumber(e.getContentLength());return n??j4(t)},P4=og&&(async e=>{let{url:t,method:n,data:r,signal:s,cancelToken:o,timeout:a,onDownloadProgress:l,onUploadProgress:c,responseType:i,headers:d,withCredentials:p="same-origin",fetchOptions:f}=Q_(e);i=i?(i+"").toLowerCase():"text";let[h,g]=s||o||a?E4([s,o],a):[],m,x;const b=()=>{!m&&setTimeout(()=>{h&&h.unsubscribe()}),m=!0};let y;try{if(c&&_4&&n!=="get"&&n!=="head"&&(y=await R4(d,r))!==0){let C=new Request(t,{method:"POST",body:r,duplex:"half"}),k;$.isFormData(r)&&(k=C.headers.get("content-type"))&&d.setContentType(k),C.body&&(r=H0(C.body,q0,K0(y,eh(c)),null,Ly))}$.isString(p)||(p=p?"cors":"omit"),x=new Request(t,{...f,signal:h,method:n.toUpperCase(),headers:d.normalize().toJSON(),body:r,duplex:"half",withCredentials:p});let w=await fetch(x);const S=$y&&(i==="stream"||i==="response");if($y&&(l||S)){const C={};["status","statusText","headers"].forEach(T=>{C[T]=w[T]});const k=$.toFiniteNumber(w.headers.get("content-length"));w=new Response(H0(w.body,q0,l&&K0(k,eh(l,!0)),S&&b,Ly),C)}i=i||"text";let E=await th[$.findKey(th,i)||"text"](w,e);return!S&&b(),g&&g(),await new Promise((C,k)=>{G_(C,k,{data:E,headers:sr.from(w.headers),status:w.status,statusText:w.statusText,config:e,request:x})})}catch(w){throw b(),w&&w.name==="TypeError"&&/fetch/i.test(w.message)?Object.assign(new He("Network Error",He.ERR_NETWORK,e,x),{cause:w.cause||w}):He.from(w,w&&w.code,e,x)}}),By={http:W$,xhr:C4,fetch:P4};$.forEach(By,(e,t)=>{if(e){try{Object.defineProperty(e,"name",{value:t})}catch{}Object.defineProperty(e,"adapterName",{value:t})}});const W0=e=>`- ${e}`,M4=e=>$.isFunction(e)||e===null||e===!1,Y_={getAdapter:e=>{e=$.isArray(e)?e:[e];const{length:t}=e;let n,r;const s={};for(let o=0;o`adapter ${l} `+(c===!1?"is not supported by the environment":"is not available in the build"));let a=t?o.length>1?`since : +`+o.map(W0).join(` +`):" "+W0(o[0]):"as no adapter specified";throw new He("There is no suitable adapter to dispatch the request "+a,"ERR_NOT_SUPPORT")}return r},adapters:By};function Bm(e){if(e.cancelToken&&e.cancelToken.throwIfRequested(),e.signal&&e.signal.aborted)throw new gu(null,e)}function G0(e){return Bm(e),e.headers=sr.from(e.headers),e.data=$m.call(e,e.transformRequest),["post","put","patch"].indexOf(e.method)!==-1&&e.headers.setContentType("application/x-www-form-urlencoded",!1),Y_.getAdapter(e.adapter||zd.adapter)(e).then(function(r){return Bm(e),r.data=$m.call(e,e.transformResponse,r),r.headers=sr.from(r.headers),r},function(r){return W_(r)||(Bm(e),r&&r.response&&(r.response.data=$m.call(e,e.transformResponse,r.response),r.response.headers=sr.from(r.response.headers))),Promise.reject(r)})}const X_="1.7.2",Ix={};["object","boolean","number","function","string","symbol"].forEach((e,t)=>{Ix[e]=function(r){return typeof r===e||"a"+(t<1?"n ":" ")+e}});const J0={};Ix.transitional=function(t,n,r){function s(o,a){return"[Axios v"+X_+"] Transitional option '"+o+"'"+a+(r?". "+r:"")}return(o,a,l)=>{if(t===!1)throw new He(s(a," has been removed"+(n?" in "+n:"")),He.ERR_DEPRECATED);return n&&!J0[a]&&(J0[a]=!0,console.warn(s(a," has been deprecated since v"+n+" and will be removed in the near future"))),t?t(o,a,l):!0}};function O4(e,t,n){if(typeof e!="object")throw new He("options must be an object",He.ERR_BAD_OPTION_VALUE);const r=Object.keys(e);let s=r.length;for(;s-- >0;){const o=r[s],a=t[o];if(a){const l=e[o],c=l===void 0||a(l,o,e);if(c!==!0)throw new He("option "+o+" must be "+c,He.ERR_BAD_OPTION_VALUE);continue}if(n!==!0)throw new He("Unknown option "+o,He.ERR_BAD_OPTION)}}const zy={assertOptions:O4,validators:Ix},Oo=zy.validators;let di=class{constructor(t){this.defaults=t,this.interceptors={request:new z0,response:new z0}}async request(t,n){try{return await this._request(t,n)}catch(r){if(r instanceof Error){let s;Error.captureStackTrace?Error.captureStackTrace(s={}):s=new Error;const o=s.stack?s.stack.replace(/^.+\n/,""):"";try{r.stack?o&&!String(r.stack).endsWith(o.replace(/^.+\n.+\n/,""))&&(r.stack+=` +`+o):r.stack=o}catch{}}throw r}}_request(t,n){typeof t=="string"?(n=n||{},n.url=t):n=t||{},n=Si(this.defaults,n);const{transitional:r,paramsSerializer:s,headers:o}=n;r!==void 0&&zy.assertOptions(r,{silentJSONParsing:Oo.transitional(Oo.boolean),forcedJSONParsing:Oo.transitional(Oo.boolean),clarifyTimeoutError:Oo.transitional(Oo.boolean)},!1),s!=null&&($.isFunction(s)?n.paramsSerializer={serialize:s}:zy.assertOptions(s,{encode:Oo.function,serialize:Oo.function},!0)),n.method=(n.method||this.defaults.method||"get").toLowerCase();let a=o&&$.merge(o.common,o[n.method]);o&&$.forEach(["delete","get","head","post","put","patch","common"],g=>{delete o[g]}),n.headers=sr.concat(a,o);const l=[];let c=!0;this.interceptors.request.forEach(function(m){typeof m.runWhen=="function"&&m.runWhen(n)===!1||(c=c&&m.synchronous,l.unshift(m.fulfilled,m.rejected))});const i=[];this.interceptors.response.forEach(function(m){i.push(m.fulfilled,m.rejected)});let d,p=0,f;if(!c){const g=[G0.bind(this),void 0];for(g.unshift.apply(g,l),g.push.apply(g,i),f=g.length,d=Promise.resolve(n);p{if(!r._listeners)return;let o=r._listeners.length;for(;o-- >0;)r._listeners[o](s);r._listeners=null}),this.promise.then=s=>{let o;const a=new Promise(l=>{r.subscribe(l),o=l}).then(s);return a.cancel=function(){r.unsubscribe(o)},a},t(function(o,a,l){r.reason||(r.reason=new gu(o,a,l),n(r.reason))})}throwIfRequested(){if(this.reason)throw this.reason}subscribe(t){if(this.reason){t(this.reason);return}this._listeners?this._listeners.push(t):this._listeners=[t]}unsubscribe(t){if(!this._listeners)return;const n=this._listeners.indexOf(t);n!==-1&&this._listeners.splice(n,1)}static source(){let t;return{token:new ej(function(s){t=s}),cancel:t}}};function I4(e){return function(n){return e.apply(null,n)}}function D4(e){return $.isObject(e)&&e.isAxiosError===!0}const Uy={Continue:100,SwitchingProtocols:101,Processing:102,EarlyHints:103,Ok:200,Created:201,Accepted:202,NonAuthoritativeInformation:203,NoContent:204,ResetContent:205,PartialContent:206,MultiStatus:207,AlreadyReported:208,ImUsed:226,MultipleChoices:300,MovedPermanently:301,Found:302,SeeOther:303,NotModified:304,UseProxy:305,Unused:306,TemporaryRedirect:307,PermanentRedirect:308,BadRequest:400,Unauthorized:401,PaymentRequired:402,Forbidden:403,NotFound:404,MethodNotAllowed:405,NotAcceptable:406,ProxyAuthenticationRequired:407,RequestTimeout:408,Conflict:409,Gone:410,LengthRequired:411,PreconditionFailed:412,PayloadTooLarge:413,UriTooLong:414,UnsupportedMediaType:415,RangeNotSatisfiable:416,ExpectationFailed:417,ImATeapot:418,MisdirectedRequest:421,UnprocessableEntity:422,Locked:423,FailedDependency:424,TooEarly:425,UpgradeRequired:426,PreconditionRequired:428,TooManyRequests:429,RequestHeaderFieldsTooLarge:431,UnavailableForLegalReasons:451,InternalServerError:500,NotImplemented:501,BadGateway:502,ServiceUnavailable:503,GatewayTimeout:504,HttpVersionNotSupported:505,VariantAlsoNegotiates:506,InsufficientStorage:507,LoopDetected:508,NotExtended:510,NetworkAuthenticationRequired:511};Object.entries(Uy).forEach(([e,t])=>{Uy[t]=e});function tj(e){const t=new di(e),n=O_(di.prototype.request,t);return $.extend(n,di.prototype,t,{allOwnKeys:!0}),$.extend(n,t,null,{allOwnKeys:!0}),n.create=function(s){return tj(Si(e,s))},n}const zt=tj(zd);zt.Axios=di;zt.CanceledError=gu;zt.CancelToken=N4;zt.isCancel=W_;zt.VERSION=X_;zt.toFormData=sg;zt.AxiosError=He;zt.Cancel=zt.CanceledError;zt.all=function(t){return Promise.all(t)};zt.spread=I4;zt.isAxiosError=D4;zt.mergeConfig=Si;zt.AxiosHeaders=sr;zt.formToJSON=e=>q_($.isHTMLForm(e)?new FormData(e):e);zt.getAdapter=Y_.getAdapter;zt.HttpStatusCode=Uy;zt.default=zt;const{Axios:Mse,AxiosError:Ose,CanceledError:Nse,isCancel:Ise,CancelToken:Dse,VERSION:Ase,all:Fse,Cancel:Lse,isAxiosError:A4,spread:$se,toFormData:Bse,AxiosHeaders:zse,HttpStatusCode:Use,formToJSON:Vse,getAdapter:Hse,mergeConfig:Kse}=zt,F4=e=>["auth","verifyServer",JSON.stringify(e)],nj=async({url:e})=>(await zt.get(`${e}/`)).data,L4=e=>{const{url:t,...n}=e;return lt({...n,queryKey:F4({url:t}),queryFn:()=>nj({url:t}),enabled:!!t})};function $4(e,t){typeof e=="function"?e(t):e!=null&&(e.current=t)}function ag(...e){return t=>e.forEach(n=>$4(n,t))}function it(...e){return v.useCallback(ag(...e),e)}var mo=v.forwardRef((e,t)=>{const{children:n,...r}=e,s=v.Children.toArray(n),o=s.find(z4);if(o){const a=o.props.children,l=s.map(c=>c===o?v.Children.count(a)>1?v.Children.only(null):v.isValidElement(a)?a.props.children:null:c);return u.jsx(Vy,{...r,ref:t,children:v.isValidElement(a)?v.cloneElement(a,void 0,l):null})}return u.jsx(Vy,{...r,ref:t,children:n})});mo.displayName="Slot";var Vy=v.forwardRef((e,t)=>{const{children:n,...r}=e;if(v.isValidElement(n)){const s=V4(n);return v.cloneElement(n,{...U4(r,n.props),ref:t?ag(t,s):s})}return v.Children.count(n)>1?v.Children.only(null):null});Vy.displayName="SlotClone";var B4=({children:e})=>u.jsx(u.Fragment,{children:e});function z4(e){return v.isValidElement(e)&&e.type===B4}function U4(e,t){const n={...t};for(const r in t){const s=e[r],o=t[r];/^on[A-Z]/.test(r)?s&&o?n[r]=(...l)=>{o(...l),s(...l)}:s&&(n[r]=s):r==="style"?n[r]={...s,...o}:r==="className"&&(n[r]=[s,o].filter(Boolean).join(" "))}return{...e,...n}}function V4(e){var r,s;let t=(r=Object.getOwnPropertyDescriptor(e.props,"ref"))==null?void 0:r.get,n=t&&"isReactWarning"in t&&t.isReactWarning;return n?e.ref:(t=(s=Object.getOwnPropertyDescriptor(e,"ref"))==null?void 0:s.get,n=t&&"isReactWarning"in t&&t.isReactWarning,n?e.props.ref:e.props.ref||e.ref)}function rj(e){var t,n,r="";if(typeof e=="string"||typeof e=="number")r+=e;else if(typeof e=="object")if(Array.isArray(e))for(t=0;ttypeof e=="boolean"?"".concat(e):e===0?"0":e,Z0=H4,ig=(e,t)=>n=>{var r;if((t==null?void 0:t.variants)==null)return Z0(e,n==null?void 0:n.class,n==null?void 0:n.className);const{variants:s,defaultVariants:o}=t,a=Object.keys(s).map(i=>{const d=n==null?void 0:n[i],p=o==null?void 0:o[i];if(d===null)return null;const f=Q0(d)||Q0(p);return s[i][f]}),l=n&&Object.entries(n).reduce((i,d)=>{let[p,f]=d;return f===void 0||(i[p]=f),i},{}),c=t==null||(r=t.compoundVariants)===null||r===void 0?void 0:r.reduce((i,d)=>{let{class:p,className:f,...h}=d;return Object.entries(h).every(g=>{let[m,x]=g;return Array.isArray(x)?x.includes({...o,...l}[m]):{...o,...l}[m]===x})?[...i,p,f]:i},[]);return Z0(e,a,c,n==null?void 0:n.class,n==null?void 0:n.className)},Dx="-";function K4(e){const t=W4(e),{conflictingClassGroups:n,conflictingClassGroupModifiers:r}=e;function s(a){const l=a.split(Dx);return l[0]===""&&l.length!==1&&l.shift(),sj(l,t)||q4(a)}function o(a,l){const c=n[a]||[];return l&&r[a]?[...c,...r[a]]:c}return{getClassGroupId:s,getConflictingClassGroupIds:o}}function sj(e,t){var a;if(e.length===0)return t.classGroupId;const n=e[0],r=t.nextPart.get(n),s=r?sj(e.slice(1),r):void 0;if(s)return s;if(t.validators.length===0)return;const o=e.join(Dx);return(a=t.validators.find(({validator:l})=>l(o)))==null?void 0:a.classGroupId}const Y0=/^\[(.+)\]$/;function q4(e){if(Y0.test(e)){const t=Y0.exec(e)[1],n=t==null?void 0:t.substring(0,t.indexOf(":"));if(n)return"arbitrary.."+n}}function W4(e){const{theme:t,prefix:n}=e,r={nextPart:new Map,validators:[]};return J4(Object.entries(e.classGroups),n).forEach(([o,a])=>{Hy(a,r,o,t)}),r}function Hy(e,t,n,r){e.forEach(s=>{if(typeof s=="string"){const o=s===""?t:X0(t,s);o.classGroupId=n;return}if(typeof s=="function"){if(G4(s)){Hy(s(r),t,n,r);return}t.validators.push({validator:s,classGroupId:n});return}Object.entries(s).forEach(([o,a])=>{Hy(a,X0(t,o),n,r)})})}function X0(e,t){let n=e;return t.split(Dx).forEach(r=>{n.nextPart.has(r)||n.nextPart.set(r,{nextPart:new Map,validators:[]}),n=n.nextPart.get(r)}),n}function G4(e){return e.isThemeGetter}function J4(e,t){return t?e.map(([n,r])=>{const s=r.map(o=>typeof o=="string"?t+o:typeof o=="object"?Object.fromEntries(Object.entries(o).map(([a,l])=>[t+a,l])):o);return[n,s]}):e}function Q4(e){if(e<1)return{get:()=>{},set:()=>{}};let t=0,n=new Map,r=new Map;function s(o,a){n.set(o,a),t++,t>e&&(t=0,r=n,n=new Map)}return{get(o){let a=n.get(o);if(a!==void 0)return a;if((a=r.get(o))!==void 0)return s(o,a),a},set(o,a){n.has(o)?n.set(o,a):s(o,a)}}}const oj="!";function Z4(e){const{separator:t,experimentalParseClassName:n}=e,r=t.length===1,s=t[0],o=t.length;function a(l){const c=[];let i=0,d=0,p;for(let x=0;xd?p-d:void 0;return{modifiers:c,hasImportantModifier:h,baseClassName:g,maybePostfixModifierPosition:m}}return n?function(c){return n({className:c,parseClassName:a})}:a}function Y4(e){if(e.length<=1)return e;const t=[];let n=[];return e.forEach(r=>{r[0]==="["?(t.push(...n.sort(),r),n=[]):n.push(r)}),t.push(...n.sort()),t}function X4(e){return{cache:Q4(e.cacheSize),parseClassName:Z4(e),...K4(e)}}const e3=/\s+/;function t3(e,t){const{parseClassName:n,getClassGroupId:r,getConflictingClassGroupIds:s}=t,o=new Set;return e.trim().split(e3).map(a=>{const{modifiers:l,hasImportantModifier:c,baseClassName:i,maybePostfixModifierPosition:d}=n(a);let p=!!d,f=r(p?i.substring(0,d):i);if(!f){if(!p)return{isTailwindClass:!1,originalClassName:a};if(f=r(i),!f)return{isTailwindClass:!1,originalClassName:a};p=!1}const h=Y4(l).join(":");return{isTailwindClass:!0,modifierId:c?h+oj:h,classGroupId:f,originalClassName:a,hasPostfixModifier:p}}).reverse().filter(a=>{if(!a.isTailwindClass)return!0;const{modifierId:l,classGroupId:c,hasPostfixModifier:i}=a,d=l+c;return o.has(d)?!1:(o.add(d),s(c,i).forEach(p=>o.add(l+p)),!0)}).reverse().map(a=>a.originalClassName).join(" ")}function n3(){let e=0,t,n,r="";for(;ep(d),e());return n=X4(i),r=n.cache.get,s=n.cache.set,o=l,l(c)}function l(c){const i=r(c);if(i)return i;const d=t3(c,n);return s(c,d),d}return function(){return o(n3.apply(null,arguments))}}function _t(e){const t=n=>n[e]||[];return t.isThemeGetter=!0,t}const ij=/^\[(?:([a-z-]+):)?(.+)\]$/i,s3=/^\d+\/\d+$/,o3=new Set(["px","full","screen"]),a3=/^(\d+(\.\d+)?)?(xs|sm|md|lg|xl)$/,i3=/\d+(%|px|r?em|[sdl]?v([hwib]|min|max)|pt|pc|in|cm|mm|cap|ch|ex|r?lh|cq(w|h|i|b|min|max))|\b(calc|min|max|clamp)\(.+\)|^0$/,l3=/^(rgba?|hsla?|hwb|(ok)?(lab|lch))\(.+\)$/,u3=/^(inset_)?-?((\d+)?\.?(\d+)[a-z]+|0)_-?((\d+)?\.?(\d+)[a-z]+|0)/,c3=/^(url|image|image-set|cross-fade|element|(repeating-)?(linear|radial|conic)-gradient)\(.+\)$/;function qs(e){return Ga(e)||o3.has(e)||s3.test(e)}function No(e){return mu(e,"length",y3)}function Ga(e){return!!e&&!Number.isNaN(Number(e))}function Pf(e){return mu(e,"number",Ga)}function Ju(e){return!!e&&Number.isInteger(Number(e))}function d3(e){return e.endsWith("%")&&Ga(e.slice(0,-1))}function We(e){return ij.test(e)}function Io(e){return a3.test(e)}const f3=new Set(["length","size","percentage"]);function p3(e){return mu(e,f3,lj)}function h3(e){return mu(e,"position",lj)}const g3=new Set(["image","url"]);function m3(e){return mu(e,g3,x3)}function v3(e){return mu(e,"",b3)}function Qu(){return!0}function mu(e,t,n){const r=ij.exec(e);return r?r[1]?typeof t=="string"?r[1]===t:t.has(r[1]):n(r[2]):!1}function y3(e){return i3.test(e)&&!l3.test(e)}function lj(){return!1}function b3(e){return u3.test(e)}function x3(e){return c3.test(e)}function w3(){const e=_t("colors"),t=_t("spacing"),n=_t("blur"),r=_t("brightness"),s=_t("borderColor"),o=_t("borderRadius"),a=_t("borderSpacing"),l=_t("borderWidth"),c=_t("contrast"),i=_t("grayscale"),d=_t("hueRotate"),p=_t("invert"),f=_t("gap"),h=_t("gradientColorStops"),g=_t("gradientColorStopPositions"),m=_t("inset"),x=_t("margin"),b=_t("opacity"),y=_t("padding"),w=_t("saturate"),S=_t("scale"),E=_t("sepia"),C=_t("skew"),k=_t("space"),T=_t("translate"),P=()=>["auto","contain","none"],N=()=>["auto","hidden","clip","visible","scroll"],U=()=>["auto",We,t],I=()=>[We,t],Z=()=>["",qs,No],V=()=>["auto",Ga,We],Q=()=>["bottom","center","left","left-bottom","left-top","right","right-bottom","right-top","top"],ee=()=>["solid","dashed","dotted","double","none"],W=()=>["normal","multiply","screen","overlay","darken","lighten","color-dodge","color-burn","hard-light","soft-light","difference","exclusion","hue","saturation","color","luminosity"],F=()=>["start","end","center","between","around","evenly","stretch"],A=()=>["","0",We],Y=()=>["auto","avoid","all","avoid-page","page","left","right","column"],de=()=>[Ga,Pf],z=()=>[Ga,We];return{cacheSize:500,separator:":",theme:{colors:[Qu],spacing:[qs,No],blur:["none","",Io,We],brightness:de(),borderColor:[e],borderRadius:["none","","full",Io,We],borderSpacing:I(),borderWidth:Z(),contrast:de(),grayscale:A(),hueRotate:z(),invert:A(),gap:I(),gradientColorStops:[e],gradientColorStopPositions:[d3,No],inset:U(),margin:U(),opacity:de(),padding:I(),saturate:de(),scale:de(),sepia:A(),skew:z(),space:I(),translate:I()},classGroups:{aspect:[{aspect:["auto","square","video",We]}],container:["container"],columns:[{columns:[Io]}],"break-after":[{"break-after":Y()}],"break-before":[{"break-before":Y()}],"break-inside":[{"break-inside":["auto","avoid","avoid-page","avoid-column"]}],"box-decoration":[{"box-decoration":["slice","clone"]}],box:[{box:["border","content"]}],display:["block","inline-block","inline","flex","inline-flex","table","inline-table","table-caption","table-cell","table-column","table-column-group","table-footer-group","table-header-group","table-row-group","table-row","flow-root","grid","inline-grid","contents","list-item","hidden"],float:[{float:["right","left","none","start","end"]}],clear:[{clear:["left","right","both","none","start","end"]}],isolation:["isolate","isolation-auto"],"object-fit":[{object:["contain","cover","fill","none","scale-down"]}],"object-position":[{object:[...Q(),We]}],overflow:[{overflow:N()}],"overflow-x":[{"overflow-x":N()}],"overflow-y":[{"overflow-y":N()}],overscroll:[{overscroll:P()}],"overscroll-x":[{"overscroll-x":P()}],"overscroll-y":[{"overscroll-y":P()}],position:["static","fixed","absolute","relative","sticky"],inset:[{inset:[m]}],"inset-x":[{"inset-x":[m]}],"inset-y":[{"inset-y":[m]}],start:[{start:[m]}],end:[{end:[m]}],top:[{top:[m]}],right:[{right:[m]}],bottom:[{bottom:[m]}],left:[{left:[m]}],visibility:["visible","invisible","collapse"],z:[{z:["auto",Ju,We]}],basis:[{basis:U()}],"flex-direction":[{flex:["row","row-reverse","col","col-reverse"]}],"flex-wrap":[{flex:["wrap","wrap-reverse","nowrap"]}],flex:[{flex:["1","auto","initial","none",We]}],grow:[{grow:A()}],shrink:[{shrink:A()}],order:[{order:["first","last","none",Ju,We]}],"grid-cols":[{"grid-cols":[Qu]}],"col-start-end":[{col:["auto",{span:["full",Ju,We]},We]}],"col-start":[{"col-start":V()}],"col-end":[{"col-end":V()}],"grid-rows":[{"grid-rows":[Qu]}],"row-start-end":[{row:["auto",{span:[Ju,We]},We]}],"row-start":[{"row-start":V()}],"row-end":[{"row-end":V()}],"grid-flow":[{"grid-flow":["row","col","dense","row-dense","col-dense"]}],"auto-cols":[{"auto-cols":["auto","min","max","fr",We]}],"auto-rows":[{"auto-rows":["auto","min","max","fr",We]}],gap:[{gap:[f]}],"gap-x":[{"gap-x":[f]}],"gap-y":[{"gap-y":[f]}],"justify-content":[{justify:["normal",...F()]}],"justify-items":[{"justify-items":["start","end","center","stretch"]}],"justify-self":[{"justify-self":["auto","start","end","center","stretch"]}],"align-content":[{content:["normal",...F(),"baseline"]}],"align-items":[{items:["start","end","center","baseline","stretch"]}],"align-self":[{self:["auto","start","end","center","stretch","baseline"]}],"place-content":[{"place-content":[...F(),"baseline"]}],"place-items":[{"place-items":["start","end","center","baseline","stretch"]}],"place-self":[{"place-self":["auto","start","end","center","stretch"]}],p:[{p:[y]}],px:[{px:[y]}],py:[{py:[y]}],ps:[{ps:[y]}],pe:[{pe:[y]}],pt:[{pt:[y]}],pr:[{pr:[y]}],pb:[{pb:[y]}],pl:[{pl:[y]}],m:[{m:[x]}],mx:[{mx:[x]}],my:[{my:[x]}],ms:[{ms:[x]}],me:[{me:[x]}],mt:[{mt:[x]}],mr:[{mr:[x]}],mb:[{mb:[x]}],ml:[{ml:[x]}],"space-x":[{"space-x":[k]}],"space-x-reverse":["space-x-reverse"],"space-y":[{"space-y":[k]}],"space-y-reverse":["space-y-reverse"],w:[{w:["auto","min","max","fit","svw","lvw","dvw",We,t]}],"min-w":[{"min-w":[We,t,"min","max","fit"]}],"max-w":[{"max-w":[We,t,"none","full","min","max","fit","prose",{screen:[Io]},Io]}],h:[{h:[We,t,"auto","min","max","fit","svh","lvh","dvh"]}],"min-h":[{"min-h":[We,t,"min","max","fit","svh","lvh","dvh"]}],"max-h":[{"max-h":[We,t,"min","max","fit","svh","lvh","dvh"]}],size:[{size:[We,t,"auto","min","max","fit"]}],"font-size":[{text:["base",Io,No]}],"font-smoothing":["antialiased","subpixel-antialiased"],"font-style":["italic","not-italic"],"font-weight":[{font:["thin","extralight","light","normal","medium","semibold","bold","extrabold","black",Pf]}],"font-family":[{font:[Qu]}],"fvn-normal":["normal-nums"],"fvn-ordinal":["ordinal"],"fvn-slashed-zero":["slashed-zero"],"fvn-figure":["lining-nums","oldstyle-nums"],"fvn-spacing":["proportional-nums","tabular-nums"],"fvn-fraction":["diagonal-fractions","stacked-fractons"],tracking:[{tracking:["tighter","tight","normal","wide","wider","widest",We]}],"line-clamp":[{"line-clamp":["none",Ga,Pf]}],leading:[{leading:["none","tight","snug","normal","relaxed","loose",qs,We]}],"list-image":[{"list-image":["none",We]}],"list-style-type":[{list:["none","disc","decimal",We]}],"list-style-position":[{list:["inside","outside"]}],"placeholder-color":[{placeholder:[e]}],"placeholder-opacity":[{"placeholder-opacity":[b]}],"text-alignment":[{text:["left","center","right","justify","start","end"]}],"text-color":[{text:[e]}],"text-opacity":[{"text-opacity":[b]}],"text-decoration":["underline","overline","line-through","no-underline"],"text-decoration-style":[{decoration:[...ee(),"wavy"]}],"text-decoration-thickness":[{decoration:["auto","from-font",qs,No]}],"underline-offset":[{"underline-offset":["auto",qs,We]}],"text-decoration-color":[{decoration:[e]}],"text-transform":["uppercase","lowercase","capitalize","normal-case"],"text-overflow":["truncate","text-ellipsis","text-clip"],"text-wrap":[{text:["wrap","nowrap","balance","pretty"]}],indent:[{indent:I()}],"vertical-align":[{align:["baseline","top","middle","bottom","text-top","text-bottom","sub","super",We]}],whitespace:[{whitespace:["normal","nowrap","pre","pre-line","pre-wrap","break-spaces"]}],break:[{break:["normal","words","all","keep"]}],hyphens:[{hyphens:["none","manual","auto"]}],content:[{content:["none",We]}],"bg-attachment":[{bg:["fixed","local","scroll"]}],"bg-clip":[{"bg-clip":["border","padding","content","text"]}],"bg-opacity":[{"bg-opacity":[b]}],"bg-origin":[{"bg-origin":["border","padding","content"]}],"bg-position":[{bg:[...Q(),h3]}],"bg-repeat":[{bg:["no-repeat",{repeat:["","x","y","round","space"]}]}],"bg-size":[{bg:["auto","cover","contain",p3]}],"bg-image":[{bg:["none",{"gradient-to":["t","tr","r","br","b","bl","l","tl"]},m3]}],"bg-color":[{bg:[e]}],"gradient-from-pos":[{from:[g]}],"gradient-via-pos":[{via:[g]}],"gradient-to-pos":[{to:[g]}],"gradient-from":[{from:[h]}],"gradient-via":[{via:[h]}],"gradient-to":[{to:[h]}],rounded:[{rounded:[o]}],"rounded-s":[{"rounded-s":[o]}],"rounded-e":[{"rounded-e":[o]}],"rounded-t":[{"rounded-t":[o]}],"rounded-r":[{"rounded-r":[o]}],"rounded-b":[{"rounded-b":[o]}],"rounded-l":[{"rounded-l":[o]}],"rounded-ss":[{"rounded-ss":[o]}],"rounded-se":[{"rounded-se":[o]}],"rounded-ee":[{"rounded-ee":[o]}],"rounded-es":[{"rounded-es":[o]}],"rounded-tl":[{"rounded-tl":[o]}],"rounded-tr":[{"rounded-tr":[o]}],"rounded-br":[{"rounded-br":[o]}],"rounded-bl":[{"rounded-bl":[o]}],"border-w":[{border:[l]}],"border-w-x":[{"border-x":[l]}],"border-w-y":[{"border-y":[l]}],"border-w-s":[{"border-s":[l]}],"border-w-e":[{"border-e":[l]}],"border-w-t":[{"border-t":[l]}],"border-w-r":[{"border-r":[l]}],"border-w-b":[{"border-b":[l]}],"border-w-l":[{"border-l":[l]}],"border-opacity":[{"border-opacity":[b]}],"border-style":[{border:[...ee(),"hidden"]}],"divide-x":[{"divide-x":[l]}],"divide-x-reverse":["divide-x-reverse"],"divide-y":[{"divide-y":[l]}],"divide-y-reverse":["divide-y-reverse"],"divide-opacity":[{"divide-opacity":[b]}],"divide-style":[{divide:ee()}],"border-color":[{border:[s]}],"border-color-x":[{"border-x":[s]}],"border-color-y":[{"border-y":[s]}],"border-color-t":[{"border-t":[s]}],"border-color-r":[{"border-r":[s]}],"border-color-b":[{"border-b":[s]}],"border-color-l":[{"border-l":[s]}],"divide-color":[{divide:[s]}],"outline-style":[{outline:["",...ee()]}],"outline-offset":[{"outline-offset":[qs,We]}],"outline-w":[{outline:[qs,No]}],"outline-color":[{outline:[e]}],"ring-w":[{ring:Z()}],"ring-w-inset":["ring-inset"],"ring-color":[{ring:[e]}],"ring-opacity":[{"ring-opacity":[b]}],"ring-offset-w":[{"ring-offset":[qs,No]}],"ring-offset-color":[{"ring-offset":[e]}],shadow:[{shadow:["","inner","none",Io,v3]}],"shadow-color":[{shadow:[Qu]}],opacity:[{opacity:[b]}],"mix-blend":[{"mix-blend":[...W(),"plus-lighter","plus-darker"]}],"bg-blend":[{"bg-blend":W()}],filter:[{filter:["","none"]}],blur:[{blur:[n]}],brightness:[{brightness:[r]}],contrast:[{contrast:[c]}],"drop-shadow":[{"drop-shadow":["","none",Io,We]}],grayscale:[{grayscale:[i]}],"hue-rotate":[{"hue-rotate":[d]}],invert:[{invert:[p]}],saturate:[{saturate:[w]}],sepia:[{sepia:[E]}],"backdrop-filter":[{"backdrop-filter":["","none"]}],"backdrop-blur":[{"backdrop-blur":[n]}],"backdrop-brightness":[{"backdrop-brightness":[r]}],"backdrop-contrast":[{"backdrop-contrast":[c]}],"backdrop-grayscale":[{"backdrop-grayscale":[i]}],"backdrop-hue-rotate":[{"backdrop-hue-rotate":[d]}],"backdrop-invert":[{"backdrop-invert":[p]}],"backdrop-opacity":[{"backdrop-opacity":[b]}],"backdrop-saturate":[{"backdrop-saturate":[w]}],"backdrop-sepia":[{"backdrop-sepia":[E]}],"border-collapse":[{border:["collapse","separate"]}],"border-spacing":[{"border-spacing":[a]}],"border-spacing-x":[{"border-spacing-x":[a]}],"border-spacing-y":[{"border-spacing-y":[a]}],"table-layout":[{table:["auto","fixed"]}],caption:[{caption:["top","bottom"]}],transition:[{transition:["none","all","","colors","opacity","shadow","transform",We]}],duration:[{duration:z()}],ease:[{ease:["linear","in","out","in-out",We]}],delay:[{delay:z()}],animate:[{animate:["none","spin","ping","pulse","bounce",We]}],transform:[{transform:["","gpu","none"]}],scale:[{scale:[S]}],"scale-x":[{"scale-x":[S]}],"scale-y":[{"scale-y":[S]}],rotate:[{rotate:[Ju,We]}],"translate-x":[{"translate-x":[T]}],"translate-y":[{"translate-y":[T]}],"skew-x":[{"skew-x":[C]}],"skew-y":[{"skew-y":[C]}],"transform-origin":[{origin:["center","top","top-right","right","bottom-right","bottom","bottom-left","left","top-left",We]}],accent:[{accent:["auto",e]}],appearance:[{appearance:["none","auto"]}],cursor:[{cursor:["auto","default","pointer","wait","text","move","help","not-allowed","none","context-menu","progress","cell","crosshair","vertical-text","alias","copy","no-drop","grab","grabbing","all-scroll","col-resize","row-resize","n-resize","e-resize","s-resize","w-resize","ne-resize","nw-resize","se-resize","sw-resize","ew-resize","ns-resize","nesw-resize","nwse-resize","zoom-in","zoom-out",We]}],"caret-color":[{caret:[e]}],"pointer-events":[{"pointer-events":["none","auto"]}],resize:[{resize:["none","y","x",""]}],"scroll-behavior":[{scroll:["auto","smooth"]}],"scroll-m":[{"scroll-m":I()}],"scroll-mx":[{"scroll-mx":I()}],"scroll-my":[{"scroll-my":I()}],"scroll-ms":[{"scroll-ms":I()}],"scroll-me":[{"scroll-me":I()}],"scroll-mt":[{"scroll-mt":I()}],"scroll-mr":[{"scroll-mr":I()}],"scroll-mb":[{"scroll-mb":I()}],"scroll-ml":[{"scroll-ml":I()}],"scroll-p":[{"scroll-p":I()}],"scroll-px":[{"scroll-px":I()}],"scroll-py":[{"scroll-py":I()}],"scroll-ps":[{"scroll-ps":I()}],"scroll-pe":[{"scroll-pe":I()}],"scroll-pt":[{"scroll-pt":I()}],"scroll-pr":[{"scroll-pr":I()}],"scroll-pb":[{"scroll-pb":I()}],"scroll-pl":[{"scroll-pl":I()}],"snap-align":[{snap:["start","end","center","align-none"]}],"snap-stop":[{snap:["normal","always"]}],"snap-type":[{snap:["none","x","y","both"]}],"snap-strictness":[{snap:["mandatory","proximity"]}],touch:[{touch:["auto","none","manipulation"]}],"touch-x":[{"touch-pan":["x","left","right"]}],"touch-y":[{"touch-pan":["y","up","down"]}],"touch-pz":["touch-pinch-zoom"],select:[{select:["none","text","all","auto"]}],"will-change":[{"will-change":["auto","scroll","contents","transform",We]}],fill:[{fill:[e,"none"]}],"stroke-w":[{stroke:[qs,No,Pf]}],stroke:[{stroke:[e,"none"]}],sr:["sr-only","not-sr-only"],"forced-color-adjust":[{"forced-color-adjust":["auto","none"]}]},conflictingClassGroups:{overflow:["overflow-x","overflow-y"],overscroll:["overscroll-x","overscroll-y"],inset:["inset-x","inset-y","start","end","top","right","bottom","left"],"inset-x":["right","left"],"inset-y":["top","bottom"],flex:["basis","grow","shrink"],gap:["gap-x","gap-y"],p:["px","py","ps","pe","pt","pr","pb","pl"],px:["pr","pl"],py:["pt","pb"],m:["mx","my","ms","me","mt","mr","mb","ml"],mx:["mr","ml"],my:["mt","mb"],size:["w","h"],"font-size":["leading"],"fvn-normal":["fvn-ordinal","fvn-slashed-zero","fvn-figure","fvn-spacing","fvn-fraction"],"fvn-ordinal":["fvn-normal"],"fvn-slashed-zero":["fvn-normal"],"fvn-figure":["fvn-normal"],"fvn-spacing":["fvn-normal"],"fvn-fraction":["fvn-normal"],"line-clamp":["display","overflow"],rounded:["rounded-s","rounded-e","rounded-t","rounded-r","rounded-b","rounded-l","rounded-ss","rounded-se","rounded-ee","rounded-es","rounded-tl","rounded-tr","rounded-br","rounded-bl"],"rounded-s":["rounded-ss","rounded-es"],"rounded-e":["rounded-se","rounded-ee"],"rounded-t":["rounded-tl","rounded-tr"],"rounded-r":["rounded-tr","rounded-br"],"rounded-b":["rounded-br","rounded-bl"],"rounded-l":["rounded-tl","rounded-bl"],"border-spacing":["border-spacing-x","border-spacing-y"],"border-w":["border-w-s","border-w-e","border-w-t","border-w-r","border-w-b","border-w-l"],"border-w-x":["border-w-r","border-w-l"],"border-w-y":["border-w-t","border-w-b"],"border-color":["border-color-t","border-color-r","border-color-b","border-color-l"],"border-color-x":["border-color-r","border-color-l"],"border-color-y":["border-color-t","border-color-b"],"scroll-m":["scroll-mx","scroll-my","scroll-ms","scroll-me","scroll-mt","scroll-mr","scroll-mb","scroll-ml"],"scroll-mx":["scroll-mr","scroll-ml"],"scroll-my":["scroll-mt","scroll-mb"],"scroll-p":["scroll-px","scroll-py","scroll-ps","scroll-pe","scroll-pt","scroll-pr","scroll-pb","scroll-pl"],"scroll-px":["scroll-pr","scroll-pl"],"scroll-py":["scroll-pt","scroll-pb"],touch:["touch-x","touch-y","touch-pz"],"touch-x":["touch"],"touch-y":["touch"],"touch-pz":["touch"]},conflictingClassGroupModifiers:{"font-size":["leading"]}}}const S3=r3(w3);function ge(...e){return S3(oo(e))}const C3=ig("inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",{variants:{variant:{default:"bg-primary text-primary-foreground hover:bg-primary/90",destructive:"bg-destructive text-destructive-foreground hover:bg-destructive/90",outline:"border border-input bg-background hover:bg-accent hover:text-accent-foreground",secondary:"bg-secondary text-secondary-foreground hover:bg-secondary/80",warning:"bg-amber-600 shadow-sm hover:bg-amber-600/90 data-active:bg-amber-600/90 text-foreground",ghost:"hover:bg-accent hover:text-accent-foreground",link:"text-primary underline-offset-4 hover:underline"},size:{default:"h-10 px-4 py-2",sm:"h-9 rounded-md px-3",lg:"h-11 rounded-md px-8",icon:"h-10 w-10"}},defaultVariants:{variant:"default",size:"default"}}),q=v.forwardRef(({className:e,variant:t,size:n,asChild:r=!1,...s},o)=>{const a=r?mo:"button";return u.jsx(a,{className:ge(C3({variant:t,size:n,className:e})),ref:o,...s})});q.displayName="Button";function Ax(){const{t:e}=ze(),t=Fs(rs.API_URL),{data:n}=L4({url:t}),r=v.useMemo(()=>n==null?void 0:n.clientName,[n]),s=v.useMemo(()=>n==null?void 0:n.version,[n]),o=[{name:"Discord",url:"https://evolution-api.com/discord"},{name:"Postman",url:"https://evolution-api.com/postman"},{name:"GitHub",url:"https://github.com/EvolutionAPI/evolution-api"},{name:"Docs",url:"https://doc.evolution-api.com"}];return u.jsxs("footer",{className:"flex w-full flex-col items-center justify-between p-6 text-xs text-secondary-foreground sm:flex-row",children:[u.jsxs("div",{className:"flex items-center space-x-3 divide-x",children:[r&&r!==""&&u.jsxs("span",{children:[e("footer.clientName"),": ",u.jsx("strong",{children:r})]}),s&&s!==""&&u.jsxs("span",{className:"pl-3",children:[e("footer.version"),": ",u.jsx("strong",{children:s})]})]}),u.jsx("div",{className:"flex gap-2",children:o.map(a=>u.jsx(q,{variant:"link",asChild:!0,size:"sm",className:"text-xs",children:u.jsx("a",{href:a.url,target:"_blank",rel:"noopener noreferrer",children:a.name})},a.url))})]})}/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const E3=e=>e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase(),uj=(...e)=>e.filter((t,n,r)=>!!t&&r.indexOf(t)===n).join(" ");/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */var T3={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"};/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const k3=v.forwardRef(({color:e="currentColor",size:t=24,strokeWidth:n=2,absoluteStrokeWidth:r,className:s="",children:o,iconNode:a,...l},c)=>v.createElement("svg",{ref:c,...T3,width:t,height:t,stroke:e,strokeWidth:r?Number(n)*24/Number(t):n,className:uj("lucide",s),...l},[...a.map(([i,d])=>v.createElement(i,d)),...Array.isArray(o)?o:[o]]));/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Xe=(e,t)=>{const n=v.forwardRef(({className:r,...s},o)=>v.createElement(k3,{ref:o,iconNode:t,className:uj(`lucide-${E3(e)}`,r),...s}));return n.displayName=`${e}`,n};/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const _3=Xe("ArrowUpDown",[["path",{d:"m21 16-4 4-4-4",key:"f6ql7i"}],["path",{d:"M17 20V4",key:"1ejh1v"}],["path",{d:"m3 8 4-4 4 4",key:"11wl7u"}],["path",{d:"M7 4v16",key:"1glfcx"}]]);/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const j3=Xe("ArrowUp",[["path",{d:"m5 12 7-7 7 7",key:"hav0vg"}],["path",{d:"M12 19V5",key:"x0mq9r"}]]);/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const cj=Xe("Check",[["path",{d:"M20 6 9 17l-5-5",key:"1gmf2c"}]]);/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const lg=Xe("ChevronDown",[["path",{d:"m6 9 6 6 6-6",key:"qrunsl"}]]);/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const R3=Xe("ChevronRight",[["path",{d:"m9 18 6-6-6-6",key:"mthhwq"}]]);/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const P3=Xe("ChevronUp",[["path",{d:"m18 15-6-6-6 6",key:"153udz"}]]);/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const M3=Xe("ChevronsUpDown",[["path",{d:"m7 15 5 5 5-5",key:"1hf1tw"}],["path",{d:"m7 9 5-5 5 5",key:"sgt6xg"}]]);/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const O3=Xe("CircleHelp",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3",key:"1u773s"}],["path",{d:"M12 17h.01",key:"p32p05"}]]);/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Ud=Xe("CircleStop",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["rect",{width:"6",height:"6",x:"9",y:"9",key:"1wrtvo"}]]);/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const dj=Xe("CircleUser",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["circle",{cx:"12",cy:"10",r:"3",key:"ilqhr7"}],["path",{d:"M7 20.662V19a2 2 0 0 1 2-2h6a2 2 0 0 1 2 2v1.662",key:"154egf"}]]);/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const N3=Xe("Circle",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}]]);/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Oi=Xe("Cog",[["path",{d:"M12 20a8 8 0 1 0 0-16 8 8 0 0 0 0 16Z",key:"sobvz5"}],["path",{d:"M12 14a2 2 0 1 0 0-4 2 2 0 0 0 0 4Z",key:"11i496"}],["path",{d:"M12 2v2",key:"tus03m"}],["path",{d:"M12 22v-2",key:"1osdcq"}],["path",{d:"m17 20.66-1-1.73",key:"eq3orb"}],["path",{d:"M11 10.27 7 3.34",key:"16pf9h"}],["path",{d:"m20.66 17-1.73-1",key:"sg0v6f"}],["path",{d:"m3.34 7 1.73 1",key:"1ulond"}],["path",{d:"M14 12h8",key:"4f43i9"}],["path",{d:"M2 12h2",key:"1t8f8n"}],["path",{d:"m20.66 7-1.73 1",key:"1ow05n"}],["path",{d:"m3.34 17 1.73-1",key:"nuk764"}],["path",{d:"m17 3.34-1 1.73",key:"2wel8s"}],["path",{d:"m11 13.73-4 6.93",key:"794ttg"}]]);/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const I3=Xe("Copy",[["rect",{width:"14",height:"14",x:"8",y:"8",rx:"2",ry:"2",key:"17jyea"}],["path",{d:"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2",key:"zix9uf"}]]);/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Vd=Xe("Delete",[["path",{d:"M10 5a2 2 0 0 0-1.344.519l-6.328 5.74a1 1 0 0 0 0 1.481l6.328 5.741A2 2 0 0 0 10 19h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2z",key:"1yo7s0"}],["path",{d:"m12 9 6 6",key:"anjzzh"}],["path",{d:"m18 9-6 6",key:"1fp51s"}]]);/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const D3=Xe("DoorOpen",[["path",{d:"M13 4h3a2 2 0 0 1 2 2v14",key:"hrm0s9"}],["path",{d:"M2 20h3",key:"1gaodv"}],["path",{d:"M13 20h9",key:"s90cdi"}],["path",{d:"M10 12v.01",key:"vx6srw"}],["path",{d:"M13 4.562v16.157a1 1 0 0 1-1.242.97L5 20V5.562a2 2 0 0 1 1.515-1.94l4-1A2 2 0 0 1 13 4.561Z",key:"199qr4"}]]);/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const vu=Xe("Ellipsis",[["circle",{cx:"12",cy:"12",r:"1",key:"41hilf"}],["circle",{cx:"19",cy:"12",r:"1",key:"1wjl8i"}],["circle",{cx:"5",cy:"12",r:"1",key:"1pcz8c"}]]);/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const A3=Xe("EyeOff",[["path",{d:"M9.88 9.88a3 3 0 1 0 4.24 4.24",key:"1jxqfv"}],["path",{d:"M10.73 5.08A10.43 10.43 0 0 1 12 5c7 0 10 7 10 7a13.16 13.16 0 0 1-1.67 2.68",key:"9wicm4"}],["path",{d:"M6.61 6.61A13.526 13.526 0 0 0 2 12s3 7 10 7a9.74 9.74 0 0 0 5.39-1.61",key:"1jreej"}],["line",{x1:"2",x2:"22",y1:"2",y2:"22",key:"a6p6uj"}]]);/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const F3=Xe("Eye",[["path",{d:"M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7Z",key:"rwhkz3"}],["circle",{cx:"12",cy:"12",r:"3",key:"1v7zrd"}]]);/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const L3=Xe("FileQuestion",[["path",{d:"M12 17h.01",key:"p32p05"}],["path",{d:"M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7z",key:"1mlx9k"}],["path",{d:"M9.1 9a3 3 0 0 1 5.82 1c0 2-3 3-3 3",key:"mhlwft"}]]);/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const $3=Xe("GripVertical",[["circle",{cx:"9",cy:"12",r:"1",key:"1vctgf"}],["circle",{cx:"9",cy:"5",r:"1",key:"hp0tcf"}],["circle",{cx:"9",cy:"19",r:"1",key:"fkjjf6"}],["circle",{cx:"15",cy:"12",r:"1",key:"1tmaij"}],["circle",{cx:"15",cy:"5",r:"1",key:"19l28e"}],["circle",{cx:"15",cy:"19",r:"1",key:"f4zoj3"}]]);/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const B3=Xe("IterationCcw",[["path",{d:"M20 10c0-4.4-3.6-8-8-8s-8 3.6-8 8 3.6 8 8 8h8",key:"4znkd0"}],["polyline",{points:"16 14 20 18 16 22",key:"11njsm"}]]);/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const z3=Xe("Languages",[["path",{d:"m5 8 6 6",key:"1wu5hv"}],["path",{d:"m4 14 6-6 2-3",key:"1k1g8d"}],["path",{d:"M2 5h12",key:"or177f"}],["path",{d:"M7 2h1",key:"1t2jsx"}],["path",{d:"m22 22-5-10-5 10",key:"don7ne"}],["path",{d:"M14 18h6",key:"1m8k6r"}]]);/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const U3=Xe("LayoutDashboard",[["rect",{width:"7",height:"9",x:"3",y:"3",rx:"1",key:"10lvy0"}],["rect",{width:"7",height:"5",x:"14",y:"3",rx:"1",key:"16une8"}],["rect",{width:"7",height:"9",x:"14",y:"12",rx:"1",key:"1hutg5"}],["rect",{width:"7",height:"5",x:"3",y:"16",rx:"1",key:"ldoo1y"}]]);/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const V3=Xe("LifeBuoy",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m4.93 4.93 4.24 4.24",key:"1ymg45"}],["path",{d:"m14.83 9.17 4.24-4.24",key:"1cb5xl"}],["path",{d:"m14.83 14.83 4.24 4.24",key:"q42g0n"}],["path",{d:"m9.17 14.83-4.24 4.24",key:"bqpfvv"}],["circle",{cx:"12",cy:"12",r:"4",key:"4exip2"}]]);/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Hd=Xe("ListCollapse",[["path",{d:"m3 10 2.5-2.5L3 5",key:"i6eama"}],["path",{d:"m3 19 2.5-2.5L3 14",key:"w2gmor"}],["path",{d:"M10 6h11",key:"c7qv1k"}],["path",{d:"M10 12h11",key:"6m4ad9"}],["path",{d:"M10 18h11",key:"11hvi2"}]]);/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const H3=Xe("Lock",[["rect",{width:"18",height:"11",x:"3",y:"11",rx:"2",ry:"2",key:"1w4ew1"}],["path",{d:"M7 11V7a5 5 0 0 1 10 0v4",key:"fwvmzm"}]]);/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const ug=Xe("MessageCircle",[["path",{d:"M7.9 20A9 9 0 1 0 4 16.1L2 22Z",key:"vv11sd"}]]);/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const K3=Xe("Moon",[["path",{d:"M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z",key:"a7tn18"}]]);/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const q3=Xe("Paperclip",[["path",{d:"m21.44 11.05-9.19 9.19a6 6 0 0 1-8.49-8.49l8.57-8.57A4 4 0 1 1 18 8.84l-8.59 8.57a2 2 0 0 1-2.83-2.83l8.49-8.48",key:"1u3ebp"}]]);/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Kd=Xe("Pause",[["rect",{x:"14",y:"4",width:"4",height:"16",rx:"1",key:"zuxfzm"}],["rect",{x:"6",y:"4",width:"4",height:"16",rx:"1",key:"1okwgv"}]]);/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const qd=Xe("Play",[["polygon",{points:"6 3 20 12 6 21 6 3",key:"1oa8hb"}]]);/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Ni=Xe("Plus",[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]]);/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const fj=Xe("RefreshCw",[["path",{d:"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8",key:"v9h5vc"}],["path",{d:"M21 3v5h-5",key:"1q7to0"}],["path",{d:"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16",key:"3uifl3"}],["path",{d:"M8 16H3v5",key:"1cv678"}]]);/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Wd=Xe("RotateCcw",[["path",{d:"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",key:"1357e3"}],["path",{d:"M3 3v5h5",key:"1xhq8a"}]]);/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const W3=Xe("Sparkle",[["path",{d:"M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z",key:"4pj2yx"}]]);/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const G3=Xe("Sun",[["circle",{cx:"12",cy:"12",r:"4",key:"4exip2"}],["path",{d:"M12 2v2",key:"tus03m"}],["path",{d:"M12 20v2",key:"1lh1kg"}],["path",{d:"m4.93 4.93 1.41 1.41",key:"149t6j"}],["path",{d:"m17.66 17.66 1.41 1.41",key:"ptbguv"}],["path",{d:"M2 12h2",key:"1t8f8n"}],["path",{d:"M20 12h2",key:"1q8mjw"}],["path",{d:"m6.34 17.66-1.41 1.41",key:"1m8zz5"}],["path",{d:"m19.07 4.93-1.41 1.41",key:"1shlcs"}]]);/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const J3=Xe("UsersRound",[["path",{d:"M18 21a8 8 0 0 0-16 0",key:"3ypg7q"}],["circle",{cx:"10",cy:"8",r:"5",key:"o932ke"}],["path",{d:"M22 20c0-3.37-2-6.5-4-8a5 5 0 0 0-.45-8.3",key:"10s06x"}]]);/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const Q3=Xe("X",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]]);/** + * @license lucide-react v0.408.0 - ISC + * + * This source code is licensed under the ISC license. + * See the LICENSE file in the root directory of this source tree. + */const pj=Xe("Zap",[["path",{d:"M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z",key:"1xq2db"}]]),he=zt.create({timeout:3e4});he.interceptors.request.use(async e=>{const t=Fs(rs.API_URL);if(t&&(e.baseURL=t.toString()),!e.headers.apiKey||e.headers.apiKey===""){const n=Fs(rs.TOKEN);n&&(e.headers.apikey=`${n}`)}return e},e=>Promise.reject(e));const Z3=e=>["instance","fetchInstance",JSON.stringify(e)],Y3=async({instanceId:e})=>{const t=await he.get("/instance/fetchInstances",{params:{instanceId:e}});return Array.isArray(t.data)?t.data[0]:t.data},hj=e=>{const{instanceId:t,...n}=e;return lt({...n,queryKey:Z3({instanceId:t}),queryFn:()=>Y3({instanceId:t}),enabled:!!t})};function Se(e,t,{checkForDefaultPrevented:n=!0}={}){return function(s){if(e==null||e(s),n===!1||!s.defaultPrevented)return t==null?void 0:t(s)}}function X3(e,t){const n=v.createContext(t);function r(o){const{children:a,...l}=o,c=v.useMemo(()=>l,Object.values(l));return u.jsx(n.Provider,{value:c,children:a})}function s(o){const a=v.useContext(n);if(a)return a;if(t!==void 0)return t;throw new Error(`\`${o}\` must be used within \`${e}\``)}return r.displayName=e+"Provider",[r,s]}function Vr(e,t=[]){let n=[];function r(o,a){const l=v.createContext(a),c=n.length;n=[...n,a];function i(p){const{scope:f,children:h,...g}=p,m=(f==null?void 0:f[e][c])||l,x=v.useMemo(()=>g,Object.values(g));return u.jsx(m.Provider,{value:x,children:h})}function d(p,f){const h=(f==null?void 0:f[e][c])||l,g=v.useContext(h);if(g)return g;if(a!==void 0)return a;throw new Error(`\`${p}\` must be used within \`${o}\``)}return i.displayName=o+"Provider",[i,d]}const s=()=>{const o=n.map(a=>v.createContext(a));return function(l){const c=(l==null?void 0:l[e])||o;return v.useMemo(()=>({[`__scope${e}`]:{...l,[e]:c}}),[l,c])}};return s.scopeName=e,[r,eB(s,...t)]}function eB(...e){const t=e[0];if(e.length===1)return t;const n=()=>{const r=e.map(s=>({useScope:s(),scopeName:s.scopeName}));return function(o){const a=r.reduce((l,{useScope:c,scopeName:i})=>{const p=c(o)[`__scope${i}`];return{...l,...p}},{});return v.useMemo(()=>({[`__scope${t.scopeName}`]:a}),[a])}};return n.scopeName=t.scopeName,n}function nn(e){const t=v.useRef(e);return v.useEffect(()=>{t.current=e}),v.useMemo(()=>(...n)=>{var r;return(r=t.current)==null?void 0:r.call(t,...n)},[])}function pa({prop:e,defaultProp:t,onChange:n=()=>{}}){const[r,s]=tB({defaultProp:t,onChange:n}),o=e!==void 0,a=o?e:r,l=nn(n),c=v.useCallback(i=>{if(o){const p=typeof i=="function"?i(e):i;p!==e&&l(p)}else s(i)},[o,e,s,l]);return[a,c]}function tB({defaultProp:e,onChange:t}){const n=v.useState(e),[r]=n,s=v.useRef(r),o=nn(t);return v.useEffect(()=>{s.current!==r&&(o(r),s.current=r)},[r,s,o]),n}var nB=["a","button","div","form","h2","h3","img","input","label","li","nav","ol","p","span","svg","ul"],Ne=nB.reduce((e,t)=>{const n=v.forwardRef((r,s)=>{const{asChild:o,...a}=r,l=o?mo:t;return typeof window<"u"&&(window[Symbol.for("radix-ui")]=!0),u.jsx(l,{...a,ref:s})});return n.displayName=`Primitive.${t}`,{...e,[t]:n}},{});function gj(e,t){e&&ka.flushSync(()=>e.dispatchEvent(t))}function Fx(e){const t=e+"CollectionProvider",[n,r]=Vr(t),[s,o]=n(t,{collectionRef:{current:null},itemMap:new Map}),a=h=>{const{scope:g,children:m}=h,x=Te.useRef(null),b=Te.useRef(new Map).current;return u.jsx(s,{scope:g,itemMap:b,collectionRef:x,children:m})};a.displayName=t;const l=e+"CollectionSlot",c=Te.forwardRef((h,g)=>{const{scope:m,children:x}=h,b=o(l,m),y=it(g,b.collectionRef);return u.jsx(mo,{ref:y,children:x})});c.displayName=l;const i=e+"CollectionItemSlot",d="data-radix-collection-item",p=Te.forwardRef((h,g)=>{const{scope:m,children:x,...b}=h,y=Te.useRef(null),w=it(g,y),S=o(i,m);return Te.useEffect(()=>(S.itemMap.set(y,{ref:y,...b}),()=>void S.itemMap.delete(y))),u.jsx(mo,{[d]:"",ref:w,children:x})});p.displayName=i;function f(h){const g=o(e+"CollectionConsumer",h);return Te.useCallback(()=>{const x=g.collectionRef.current;if(!x)return[];const b=Array.from(x.querySelectorAll(`[${d}]`));return Array.from(g.itemMap.values()).sort((S,E)=>b.indexOf(S.ref.current)-b.indexOf(E.ref.current))},[g.collectionRef,g.itemMap])}return[{Provider:a,Slot:c,ItemSlot:p},f,r]}var rB=v.createContext(void 0);function Gd(e){const t=v.useContext(rB);return e||t||"ltr"}function sB(e,t=globalThis==null?void 0:globalThis.document){const n=nn(e);v.useEffect(()=>{const r=s=>{s.key==="Escape"&&n(s)};return t.addEventListener("keydown",r,{capture:!0}),()=>t.removeEventListener("keydown",r,{capture:!0})},[n,t])}var oB="DismissableLayer",Ky="dismissableLayer.update",aB="dismissableLayer.pointerDownOutside",iB="dismissableLayer.focusOutside",eC,mj=v.createContext({layers:new Set,layersWithOutsidePointerEventsDisabled:new Set,branches:new Set}),cg=v.forwardRef((e,t)=>{const{disableOutsidePointerEvents:n=!1,onEscapeKeyDown:r,onPointerDownOutside:s,onFocusOutside:o,onInteractOutside:a,onDismiss:l,...c}=e,i=v.useContext(mj),[d,p]=v.useState(null),f=(d==null?void 0:d.ownerDocument)??(globalThis==null?void 0:globalThis.document),[,h]=v.useState({}),g=it(t,k=>p(k)),m=Array.from(i.layers),[x]=[...i.layersWithOutsidePointerEventsDisabled].slice(-1),b=m.indexOf(x),y=d?m.indexOf(d):-1,w=i.layersWithOutsidePointerEventsDisabled.size>0,S=y>=b,E=cB(k=>{const T=k.target,P=[...i.branches].some(N=>N.contains(T));!S||P||(s==null||s(k),a==null||a(k),k.defaultPrevented||l==null||l())},f),C=dB(k=>{const T=k.target;[...i.branches].some(N=>N.contains(T))||(o==null||o(k),a==null||a(k),k.defaultPrevented||l==null||l())},f);return sB(k=>{y===i.layers.size-1&&(r==null||r(k),!k.defaultPrevented&&l&&(k.preventDefault(),l()))},f),v.useEffect(()=>{if(d)return n&&(i.layersWithOutsidePointerEventsDisabled.size===0&&(eC=f.body.style.pointerEvents,f.body.style.pointerEvents="none"),i.layersWithOutsidePointerEventsDisabled.add(d)),i.layers.add(d),tC(),()=>{n&&i.layersWithOutsidePointerEventsDisabled.size===1&&(f.body.style.pointerEvents=eC)}},[d,f,n,i]),v.useEffect(()=>()=>{d&&(i.layers.delete(d),i.layersWithOutsidePointerEventsDisabled.delete(d),tC())},[d,i]),v.useEffect(()=>{const k=()=>h({});return document.addEventListener(Ky,k),()=>document.removeEventListener(Ky,k)},[]),u.jsx(Ne.div,{...c,ref:g,style:{pointerEvents:w?S?"auto":"none":void 0,...e.style},onFocusCapture:Se(e.onFocusCapture,C.onFocusCapture),onBlurCapture:Se(e.onBlurCapture,C.onBlurCapture),onPointerDownCapture:Se(e.onPointerDownCapture,E.onPointerDownCapture)})});cg.displayName=oB;var lB="DismissableLayerBranch",uB=v.forwardRef((e,t)=>{const n=v.useContext(mj),r=v.useRef(null),s=it(t,r);return v.useEffect(()=>{const o=r.current;if(o)return n.branches.add(o),()=>{n.branches.delete(o)}},[n.branches]),u.jsx(Ne.div,{...e,ref:s})});uB.displayName=lB;function cB(e,t=globalThis==null?void 0:globalThis.document){const n=nn(e),r=v.useRef(!1),s=v.useRef(()=>{});return v.useEffect(()=>{const o=l=>{if(l.target&&!r.current){let c=function(){vj(aB,n,i,{discrete:!0})};const i={originalEvent:l};l.pointerType==="touch"?(t.removeEventListener("click",s.current),s.current=c,t.addEventListener("click",s.current,{once:!0})):c()}else t.removeEventListener("click",s.current);r.current=!1},a=window.setTimeout(()=>{t.addEventListener("pointerdown",o)},0);return()=>{window.clearTimeout(a),t.removeEventListener("pointerdown",o),t.removeEventListener("click",s.current)}},[t,n]),{onPointerDownCapture:()=>r.current=!0}}function dB(e,t=globalThis==null?void 0:globalThis.document){const n=nn(e),r=v.useRef(!1);return v.useEffect(()=>{const s=o=>{o.target&&!r.current&&vj(iB,n,{originalEvent:o},{discrete:!1})};return t.addEventListener("focusin",s),()=>t.removeEventListener("focusin",s)},[t,n]),{onFocusCapture:()=>r.current=!0,onBlurCapture:()=>r.current=!1}}function tC(){const e=new CustomEvent(Ky);document.dispatchEvent(e)}function vj(e,t,n,{discrete:r}){const s=n.originalEvent.target,o=new CustomEvent(e,{bubbles:!1,cancelable:!0,detail:n});t&&s.addEventListener(e,t,{once:!0}),r?gj(s,o):s.dispatchEvent(o)}var zm=0;function Lx(){v.useEffect(()=>{const e=document.querySelectorAll("[data-radix-focus-guard]");return document.body.insertAdjacentElement("afterbegin",e[0]??nC()),document.body.insertAdjacentElement("beforeend",e[1]??nC()),zm++,()=>{zm===1&&document.querySelectorAll("[data-radix-focus-guard]").forEach(t=>t.remove()),zm--}},[])}function nC(){const e=document.createElement("span");return e.setAttribute("data-radix-focus-guard",""),e.tabIndex=0,e.style.cssText="outline: none; opacity: 0; position: fixed; pointer-events: none",e}var Um="focusScope.autoFocusOnMount",Vm="focusScope.autoFocusOnUnmount",rC={bubbles:!1,cancelable:!0},fB="FocusScope",dg=v.forwardRef((e,t)=>{const{loop:n=!1,trapped:r=!1,onMountAutoFocus:s,onUnmountAutoFocus:o,...a}=e,[l,c]=v.useState(null),i=nn(s),d=nn(o),p=v.useRef(null),f=it(t,m=>c(m)),h=v.useRef({paused:!1,pause(){this.paused=!0},resume(){this.paused=!1}}).current;v.useEffect(()=>{if(r){let m=function(w){if(h.paused||!l)return;const S=w.target;l.contains(S)?p.current=S:Lo(p.current,{select:!0})},x=function(w){if(h.paused||!l)return;const S=w.relatedTarget;S!==null&&(l.contains(S)||Lo(p.current,{select:!0}))},b=function(w){if(document.activeElement===document.body)for(const E of w)E.removedNodes.length>0&&Lo(l)};document.addEventListener("focusin",m),document.addEventListener("focusout",x);const y=new MutationObserver(b);return l&&y.observe(l,{childList:!0,subtree:!0}),()=>{document.removeEventListener("focusin",m),document.removeEventListener("focusout",x),y.disconnect()}}},[r,l,h.paused]),v.useEffect(()=>{if(l){oC.add(h);const m=document.activeElement;if(!l.contains(m)){const b=new CustomEvent(Um,rC);l.addEventListener(Um,i),l.dispatchEvent(b),b.defaultPrevented||(pB(yB(yj(l)),{select:!0}),document.activeElement===m&&Lo(l))}return()=>{l.removeEventListener(Um,i),setTimeout(()=>{const b=new CustomEvent(Vm,rC);l.addEventListener(Vm,d),l.dispatchEvent(b),b.defaultPrevented||Lo(m??document.body,{select:!0}),l.removeEventListener(Vm,d),oC.remove(h)},0)}}},[l,i,d,h]);const g=v.useCallback(m=>{if(!n&&!r||h.paused)return;const x=m.key==="Tab"&&!m.altKey&&!m.ctrlKey&&!m.metaKey,b=document.activeElement;if(x&&b){const y=m.currentTarget,[w,S]=hB(y);w&&S?!m.shiftKey&&b===S?(m.preventDefault(),n&&Lo(w,{select:!0})):m.shiftKey&&b===w&&(m.preventDefault(),n&&Lo(S,{select:!0})):b===y&&m.preventDefault()}},[n,r,h.paused]);return u.jsx(Ne.div,{tabIndex:-1,...a,ref:f,onKeyDown:g})});dg.displayName=fB;function pB(e,{select:t=!1}={}){const n=document.activeElement;for(const r of e)if(Lo(r,{select:t}),document.activeElement!==n)return}function hB(e){const t=yj(e),n=sC(t,e),r=sC(t.reverse(),e);return[n,r]}function yj(e){const t=[],n=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT,{acceptNode:r=>{const s=r.tagName==="INPUT"&&r.type==="hidden";return r.disabled||r.hidden||s?NodeFilter.FILTER_SKIP:r.tabIndex>=0?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_SKIP}});for(;n.nextNode();)t.push(n.currentNode);return t}function sC(e,t){for(const n of e)if(!gB(n,{upTo:t}))return n}function gB(e,{upTo:t}){if(getComputedStyle(e).visibility==="hidden")return!0;for(;e;){if(t!==void 0&&e===t)return!1;if(getComputedStyle(e).display==="none")return!0;e=e.parentElement}return!1}function mB(e){return e instanceof HTMLInputElement&&"select"in e}function Lo(e,{select:t=!1}={}){if(e&&e.focus){const n=document.activeElement;e.focus({preventScroll:!0}),e!==n&&mB(e)&&t&&e.select()}}var oC=vB();function vB(){let e=[];return{add(t){const n=e[0];t!==n&&(n==null||n.pause()),e=aC(e,t),e.unshift(t)},remove(t){var n;e=aC(e,t),(n=e[0])==null||n.resume()}}}function aC(e,t){const n=[...e],r=n.indexOf(t);return r!==-1&&n.splice(r,1),n}function yB(e){return e.filter(t=>t.tagName!=="A")}var fn=globalThis!=null&&globalThis.document?v.useLayoutEffect:()=>{},bB=Nh.useId||(()=>{}),xB=0;function os(e){const[t,n]=v.useState(bB());return fn(()=>{n(r=>r??String(xB++))},[e]),t?`radix-${t}`:""}const wB=["top","right","bottom","left"],Ms=Math.min,pr=Math.max,nh=Math.round,Mf=Math.floor,ha=e=>({x:e,y:e}),SB={left:"right",right:"left",bottom:"top",top:"bottom"},CB={start:"end",end:"start"};function qy(e,t,n){return pr(e,Ms(t,n))}function vo(e,t){return typeof e=="function"?e(t):e}function yo(e){return e.split("-")[0]}function yu(e){return e.split("-")[1]}function $x(e){return e==="x"?"y":"x"}function Bx(e){return e==="y"?"height":"width"}function ga(e){return["top","bottom"].includes(yo(e))?"y":"x"}function zx(e){return $x(ga(e))}function EB(e,t,n){n===void 0&&(n=!1);const r=yu(e),s=zx(e),o=Bx(s);let a=s==="x"?r===(n?"end":"start")?"right":"left":r==="start"?"bottom":"top";return t.reference[o]>t.floating[o]&&(a=rh(a)),[a,rh(a)]}function TB(e){const t=rh(e);return[Wy(e),t,Wy(t)]}function Wy(e){return e.replace(/start|end/g,t=>CB[t])}function kB(e,t,n){const r=["left","right"],s=["right","left"],o=["top","bottom"],a=["bottom","top"];switch(e){case"top":case"bottom":return n?t?s:r:t?r:s;case"left":case"right":return t?o:a;default:return[]}}function _B(e,t,n,r){const s=yu(e);let o=kB(yo(e),n==="start",r);return s&&(o=o.map(a=>a+"-"+s),t&&(o=o.concat(o.map(Wy)))),o}function rh(e){return e.replace(/left|right|bottom|top/g,t=>SB[t])}function jB(e){return{top:0,right:0,bottom:0,left:0,...e}}function bj(e){return typeof e!="number"?jB(e):{top:e,right:e,bottom:e,left:e}}function sh(e){const{x:t,y:n,width:r,height:s}=e;return{width:r,height:s,top:n,left:t,right:t+r,bottom:n+s,x:t,y:n}}function iC(e,t,n){let{reference:r,floating:s}=e;const o=ga(t),a=zx(t),l=Bx(a),c=yo(t),i=o==="y",d=r.x+r.width/2-s.width/2,p=r.y+r.height/2-s.height/2,f=r[l]/2-s[l]/2;let h;switch(c){case"top":h={x:d,y:r.y-s.height};break;case"bottom":h={x:d,y:r.y+r.height};break;case"right":h={x:r.x+r.width,y:p};break;case"left":h={x:r.x-s.width,y:p};break;default:h={x:r.x,y:r.y}}switch(yu(t)){case"start":h[a]-=f*(n&&i?-1:1);break;case"end":h[a]+=f*(n&&i?-1:1);break}return h}const RB=async(e,t,n)=>{const{placement:r="bottom",strategy:s="absolute",middleware:o=[],platform:a}=n,l=o.filter(Boolean),c=await(a.isRTL==null?void 0:a.isRTL(t));let i=await a.getElementRects({reference:e,floating:t,strategy:s}),{x:d,y:p}=iC(i,r,c),f=r,h={},g=0;for(let m=0;m({name:"arrow",options:e,async fn(t){const{x:n,y:r,placement:s,rects:o,platform:a,elements:l,middlewareData:c}=t,{element:i,padding:d=0}=vo(e,t)||{};if(i==null)return{};const p=bj(d),f={x:n,y:r},h=zx(s),g=Bx(h),m=await a.getDimensions(i),x=h==="y",b=x?"top":"left",y=x?"bottom":"right",w=x?"clientHeight":"clientWidth",S=o.reference[g]+o.reference[h]-f[h]-o.floating[g],E=f[h]-o.reference[h],C=await(a.getOffsetParent==null?void 0:a.getOffsetParent(i));let k=C?C[w]:0;(!k||!await(a.isElement==null?void 0:a.isElement(C)))&&(k=l.floating[w]||o.floating[g]);const T=S/2-E/2,P=k/2-m[g]/2-1,N=Ms(p[b],P),U=Ms(p[y],P),I=N,Z=k-m[g]-U,V=k/2-m[g]/2+T,Q=qy(I,V,Z),ee=!c.arrow&&yu(s)!=null&&V!==Q&&o.reference[g]/2-(VV<=0)){var U,I;const V=(((U=o.flip)==null?void 0:U.index)||0)+1,Q=k[V];if(Q)return{data:{index:V,overflows:N},reset:{placement:Q}};let ee=(I=N.filter(W=>W.overflows[0]<=0).sort((W,F)=>W.overflows[1]-F.overflows[1])[0])==null?void 0:I.placement;if(!ee)switch(h){case"bestFit":{var Z;const W=(Z=N.filter(F=>{if(C){const A=ga(F.placement);return A===y||A==="y"}return!0}).map(F=>[F.placement,F.overflows.filter(A=>A>0).reduce((A,Y)=>A+Y,0)]).sort((F,A)=>F[1]-A[1])[0])==null?void 0:Z[0];W&&(ee=W);break}case"initialPlacement":ee=l;break}if(s!==ee)return{reset:{placement:ee}}}return{}}}};function lC(e,t){return{top:e.top-t.height,right:e.right-t.width,bottom:e.bottom-t.height,left:e.left-t.width}}function uC(e){return wB.some(t=>e[t]>=0)}const OB=function(e){return e===void 0&&(e={}),{name:"hide",options:e,async fn(t){const{rects:n}=t,{strategy:r="referenceHidden",...s}=vo(e,t);switch(r){case"referenceHidden":{const o=await ad(t,{...s,elementContext:"reference"}),a=lC(o,n.reference);return{data:{referenceHiddenOffsets:a,referenceHidden:uC(a)}}}case"escaped":{const o=await ad(t,{...s,altBoundary:!0}),a=lC(o,n.floating);return{data:{escapedOffsets:a,escaped:uC(a)}}}default:return{}}}}};async function NB(e,t){const{placement:n,platform:r,elements:s}=e,o=await(r.isRTL==null?void 0:r.isRTL(s.floating)),a=yo(n),l=yu(n),c=ga(n)==="y",i=["left","top"].includes(a)?-1:1,d=o&&c?-1:1,p=vo(t,e);let{mainAxis:f,crossAxis:h,alignmentAxis:g}=typeof p=="number"?{mainAxis:p,crossAxis:0,alignmentAxis:null}:{mainAxis:0,crossAxis:0,alignmentAxis:null,...p};return l&&typeof g=="number"&&(h=l==="end"?g*-1:g),c?{x:h*d,y:f*i}:{x:f*i,y:h*d}}const IB=function(e){return e===void 0&&(e=0),{name:"offset",options:e,async fn(t){var n,r;const{x:s,y:o,placement:a,middlewareData:l}=t,c=await NB(t,e);return a===((n=l.offset)==null?void 0:n.placement)&&(r=l.arrow)!=null&&r.alignmentOffset?{}:{x:s+c.x,y:o+c.y,data:{...c,placement:a}}}}},DB=function(e){return e===void 0&&(e={}),{name:"shift",options:e,async fn(t){const{x:n,y:r,placement:s}=t,{mainAxis:o=!0,crossAxis:a=!1,limiter:l={fn:x=>{let{x:b,y}=x;return{x:b,y}}},...c}=vo(e,t),i={x:n,y:r},d=await ad(t,c),p=ga(yo(s)),f=$x(p);let h=i[f],g=i[p];if(o){const x=f==="y"?"top":"left",b=f==="y"?"bottom":"right",y=h+d[x],w=h-d[b];h=qy(y,h,w)}if(a){const x=p==="y"?"top":"left",b=p==="y"?"bottom":"right",y=g+d[x],w=g-d[b];g=qy(y,g,w)}const m=l.fn({...t,[f]:h,[p]:g});return{...m,data:{x:m.x-n,y:m.y-r}}}}},AB=function(e){return e===void 0&&(e={}),{options:e,fn(t){const{x:n,y:r,placement:s,rects:o,middlewareData:a}=t,{offset:l=0,mainAxis:c=!0,crossAxis:i=!0}=vo(e,t),d={x:n,y:r},p=ga(s),f=$x(p);let h=d[f],g=d[p];const m=vo(l,t),x=typeof m=="number"?{mainAxis:m,crossAxis:0}:{mainAxis:0,crossAxis:0,...m};if(c){const w=f==="y"?"height":"width",S=o.reference[f]-o.floating[w]+x.mainAxis,E=o.reference[f]+o.reference[w]-x.mainAxis;hE&&(h=E)}if(i){var b,y;const w=f==="y"?"width":"height",S=["top","left"].includes(yo(s)),E=o.reference[p]-o.floating[w]+(S&&((b=a.offset)==null?void 0:b[p])||0)+(S?0:x.crossAxis),C=o.reference[p]+o.reference[w]+(S?0:((y=a.offset)==null?void 0:y[p])||0)-(S?x.crossAxis:0);gC&&(g=C)}return{[f]:h,[p]:g}}}},FB=function(e){return e===void 0&&(e={}),{name:"size",options:e,async fn(t){const{placement:n,rects:r,platform:s,elements:o}=t,{apply:a=()=>{},...l}=vo(e,t),c=await ad(t,l),i=yo(n),d=yu(n),p=ga(n)==="y",{width:f,height:h}=r.floating;let g,m;i==="top"||i==="bottom"?(g=i,m=d===(await(s.isRTL==null?void 0:s.isRTL(o.floating))?"start":"end")?"left":"right"):(m=i,g=d==="end"?"top":"bottom");const x=h-c.top-c.bottom,b=f-c.left-c.right,y=Ms(h-c[g],x),w=Ms(f-c[m],b),S=!t.middlewareData.shift;let E=y,C=w;if(p?C=d||S?Ms(w,b):b:E=d||S?Ms(y,x):x,S&&!d){const T=pr(c.left,0),P=pr(c.right,0),N=pr(c.top,0),U=pr(c.bottom,0);p?C=f-2*(T!==0||P!==0?T+P:pr(c.left,c.right)):E=h-2*(N!==0||U!==0?N+U:pr(c.top,c.bottom))}await a({...t,availableWidth:C,availableHeight:E});const k=await s.getDimensions(o.floating);return f!==k.width||h!==k.height?{reset:{rects:!0}}:{}}}};function bu(e){return xj(e)?(e.nodeName||"").toLowerCase():"#document"}function vr(e){var t;return(e==null||(t=e.ownerDocument)==null?void 0:t.defaultView)||window}function Co(e){var t;return(t=(xj(e)?e.ownerDocument:e.document)||window.document)==null?void 0:t.documentElement}function xj(e){return e instanceof Node||e instanceof vr(e).Node}function $s(e){return e instanceof Element||e instanceof vr(e).Element}function Bs(e){return e instanceof HTMLElement||e instanceof vr(e).HTMLElement}function cC(e){return typeof ShadowRoot>"u"?!1:e instanceof ShadowRoot||e instanceof vr(e).ShadowRoot}function Jd(e){const{overflow:t,overflowX:n,overflowY:r,display:s}=cs(e);return/auto|scroll|overlay|hidden|clip/.test(t+r+n)&&!["inline","contents"].includes(s)}function LB(e){return["table","td","th"].includes(bu(e))}function fg(e){return[":popover-open",":modal"].some(t=>{try{return e.matches(t)}catch{return!1}})}function Ux(e){const t=Vx(),n=cs(e);return n.transform!=="none"||n.perspective!=="none"||(n.containerType?n.containerType!=="normal":!1)||!t&&(n.backdropFilter?n.backdropFilter!=="none":!1)||!t&&(n.filter?n.filter!=="none":!1)||["transform","perspective","filter"].some(r=>(n.willChange||"").includes(r))||["paint","layout","strict","content"].some(r=>(n.contain||"").includes(r))}function $B(e){let t=ma(e);for(;Bs(t)&&!eu(t);){if(fg(t))return null;if(Ux(t))return t;t=ma(t)}return null}function Vx(){return typeof CSS>"u"||!CSS.supports?!1:CSS.supports("-webkit-backdrop-filter","none")}function eu(e){return["html","body","#document"].includes(bu(e))}function cs(e){return vr(e).getComputedStyle(e)}function pg(e){return $s(e)?{scrollLeft:e.scrollLeft,scrollTop:e.scrollTop}:{scrollLeft:e.scrollX,scrollTop:e.scrollY}}function ma(e){if(bu(e)==="html")return e;const t=e.assignedSlot||e.parentNode||cC(e)&&e.host||Co(e);return cC(t)?t.host:t}function wj(e){const t=ma(e);return eu(t)?e.ownerDocument?e.ownerDocument.body:e.body:Bs(t)&&Jd(t)?t:wj(t)}function id(e,t,n){var r;t===void 0&&(t=[]),n===void 0&&(n=!0);const s=wj(e),o=s===((r=e.ownerDocument)==null?void 0:r.body),a=vr(s);return o?t.concat(a,a.visualViewport||[],Jd(s)?s:[],a.frameElement&&n?id(a.frameElement):[]):t.concat(s,id(s,[],n))}function Sj(e){const t=cs(e);let n=parseFloat(t.width)||0,r=parseFloat(t.height)||0;const s=Bs(e),o=s?e.offsetWidth:n,a=s?e.offsetHeight:r,l=nh(n)!==o||nh(r)!==a;return l&&(n=o,r=a),{width:n,height:r,$:l}}function Hx(e){return $s(e)?e:e.contextElement}function kl(e){const t=Hx(e);if(!Bs(t))return ha(1);const n=t.getBoundingClientRect(),{width:r,height:s,$:o}=Sj(t);let a=(o?nh(n.width):n.width)/r,l=(o?nh(n.height):n.height)/s;return(!a||!Number.isFinite(a))&&(a=1),(!l||!Number.isFinite(l))&&(l=1),{x:a,y:l}}const BB=ha(0);function Cj(e){const t=vr(e);return!Vx()||!t.visualViewport?BB:{x:t.visualViewport.offsetLeft,y:t.visualViewport.offsetTop}}function zB(e,t,n){return t===void 0&&(t=!1),!n||t&&n!==vr(e)?!1:t}function Ci(e,t,n,r){t===void 0&&(t=!1),n===void 0&&(n=!1);const s=e.getBoundingClientRect(),o=Hx(e);let a=ha(1);t&&(r?$s(r)&&(a=kl(r)):a=kl(e));const l=zB(o,n,r)?Cj(o):ha(0);let c=(s.left+l.x)/a.x,i=(s.top+l.y)/a.y,d=s.width/a.x,p=s.height/a.y;if(o){const f=vr(o),h=r&&$s(r)?vr(r):r;let g=f,m=g.frameElement;for(;m&&r&&h!==g;){const x=kl(m),b=m.getBoundingClientRect(),y=cs(m),w=b.left+(m.clientLeft+parseFloat(y.paddingLeft))*x.x,S=b.top+(m.clientTop+parseFloat(y.paddingTop))*x.y;c*=x.x,i*=x.y,d*=x.x,p*=x.y,c+=w,i+=S,g=vr(m),m=g.frameElement}}return sh({width:d,height:p,x:c,y:i})}function UB(e){let{elements:t,rect:n,offsetParent:r,strategy:s}=e;const o=s==="fixed",a=Co(r),l=t?fg(t.floating):!1;if(r===a||l&&o)return n;let c={scrollLeft:0,scrollTop:0},i=ha(1);const d=ha(0),p=Bs(r);if((p||!p&&!o)&&((bu(r)!=="body"||Jd(a))&&(c=pg(r)),Bs(r))){const f=Ci(r);i=kl(r),d.x=f.x+r.clientLeft,d.y=f.y+r.clientTop}return{width:n.width*i.x,height:n.height*i.y,x:n.x*i.x-c.scrollLeft*i.x+d.x,y:n.y*i.y-c.scrollTop*i.y+d.y}}function VB(e){return Array.from(e.getClientRects())}function Ej(e){return Ci(Co(e)).left+pg(e).scrollLeft}function HB(e){const t=Co(e),n=pg(e),r=e.ownerDocument.body,s=pr(t.scrollWidth,t.clientWidth,r.scrollWidth,r.clientWidth),o=pr(t.scrollHeight,t.clientHeight,r.scrollHeight,r.clientHeight);let a=-n.scrollLeft+Ej(e);const l=-n.scrollTop;return cs(r).direction==="rtl"&&(a+=pr(t.clientWidth,r.clientWidth)-s),{width:s,height:o,x:a,y:l}}function KB(e,t){const n=vr(e),r=Co(e),s=n.visualViewport;let o=r.clientWidth,a=r.clientHeight,l=0,c=0;if(s){o=s.width,a=s.height;const i=Vx();(!i||i&&t==="fixed")&&(l=s.offsetLeft,c=s.offsetTop)}return{width:o,height:a,x:l,y:c}}function qB(e,t){const n=Ci(e,!0,t==="fixed"),r=n.top+e.clientTop,s=n.left+e.clientLeft,o=Bs(e)?kl(e):ha(1),a=e.clientWidth*o.x,l=e.clientHeight*o.y,c=s*o.x,i=r*o.y;return{width:a,height:l,x:c,y:i}}function dC(e,t,n){let r;if(t==="viewport")r=KB(e,n);else if(t==="document")r=HB(Co(e));else if($s(t))r=qB(t,n);else{const s=Cj(e);r={...t,x:t.x-s.x,y:t.y-s.y}}return sh(r)}function Tj(e,t){const n=ma(e);return n===t||!$s(n)||eu(n)?!1:cs(n).position==="fixed"||Tj(n,t)}function WB(e,t){const n=t.get(e);if(n)return n;let r=id(e,[],!1).filter(l=>$s(l)&&bu(l)!=="body"),s=null;const o=cs(e).position==="fixed";let a=o?ma(e):e;for(;$s(a)&&!eu(a);){const l=cs(a),c=Ux(a);!c&&l.position==="fixed"&&(s=null),(o?!c&&!s:!c&&l.position==="static"&&!!s&&["absolute","fixed"].includes(s.position)||Jd(a)&&!c&&Tj(e,a))?r=r.filter(d=>d!==a):s=l,a=ma(a)}return t.set(e,r),r}function GB(e){let{element:t,boundary:n,rootBoundary:r,strategy:s}=e;const a=[...n==="clippingAncestors"?fg(t)?[]:WB(t,this._c):[].concat(n),r],l=a[0],c=a.reduce((i,d)=>{const p=dC(t,d,s);return i.top=pr(p.top,i.top),i.right=Ms(p.right,i.right),i.bottom=Ms(p.bottom,i.bottom),i.left=pr(p.left,i.left),i},dC(t,l,s));return{width:c.right-c.left,height:c.bottom-c.top,x:c.left,y:c.top}}function JB(e){const{width:t,height:n}=Sj(e);return{width:t,height:n}}function QB(e,t,n){const r=Bs(t),s=Co(t),o=n==="fixed",a=Ci(e,!0,o,t);let l={scrollLeft:0,scrollTop:0};const c=ha(0);if(r||!r&&!o)if((bu(t)!=="body"||Jd(s))&&(l=pg(t)),r){const p=Ci(t,!0,o,t);c.x=p.x+t.clientLeft,c.y=p.y+t.clientTop}else s&&(c.x=Ej(s));const i=a.left+l.scrollLeft-c.x,d=a.top+l.scrollTop-c.y;return{x:i,y:d,width:a.width,height:a.height}}function Hm(e){return cs(e).position==="static"}function fC(e,t){return!Bs(e)||cs(e).position==="fixed"?null:t?t(e):e.offsetParent}function kj(e,t){const n=vr(e);if(fg(e))return n;if(!Bs(e)){let s=ma(e);for(;s&&!eu(s);){if($s(s)&&!Hm(s))return s;s=ma(s)}return n}let r=fC(e,t);for(;r&&LB(r)&&Hm(r);)r=fC(r,t);return r&&eu(r)&&Hm(r)&&!Ux(r)?n:r||$B(e)||n}const ZB=async function(e){const t=this.getOffsetParent||kj,n=this.getDimensions,r=await n(e.floating);return{reference:QB(e.reference,await t(e.floating),e.strategy),floating:{x:0,y:0,width:r.width,height:r.height}}};function YB(e){return cs(e).direction==="rtl"}const XB={convertOffsetParentRelativeRectToViewportRelativeRect:UB,getDocumentElement:Co,getClippingRect:GB,getOffsetParent:kj,getElementRects:ZB,getClientRects:VB,getDimensions:JB,getScale:kl,isElement:$s,isRTL:YB};function ez(e,t){let n=null,r;const s=Co(e);function o(){var l;clearTimeout(r),(l=n)==null||l.disconnect(),n=null}function a(l,c){l===void 0&&(l=!1),c===void 0&&(c=1),o();const{left:i,top:d,width:p,height:f}=e.getBoundingClientRect();if(l||t(),!p||!f)return;const h=Mf(d),g=Mf(s.clientWidth-(i+p)),m=Mf(s.clientHeight-(d+f)),x=Mf(i),y={rootMargin:-h+"px "+-g+"px "+-m+"px "+-x+"px",threshold:pr(0,Ms(1,c))||1};let w=!0;function S(E){const C=E[0].intersectionRatio;if(C!==c){if(!w)return a();C?a(!1,C):r=setTimeout(()=>{a(!1,1e-7)},1e3)}w=!1}try{n=new IntersectionObserver(S,{...y,root:s.ownerDocument})}catch{n=new IntersectionObserver(S,y)}n.observe(e)}return a(!0),o}function tz(e,t,n,r){r===void 0&&(r={});const{ancestorScroll:s=!0,ancestorResize:o=!0,elementResize:a=typeof ResizeObserver=="function",layoutShift:l=typeof IntersectionObserver=="function",animationFrame:c=!1}=r,i=Hx(e),d=s||o?[...i?id(i):[],...id(t)]:[];d.forEach(b=>{s&&b.addEventListener("scroll",n,{passive:!0}),o&&b.addEventListener("resize",n)});const p=i&&l?ez(i,n):null;let f=-1,h=null;a&&(h=new ResizeObserver(b=>{let[y]=b;y&&y.target===i&&h&&(h.unobserve(t),cancelAnimationFrame(f),f=requestAnimationFrame(()=>{var w;(w=h)==null||w.observe(t)})),n()}),i&&!c&&h.observe(i),h.observe(t));let g,m=c?Ci(e):null;c&&x();function x(){const b=Ci(e);m&&(b.x!==m.x||b.y!==m.y||b.width!==m.width||b.height!==m.height)&&n(),m=b,g=requestAnimationFrame(x)}return n(),()=>{var b;d.forEach(y=>{s&&y.removeEventListener("scroll",n),o&&y.removeEventListener("resize",n)}),p==null||p(),(b=h)==null||b.disconnect(),h=null,c&&cancelAnimationFrame(g)}}const nz=IB,rz=DB,sz=MB,oz=FB,az=OB,pC=PB,iz=AB,lz=(e,t,n)=>{const r=new Map,s={platform:XB,...n},o={...s.platform,_c:r};return RB(e,t,{...s,platform:o})};var hp=typeof document<"u"?v.useLayoutEffect:v.useEffect;function oh(e,t){if(e===t)return!0;if(typeof e!=typeof t)return!1;if(typeof e=="function"&&e.toString()===t.toString())return!0;let n,r,s;if(e&&t&&typeof e=="object"){if(Array.isArray(e)){if(n=e.length,n!==t.length)return!1;for(r=n;r--!==0;)if(!oh(e[r],t[r]))return!1;return!0}if(s=Object.keys(e),n=s.length,n!==Object.keys(t).length)return!1;for(r=n;r--!==0;)if(!{}.hasOwnProperty.call(t,s[r]))return!1;for(r=n;r--!==0;){const o=s[r];if(!(o==="_owner"&&e.$$typeof)&&!oh(e[o],t[o]))return!1}return!0}return e!==e&&t!==t}function _j(e){return typeof window>"u"?1:(e.ownerDocument.defaultView||window).devicePixelRatio||1}function hC(e,t){const n=_j(e);return Math.round(t*n)/n}function gC(e){const t=v.useRef(e);return hp(()=>{t.current=e}),t}function uz(e){e===void 0&&(e={});const{placement:t="bottom",strategy:n="absolute",middleware:r=[],platform:s,elements:{reference:o,floating:a}={},transform:l=!0,whileElementsMounted:c,open:i}=e,[d,p]=v.useState({x:0,y:0,strategy:n,placement:t,middlewareData:{},isPositioned:!1}),[f,h]=v.useState(r);oh(f,r)||h(r);const[g,m]=v.useState(null),[x,b]=v.useState(null),y=v.useCallback(W=>{W!==C.current&&(C.current=W,m(W))},[]),w=v.useCallback(W=>{W!==k.current&&(k.current=W,b(W))},[]),S=o||g,E=a||x,C=v.useRef(null),k=v.useRef(null),T=v.useRef(d),P=c!=null,N=gC(c),U=gC(s),I=v.useCallback(()=>{if(!C.current||!k.current)return;const W={placement:t,strategy:n,middleware:f};U.current&&(W.platform=U.current),lz(C.current,k.current,W).then(F=>{const A={...F,isPositioned:!0};Z.current&&!oh(T.current,A)&&(T.current=A,ka.flushSync(()=>{p(A)}))})},[f,t,n,U]);hp(()=>{i===!1&&T.current.isPositioned&&(T.current.isPositioned=!1,p(W=>({...W,isPositioned:!1})))},[i]);const Z=v.useRef(!1);hp(()=>(Z.current=!0,()=>{Z.current=!1}),[]),hp(()=>{if(S&&(C.current=S),E&&(k.current=E),S&&E){if(N.current)return N.current(S,E,I);I()}},[S,E,I,N,P]);const V=v.useMemo(()=>({reference:C,floating:k,setReference:y,setFloating:w}),[y,w]),Q=v.useMemo(()=>({reference:S,floating:E}),[S,E]),ee=v.useMemo(()=>{const W={position:n,left:0,top:0};if(!Q.floating)return W;const F=hC(Q.floating,d.x),A=hC(Q.floating,d.y);return l?{...W,transform:"translate("+F+"px, "+A+"px)",..._j(Q.floating)>=1.5&&{willChange:"transform"}}:{position:n,left:F,top:A}},[n,l,Q.floating,d.x,d.y]);return v.useMemo(()=>({...d,update:I,refs:V,elements:Q,floatingStyles:ee}),[d,I,V,Q,ee])}const cz=e=>{function t(n){return{}.hasOwnProperty.call(n,"current")}return{name:"arrow",options:e,fn(n){const{element:r,padding:s}=typeof e=="function"?e(n):e;return r&&t(r)?r.current!=null?pC({element:r.current,padding:s}).fn(n):{}:r?pC({element:r,padding:s}).fn(n):{}}}},dz=(e,t)=>({...nz(e),options:[e,t]}),fz=(e,t)=>({...rz(e),options:[e,t]}),pz=(e,t)=>({...iz(e),options:[e,t]}),hz=(e,t)=>({...sz(e),options:[e,t]}),gz=(e,t)=>({...oz(e),options:[e,t]}),mz=(e,t)=>({...az(e),options:[e,t]}),vz=(e,t)=>({...cz(e),options:[e,t]});var yz="Arrow",jj=v.forwardRef((e,t)=>{const{children:n,width:r=10,height:s=5,...o}=e;return u.jsx(Ne.svg,{...o,ref:t,width:r,height:s,viewBox:"0 0 30 10",preserveAspectRatio:"none",children:e.asChild?n:u.jsx("polygon",{points:"0,0 30,0 15,10"})})});jj.displayName=yz;var bz=jj;function Rj(e){const[t,n]=v.useState(void 0);return fn(()=>{if(e){n({width:e.offsetWidth,height:e.offsetHeight});const r=new ResizeObserver(s=>{if(!Array.isArray(s)||!s.length)return;const o=s[0];let a,l;if("borderBoxSize"in o){const c=o.borderBoxSize,i=Array.isArray(c)?c[0]:c;a=i.inlineSize,l=i.blockSize}else a=e.offsetWidth,l=e.offsetHeight;n({width:a,height:l})});return r.observe(e,{box:"border-box"}),()=>r.unobserve(e)}else n(void 0)},[e]),t}var Kx="Popper",[Pj,hg]=Vr(Kx),[xz,Mj]=Pj(Kx),Oj=e=>{const{__scopePopper:t,children:n}=e,[r,s]=v.useState(null);return u.jsx(xz,{scope:t,anchor:r,onAnchorChange:s,children:n})};Oj.displayName=Kx;var Nj="PopperAnchor",Ij=v.forwardRef((e,t)=>{const{__scopePopper:n,virtualRef:r,...s}=e,o=Mj(Nj,n),a=v.useRef(null),l=it(t,a);return v.useEffect(()=>{o.onAnchorChange((r==null?void 0:r.current)||a.current)}),r?null:u.jsx(Ne.div,{...s,ref:l})});Ij.displayName=Nj;var qx="PopperContent",[wz,Sz]=Pj(qx),Dj=v.forwardRef((e,t)=>{var J,Ce,Pe,Le,Me,me;const{__scopePopper:n,side:r="bottom",sideOffset:s=0,align:o="center",alignOffset:a=0,arrowPadding:l=0,avoidCollisions:c=!0,collisionBoundary:i=[],collisionPadding:d=0,sticky:p="partial",hideWhenDetached:f=!1,updatePositionStrategy:h="optimized",onPlaced:g,...m}=e,x=Mj(qx,n),[b,y]=v.useState(null),w=it(t,rt=>y(rt)),[S,E]=v.useState(null),C=Rj(S),k=(C==null?void 0:C.width)??0,T=(C==null?void 0:C.height)??0,P=r+(o!=="center"?"-"+o:""),N=typeof d=="number"?d:{top:0,right:0,bottom:0,left:0,...d},U=Array.isArray(i)?i:[i],I=U.length>0,Z={padding:N,boundary:U.filter(Ez),altBoundary:I},{refs:V,floatingStyles:Q,placement:ee,isPositioned:W,middlewareData:F}=uz({strategy:"fixed",placement:P,whileElementsMounted:(...rt)=>tz(...rt,{animationFrame:h==="always"}),elements:{reference:x.anchor},middleware:[dz({mainAxis:s+T,alignmentAxis:a}),c&&fz({mainAxis:!0,crossAxis:!1,limiter:p==="partial"?pz():void 0,...Z}),c&&hz({...Z}),gz({...Z,apply:({elements:rt,rects:It,availableWidth:Zt,availableHeight:Wt})=>{const{width:an,height:j}=It.reference,D=rt.floating.style;D.setProperty("--radix-popper-available-width",`${Zt}px`),D.setProperty("--radix-popper-available-height",`${Wt}px`),D.setProperty("--radix-popper-anchor-width",`${an}px`),D.setProperty("--radix-popper-anchor-height",`${j}px`)}}),S&&vz({element:S,padding:l}),Tz({arrowWidth:k,arrowHeight:T}),f&&mz({strategy:"referenceHidden",...Z})]}),[A,Y]=Lj(ee),de=nn(g);fn(()=>{W&&(de==null||de())},[W,de]);const z=(J=F.arrow)==null?void 0:J.x,se=(Ce=F.arrow)==null?void 0:Ce.y,ne=((Pe=F.arrow)==null?void 0:Pe.centerOffset)!==0,[ie,oe]=v.useState();return fn(()=>{b&&oe(window.getComputedStyle(b).zIndex)},[b]),u.jsx("div",{ref:V.setFloating,"data-radix-popper-content-wrapper":"",style:{...Q,transform:W?Q.transform:"translate(0, -200%)",minWidth:"max-content",zIndex:ie,"--radix-popper-transform-origin":[(Le=F.transformOrigin)==null?void 0:Le.x,(Me=F.transformOrigin)==null?void 0:Me.y].join(" "),...((me=F.hide)==null?void 0:me.referenceHidden)&&{visibility:"hidden",pointerEvents:"none"}},dir:e.dir,children:u.jsx(wz,{scope:n,placedSide:A,onArrowChange:E,arrowX:z,arrowY:se,shouldHideArrow:ne,children:u.jsx(Ne.div,{"data-side":A,"data-align":Y,...m,ref:w,style:{...m.style,animation:W?void 0:"none"}})})})});Dj.displayName=qx;var Aj="PopperArrow",Cz={top:"bottom",right:"left",bottom:"top",left:"right"},Fj=v.forwardRef(function(t,n){const{__scopePopper:r,...s}=t,o=Sz(Aj,r),a=Cz[o.placedSide];return u.jsx("span",{ref:o.onArrowChange,style:{position:"absolute",left:o.arrowX,top:o.arrowY,[a]:0,transformOrigin:{top:"",right:"0 0",bottom:"center 0",left:"100% 0"}[o.placedSide],transform:{top:"translateY(100%)",right:"translateY(50%) rotate(90deg) translateX(-50%)",bottom:"rotate(180deg)",left:"translateY(50%) rotate(-90deg) translateX(50%)"}[o.placedSide],visibility:o.shouldHideArrow?"hidden":void 0},children:u.jsx(bz,{...s,ref:n,style:{...s.style,display:"block"}})})});Fj.displayName=Aj;function Ez(e){return e!==null}var Tz=e=>({name:"transformOrigin",options:e,fn(t){var x,b,y;const{placement:n,rects:r,middlewareData:s}=t,a=((x=s.arrow)==null?void 0:x.centerOffset)!==0,l=a?0:e.arrowWidth,c=a?0:e.arrowHeight,[i,d]=Lj(n),p={start:"0%",center:"50%",end:"100%"}[d],f=(((b=s.arrow)==null?void 0:b.x)??0)+l/2,h=(((y=s.arrow)==null?void 0:y.y)??0)+c/2;let g="",m="";return i==="bottom"?(g=a?p:`${f}px`,m=`${-c}px`):i==="top"?(g=a?p:`${f}px`,m=`${r.floating.height+c}px`):i==="right"?(g=`${-c}px`,m=a?p:`${h}px`):i==="left"&&(g=`${r.floating.width+c}px`,m=a?p:`${h}px`),{data:{x:g,y:m}}}});function Lj(e){const[t,n="center"]=e.split("-");return[t,n]}var $j=Oj,Bj=Ij,zj=Dj,Uj=Fj,kz="Portal",gg=v.forwardRef((e,t)=>{var l;const{container:n,...r}=e,[s,o]=v.useState(!1);fn(()=>o(!0),[]);const a=n||s&&((l=globalThis==null?void 0:globalThis.document)==null?void 0:l.body);return a?t_.createPortal(u.jsx(Ne.div,{...r,ref:t}),a):null});gg.displayName=kz;function _z(e,t){return v.useReducer((n,r)=>t[n][r]??n,e)}var or=e=>{const{present:t,children:n}=e,r=jz(t),s=typeof n=="function"?n({present:r.isPresent}):v.Children.only(n),o=it(r.ref,Rz(s));return typeof n=="function"||r.isPresent?v.cloneElement(s,{ref:o}):null};or.displayName="Presence";function jz(e){const[t,n]=v.useState(),r=v.useRef({}),s=v.useRef(e),o=v.useRef("none"),a=e?"mounted":"unmounted",[l,c]=_z(a,{mounted:{UNMOUNT:"unmounted",ANIMATION_OUT:"unmountSuspended"},unmountSuspended:{MOUNT:"mounted",ANIMATION_END:"unmounted"},unmounted:{MOUNT:"mounted"}});return v.useEffect(()=>{const i=Of(r.current);o.current=l==="mounted"?i:"none"},[l]),fn(()=>{const i=r.current,d=s.current;if(d!==e){const f=o.current,h=Of(i);e?c("MOUNT"):h==="none"||(i==null?void 0:i.display)==="none"?c("UNMOUNT"):c(d&&f!==h?"ANIMATION_OUT":"UNMOUNT"),s.current=e}},[e,c]),fn(()=>{if(t){const i=p=>{const h=Of(r.current).includes(p.animationName);p.target===t&&h&&ka.flushSync(()=>c("ANIMATION_END"))},d=p=>{p.target===t&&(o.current=Of(r.current))};return t.addEventListener("animationstart",d),t.addEventListener("animationcancel",i),t.addEventListener("animationend",i),()=>{t.removeEventListener("animationstart",d),t.removeEventListener("animationcancel",i),t.removeEventListener("animationend",i)}}else c("ANIMATION_END")},[t,c]),{isPresent:["mounted","unmountSuspended"].includes(l),ref:v.useCallback(i=>{i&&(r.current=getComputedStyle(i)),n(i)},[])}}function Of(e){return(e==null?void 0:e.animationName)||"none"}function Rz(e){var r,s;let t=(r=Object.getOwnPropertyDescriptor(e.props,"ref"))==null?void 0:r.get,n=t&&"isReactWarning"in t&&t.isReactWarning;return n?e.ref:(t=(s=Object.getOwnPropertyDescriptor(e,"ref"))==null?void 0:s.get,n=t&&"isReactWarning"in t&&t.isReactWarning,n?e.props.ref:e.props.ref||e.ref)}var Km="rovingFocusGroup.onEntryFocus",Pz={bubbles:!1,cancelable:!0},mg="RovingFocusGroup",[Gy,Vj,Mz]=Fx(mg),[Oz,vg]=Vr(mg,[Mz]),[Nz,Iz]=Oz(mg),Hj=v.forwardRef((e,t)=>u.jsx(Gy.Provider,{scope:e.__scopeRovingFocusGroup,children:u.jsx(Gy.Slot,{scope:e.__scopeRovingFocusGroup,children:u.jsx(Dz,{...e,ref:t})})}));Hj.displayName=mg;var Dz=v.forwardRef((e,t)=>{const{__scopeRovingFocusGroup:n,orientation:r,loop:s=!1,dir:o,currentTabStopId:a,defaultCurrentTabStopId:l,onCurrentTabStopIdChange:c,onEntryFocus:i,preventScrollOnEntryFocus:d=!1,...p}=e,f=v.useRef(null),h=it(t,f),g=Gd(o),[m=null,x]=pa({prop:a,defaultProp:l,onChange:c}),[b,y]=v.useState(!1),w=nn(i),S=Vj(n),E=v.useRef(!1),[C,k]=v.useState(0);return v.useEffect(()=>{const T=f.current;if(T)return T.addEventListener(Km,w),()=>T.removeEventListener(Km,w)},[w]),u.jsx(Nz,{scope:n,orientation:r,dir:g,loop:s,currentTabStopId:m,onItemFocus:v.useCallback(T=>x(T),[x]),onItemShiftTab:v.useCallback(()=>y(!0),[]),onFocusableItemAdd:v.useCallback(()=>k(T=>T+1),[]),onFocusableItemRemove:v.useCallback(()=>k(T=>T-1),[]),children:u.jsx(Ne.div,{tabIndex:b||C===0?-1:0,"data-orientation":r,...p,ref:h,style:{outline:"none",...e.style},onMouseDown:Se(e.onMouseDown,()=>{E.current=!0}),onFocus:Se(e.onFocus,T=>{const P=!E.current;if(T.target===T.currentTarget&&P&&!b){const N=new CustomEvent(Km,Pz);if(T.currentTarget.dispatchEvent(N),!N.defaultPrevented){const U=S().filter(ee=>ee.focusable),I=U.find(ee=>ee.active),Z=U.find(ee=>ee.id===m),Q=[I,Z,...U].filter(Boolean).map(ee=>ee.ref.current);Wj(Q,d)}}E.current=!1}),onBlur:Se(e.onBlur,()=>y(!1))})})}),Kj="RovingFocusGroupItem",qj=v.forwardRef((e,t)=>{const{__scopeRovingFocusGroup:n,focusable:r=!0,active:s=!1,tabStopId:o,...a}=e,l=os(),c=o||l,i=Iz(Kj,n),d=i.currentTabStopId===c,p=Vj(n),{onFocusableItemAdd:f,onFocusableItemRemove:h}=i;return v.useEffect(()=>{if(r)return f(),()=>h()},[r,f,h]),u.jsx(Gy.ItemSlot,{scope:n,id:c,focusable:r,active:s,children:u.jsx(Ne.span,{tabIndex:d?0:-1,"data-orientation":i.orientation,...a,ref:t,onMouseDown:Se(e.onMouseDown,g=>{r?i.onItemFocus(c):g.preventDefault()}),onFocus:Se(e.onFocus,()=>i.onItemFocus(c)),onKeyDown:Se(e.onKeyDown,g=>{if(g.key==="Tab"&&g.shiftKey){i.onItemShiftTab();return}if(g.target!==g.currentTarget)return;const m=Lz(g,i.orientation,i.dir);if(m!==void 0){if(g.metaKey||g.ctrlKey||g.altKey||g.shiftKey)return;g.preventDefault();let b=p().filter(y=>y.focusable).map(y=>y.ref.current);if(m==="last")b.reverse();else if(m==="prev"||m==="next"){m==="prev"&&b.reverse();const y=b.indexOf(g.currentTarget);b=i.loop?$z(b,y+1):b.slice(y+1)}setTimeout(()=>Wj(b))}})})})});qj.displayName=Kj;var Az={ArrowLeft:"prev",ArrowUp:"prev",ArrowRight:"next",ArrowDown:"next",PageUp:"first",Home:"first",PageDown:"last",End:"last"};function Fz(e,t){return t!=="rtl"?e:e==="ArrowLeft"?"ArrowRight":e==="ArrowRight"?"ArrowLeft":e}function Lz(e,t,n){const r=Fz(e.key,n);if(!(t==="vertical"&&["ArrowLeft","ArrowRight"].includes(r))&&!(t==="horizontal"&&["ArrowUp","ArrowDown"].includes(r)))return Az[r]}function Wj(e,t=!1){const n=document.activeElement;for(const r of e)if(r===n||(r.focus({preventScroll:t}),document.activeElement!==n))return}function $z(e,t){return e.map((n,r)=>e[(t+r)%e.length])}var Gj=Hj,Jj=qj,Bz=function(e){if(typeof document>"u")return null;var t=Array.isArray(e)?e[0]:e;return t.ownerDocument.body},Ki=new WeakMap,Nf=new WeakMap,If={},qm=0,Qj=function(e){return e&&(e.host||Qj(e.parentNode))},zz=function(e,t){return t.map(function(n){if(e.contains(n))return n;var r=Qj(n);return r&&e.contains(r)?r:(console.error("aria-hidden",n,"in not contained inside",e,". Doing nothing"),null)}).filter(function(n){return!!n})},Uz=function(e,t,n,r){var s=zz(t,Array.isArray(e)?e:[e]);If[n]||(If[n]=new WeakMap);var o=If[n],a=[],l=new Set,c=new Set(s),i=function(p){!p||l.has(p)||(l.add(p),i(p.parentNode))};s.forEach(i);var d=function(p){!p||c.has(p)||Array.prototype.forEach.call(p.children,function(f){if(l.has(f))d(f);else try{var h=f.getAttribute(r),g=h!==null&&h!=="false",m=(Ki.get(f)||0)+1,x=(o.get(f)||0)+1;Ki.set(f,m),o.set(f,x),a.push(f),m===1&&g&&Nf.set(f,!0),x===1&&f.setAttribute(n,"true"),g||f.setAttribute(r,"true")}catch(b){console.error("aria-hidden: cannot operate on ",f,b)}})};return d(t),l.clear(),qm++,function(){a.forEach(function(p){var f=Ki.get(p)-1,h=o.get(p)-1;Ki.set(p,f),o.set(p,h),f||(Nf.has(p)||p.removeAttribute(r),Nf.delete(p)),h||p.removeAttribute(n)}),qm--,qm||(Ki=new WeakMap,Ki=new WeakMap,Nf=new WeakMap,If={})}},Wx=function(e,t,n){n===void 0&&(n="data-aria-hidden");var r=Array.from(Array.isArray(e)?e:[e]),s=Bz(e);return s?(r.push.apply(r,Array.from(s.querySelectorAll("[aria-live]"))),Uz(r,s,n,"aria-hidden")):function(){return null}},_s=function(){return _s=Object.assign||function(t){for(var n,r=1,s=arguments.length;r"u")return oU;var t=aU(e),n=document.documentElement.clientWidth,r=window.innerWidth;return{left:t[0],top:t[1],right:t[2],gap:Math.max(0,r-n+t[2]-t[0])}},lU=eR(),_l="data-scroll-locked",uU=function(e,t,n,r){var s=e.left,o=e.top,a=e.right,l=e.gap;return n===void 0&&(n="margin"),` + .`.concat(Hz,` { + overflow: hidden `).concat(r,`; + padding-right: `).concat(l,"px ").concat(r,`; + } + body[`).concat(_l,`] { + overflow: hidden `).concat(r,`; + overscroll-behavior: contain; + `).concat([t&&"position: relative ".concat(r,";"),n==="margin"&&` + padding-left: `.concat(s,`px; + padding-top: `).concat(o,`px; + padding-right: `).concat(a,`px; + margin-left:0; + margin-top:0; + margin-right: `).concat(l,"px ").concat(r,`; + `),n==="padding"&&"padding-right: ".concat(l,"px ").concat(r,";")].filter(Boolean).join(""),` + } + + .`).concat(gp,` { + right: `).concat(l,"px ").concat(r,`; + } + + .`).concat(mp,` { + margin-right: `).concat(l,"px ").concat(r,`; + } + + .`).concat(gp," .").concat(gp,` { + right: 0 `).concat(r,`; + } + + .`).concat(mp," .").concat(mp,` { + margin-right: 0 `).concat(r,`; + } + + body[`).concat(_l,`] { + `).concat(Kz,": ").concat(l,`px; + } +`)},vC=function(){var e=parseInt(document.body.getAttribute(_l)||"0",10);return isFinite(e)?e:0},cU=function(){v.useEffect(function(){return document.body.setAttribute(_l,(vC()+1).toString()),function(){var e=vC()-1;e<=0?document.body.removeAttribute(_l):document.body.setAttribute(_l,e.toString())}},[])},dU=function(e){var t=e.noRelative,n=e.noImportant,r=e.gapMode,s=r===void 0?"margin":r;cU();var o=v.useMemo(function(){return iU(s)},[s]);return v.createElement(lU,{styles:uU(o,!t,s,n?"":"!important")})},Jy=!1;if(typeof window<"u")try{var Df=Object.defineProperty({},"passive",{get:function(){return Jy=!0,!0}});window.addEventListener("test",Df,Df),window.removeEventListener("test",Df,Df)}catch{Jy=!1}var qi=Jy?{passive:!1}:!1,fU=function(e){return e.tagName==="TEXTAREA"},tR=function(e,t){var n=window.getComputedStyle(e);return n[t]!=="hidden"&&!(n.overflowY===n.overflowX&&!fU(e)&&n[t]==="visible")},pU=function(e){return tR(e,"overflowY")},hU=function(e){return tR(e,"overflowX")},yC=function(e,t){var n=t.ownerDocument,r=t;do{typeof ShadowRoot<"u"&&r instanceof ShadowRoot&&(r=r.host);var s=nR(e,r);if(s){var o=rR(e,r),a=o[1],l=o[2];if(a>l)return!0}r=r.parentNode}while(r&&r!==n.body);return!1},gU=function(e){var t=e.scrollTop,n=e.scrollHeight,r=e.clientHeight;return[t,n,r]},mU=function(e){var t=e.scrollLeft,n=e.scrollWidth,r=e.clientWidth;return[t,n,r]},nR=function(e,t){return e==="v"?pU(t):hU(t)},rR=function(e,t){return e==="v"?gU(t):mU(t)},vU=function(e,t){return e==="h"&&t==="rtl"?-1:1},yU=function(e,t,n,r,s){var o=vU(e,window.getComputedStyle(t).direction),a=o*r,l=n.target,c=t.contains(l),i=!1,d=a>0,p=0,f=0;do{var h=rR(e,l),g=h[0],m=h[1],x=h[2],b=m-x-o*g;(g||b)&&nR(e,l)&&(p+=b,f+=g),l instanceof ShadowRoot?l=l.host:l=l.parentNode}while(!c&&l!==document.body||c&&(t.contains(l)||t===l));return(d&&(Math.abs(p)<1||!s)||!d&&(Math.abs(f)<1||!s))&&(i=!0),i},Af=function(e){return"changedTouches"in e?[e.changedTouches[0].clientX,e.changedTouches[0].clientY]:[0,0]},bC=function(e){return[e.deltaX,e.deltaY]},xC=function(e){return e&&"current"in e?e.current:e},bU=function(e,t){return e[0]===t[0]&&e[1]===t[1]},xU=function(e){return` + .block-interactivity-`.concat(e,` {pointer-events: none;} + .allow-interactivity-`).concat(e,` {pointer-events: all;} +`)},wU=0,Wi=[];function SU(e){var t=v.useRef([]),n=v.useRef([0,0]),r=v.useRef(),s=v.useState(wU++)[0],o=v.useState(eR)[0],a=v.useRef(e);v.useEffect(function(){a.current=e},[e]),v.useEffect(function(){if(e.inert){document.body.classList.add("block-interactivity-".concat(s));var m=Vz([e.lockRef.current],(e.shards||[]).map(xC),!0).filter(Boolean);return m.forEach(function(x){return x.classList.add("allow-interactivity-".concat(s))}),function(){document.body.classList.remove("block-interactivity-".concat(s)),m.forEach(function(x){return x.classList.remove("allow-interactivity-".concat(s))})}}},[e.inert,e.lockRef.current,e.shards]);var l=v.useCallback(function(m,x){if("touches"in m&&m.touches.length===2)return!a.current.allowPinchZoom;var b=Af(m),y=n.current,w="deltaX"in m?m.deltaX:y[0]-b[0],S="deltaY"in m?m.deltaY:y[1]-b[1],E,C=m.target,k=Math.abs(w)>Math.abs(S)?"h":"v";if("touches"in m&&k==="h"&&C.type==="range")return!1;var T=yC(k,C);if(!T)return!0;if(T?E=k:(E=k==="v"?"h":"v",T=yC(k,C)),!T)return!1;if(!r.current&&"changedTouches"in m&&(w||S)&&(r.current=E),!E)return!0;var P=r.current||E;return yU(P,x,m,P==="h"?w:S,!0)},[]),c=v.useCallback(function(m){var x=m;if(!(!Wi.length||Wi[Wi.length-1]!==o)){var b="deltaY"in x?bC(x):Af(x),y=t.current.filter(function(E){return E.name===x.type&&(E.target===x.target||x.target===E.shadowParent)&&bU(E.delta,b)})[0];if(y&&y.should){x.cancelable&&x.preventDefault();return}if(!y){var w=(a.current.shards||[]).map(xC).filter(Boolean).filter(function(E){return E.contains(x.target)}),S=w.length>0?l(x,w[0]):!a.current.noIsolation;S&&x.cancelable&&x.preventDefault()}}},[]),i=v.useCallback(function(m,x,b,y){var w={name:m,delta:x,target:b,should:y,shadowParent:CU(b)};t.current.push(w),setTimeout(function(){t.current=t.current.filter(function(S){return S!==w})},1)},[]),d=v.useCallback(function(m){n.current=Af(m),r.current=void 0},[]),p=v.useCallback(function(m){i(m.type,bC(m),m.target,l(m,e.lockRef.current))},[]),f=v.useCallback(function(m){i(m.type,Af(m),m.target,l(m,e.lockRef.current))},[]);v.useEffect(function(){return Wi.push(o),e.setCallbacks({onScrollCapture:p,onWheelCapture:p,onTouchMoveCapture:f}),document.addEventListener("wheel",c,qi),document.addEventListener("touchmove",c,qi),document.addEventListener("touchstart",d,qi),function(){Wi=Wi.filter(function(m){return m!==o}),document.removeEventListener("wheel",c,qi),document.removeEventListener("touchmove",c,qi),document.removeEventListener("touchstart",d,qi)}},[]);var h=e.removeScrollBar,g=e.inert;return v.createElement(v.Fragment,null,g?v.createElement(o,{styles:xU(s)}):null,h?v.createElement(dU,{gapMode:e.gapMode}):null)}function CU(e){for(var t=null;e!==null;)e instanceof ShadowRoot&&(t=e.host,e=e.host),e=e.parentNode;return t}const EU=Yz(Xj,SU);var bg=v.forwardRef(function(e,t){return v.createElement(yg,_s({},e,{ref:t,sideCar:EU}))});bg.classNames=yg.classNames;var Qy=["Enter"," "],TU=["ArrowDown","PageUp","Home"],sR=["ArrowUp","PageDown","End"],kU=[...TU,...sR],_U={ltr:[...Qy,"ArrowRight"],rtl:[...Qy,"ArrowLeft"]},jU={ltr:["ArrowLeft"],rtl:["ArrowRight"]},Qd="Menu",[ld,RU,PU]=Fx(Qd),[Ii,oR]=Vr(Qd,[PU,hg,vg]),xg=hg(),aR=vg(),[MU,Di]=Ii(Qd),[OU,Zd]=Ii(Qd),iR=e=>{const{__scopeMenu:t,open:n=!1,children:r,dir:s,onOpenChange:o,modal:a=!0}=e,l=xg(t),[c,i]=v.useState(null),d=v.useRef(!1),p=nn(o),f=Gd(s);return v.useEffect(()=>{const h=()=>{d.current=!0,document.addEventListener("pointerdown",g,{capture:!0,once:!0}),document.addEventListener("pointermove",g,{capture:!0,once:!0})},g=()=>d.current=!1;return document.addEventListener("keydown",h,{capture:!0}),()=>{document.removeEventListener("keydown",h,{capture:!0}),document.removeEventListener("pointerdown",g,{capture:!0}),document.removeEventListener("pointermove",g,{capture:!0})}},[]),u.jsx($j,{...l,children:u.jsx(MU,{scope:t,open:n,onOpenChange:p,content:c,onContentChange:i,children:u.jsx(OU,{scope:t,onClose:v.useCallback(()=>p(!1),[p]),isUsingKeyboardRef:d,dir:f,modal:a,children:r})})})};iR.displayName=Qd;var NU="MenuAnchor",Gx=v.forwardRef((e,t)=>{const{__scopeMenu:n,...r}=e,s=xg(n);return u.jsx(Bj,{...s,...r,ref:t})});Gx.displayName=NU;var Jx="MenuPortal",[IU,lR]=Ii(Jx,{forceMount:void 0}),uR=e=>{const{__scopeMenu:t,forceMount:n,children:r,container:s}=e,o=Di(Jx,t);return u.jsx(IU,{scope:t,forceMount:n,children:u.jsx(or,{present:n||o.open,children:u.jsx(gg,{asChild:!0,container:s,children:r})})})};uR.displayName=Jx;var $r="MenuContent",[DU,Qx]=Ii($r),cR=v.forwardRef((e,t)=>{const n=lR($r,e.__scopeMenu),{forceMount:r=n.forceMount,...s}=e,o=Di($r,e.__scopeMenu),a=Zd($r,e.__scopeMenu);return u.jsx(ld.Provider,{scope:e.__scopeMenu,children:u.jsx(or,{present:r||o.open,children:u.jsx(ld.Slot,{scope:e.__scopeMenu,children:a.modal?u.jsx(AU,{...s,ref:t}):u.jsx(FU,{...s,ref:t})})})})}),AU=v.forwardRef((e,t)=>{const n=Di($r,e.__scopeMenu),r=v.useRef(null),s=it(t,r);return v.useEffect(()=>{const o=r.current;if(o)return Wx(o)},[]),u.jsx(Zx,{...e,ref:s,trapFocus:n.open,disableOutsidePointerEvents:n.open,disableOutsideScroll:!0,onFocusOutside:Se(e.onFocusOutside,o=>o.preventDefault(),{checkForDefaultPrevented:!1}),onDismiss:()=>n.onOpenChange(!1)})}),FU=v.forwardRef((e,t)=>{const n=Di($r,e.__scopeMenu);return u.jsx(Zx,{...e,ref:t,trapFocus:!1,disableOutsidePointerEvents:!1,disableOutsideScroll:!1,onDismiss:()=>n.onOpenChange(!1)})}),Zx=v.forwardRef((e,t)=>{const{__scopeMenu:n,loop:r=!1,trapFocus:s,onOpenAutoFocus:o,onCloseAutoFocus:a,disableOutsidePointerEvents:l,onEntryFocus:c,onEscapeKeyDown:i,onPointerDownOutside:d,onFocusOutside:p,onInteractOutside:f,onDismiss:h,disableOutsideScroll:g,...m}=e,x=Di($r,n),b=Zd($r,n),y=xg(n),w=aR(n),S=RU(n),[E,C]=v.useState(null),k=v.useRef(null),T=it(t,k,x.onContentChange),P=v.useRef(0),N=v.useRef(""),U=v.useRef(0),I=v.useRef(null),Z=v.useRef("right"),V=v.useRef(0),Q=g?bg:v.Fragment,ee=g?{as:mo,allowPinchZoom:!0}:void 0,W=A=>{var J,Ce;const Y=N.current+A,de=S().filter(Pe=>!Pe.disabled),z=document.activeElement,se=(J=de.find(Pe=>Pe.ref.current===z))==null?void 0:J.textValue,ne=de.map(Pe=>Pe.textValue),ie=JU(ne,Y,se),oe=(Ce=de.find(Pe=>Pe.textValue===ie))==null?void 0:Ce.ref.current;(function Pe(Le){N.current=Le,window.clearTimeout(P.current),Le!==""&&(P.current=window.setTimeout(()=>Pe(""),1e3))})(Y),oe&&setTimeout(()=>oe.focus())};v.useEffect(()=>()=>window.clearTimeout(P.current),[]),Lx();const F=v.useCallback(A=>{var de,z;return Z.current===((de=I.current)==null?void 0:de.side)&&ZU(A,(z=I.current)==null?void 0:z.area)},[]);return u.jsx(DU,{scope:n,searchRef:N,onItemEnter:v.useCallback(A=>{F(A)&&A.preventDefault()},[F]),onItemLeave:v.useCallback(A=>{var Y;F(A)||((Y=k.current)==null||Y.focus(),C(null))},[F]),onTriggerLeave:v.useCallback(A=>{F(A)&&A.preventDefault()},[F]),pointerGraceTimerRef:U,onPointerGraceIntentChange:v.useCallback(A=>{I.current=A},[]),children:u.jsx(Q,{...ee,children:u.jsx(dg,{asChild:!0,trapped:s,onMountAutoFocus:Se(o,A=>{var Y;A.preventDefault(),(Y=k.current)==null||Y.focus({preventScroll:!0})}),onUnmountAutoFocus:a,children:u.jsx(cg,{asChild:!0,disableOutsidePointerEvents:l,onEscapeKeyDown:i,onPointerDownOutside:d,onFocusOutside:p,onInteractOutside:f,onDismiss:h,children:u.jsx(Gj,{asChild:!0,...w,dir:b.dir,orientation:"vertical",loop:r,currentTabStopId:E,onCurrentTabStopIdChange:C,onEntryFocus:Se(c,A=>{b.isUsingKeyboardRef.current||A.preventDefault()}),preventScrollOnEntryFocus:!0,children:u.jsx(zj,{role:"menu","aria-orientation":"vertical","data-state":kR(x.open),"data-radix-menu-content":"",dir:b.dir,...y,...m,ref:T,style:{outline:"none",...m.style},onKeyDown:Se(m.onKeyDown,A=>{const de=A.target.closest("[data-radix-menu-content]")===A.currentTarget,z=A.ctrlKey||A.altKey||A.metaKey,se=A.key.length===1;de&&(A.key==="Tab"&&A.preventDefault(),!z&&se&&W(A.key));const ne=k.current;if(A.target!==ne||!kU.includes(A.key))return;A.preventDefault();const oe=S().filter(J=>!J.disabled).map(J=>J.ref.current);sR.includes(A.key)&&oe.reverse(),WU(oe)}),onBlur:Se(e.onBlur,A=>{A.currentTarget.contains(A.target)||(window.clearTimeout(P.current),N.current="")}),onPointerMove:Se(e.onPointerMove,ud(A=>{const Y=A.target,de=V.current!==A.clientX;if(A.currentTarget.contains(Y)&&de){const z=A.clientX>V.current?"right":"left";Z.current=z,V.current=A.clientX}}))})})})})})})});cR.displayName=$r;var LU="MenuGroup",Yx=v.forwardRef((e,t)=>{const{__scopeMenu:n,...r}=e;return u.jsx(Ne.div,{role:"group",...r,ref:t})});Yx.displayName=LU;var $U="MenuLabel",dR=v.forwardRef((e,t)=>{const{__scopeMenu:n,...r}=e;return u.jsx(Ne.div,{...r,ref:t})});dR.displayName=$U;var ah="MenuItem",wC="menu.itemSelect",wg=v.forwardRef((e,t)=>{const{disabled:n=!1,onSelect:r,...s}=e,o=v.useRef(null),a=Zd(ah,e.__scopeMenu),l=Qx(ah,e.__scopeMenu),c=it(t,o),i=v.useRef(!1),d=()=>{const p=o.current;if(!n&&p){const f=new CustomEvent(wC,{bubbles:!0,cancelable:!0});p.addEventListener(wC,h=>r==null?void 0:r(h),{once:!0}),gj(p,f),f.defaultPrevented?i.current=!1:a.onClose()}};return u.jsx(fR,{...s,ref:c,disabled:n,onClick:Se(e.onClick,d),onPointerDown:p=>{var f;(f=e.onPointerDown)==null||f.call(e,p),i.current=!0},onPointerUp:Se(e.onPointerUp,p=>{var f;i.current||(f=p.currentTarget)==null||f.click()}),onKeyDown:Se(e.onKeyDown,p=>{const f=l.searchRef.current!=="";n||f&&p.key===" "||Qy.includes(p.key)&&(p.currentTarget.click(),p.preventDefault())})})});wg.displayName=ah;var fR=v.forwardRef((e,t)=>{const{__scopeMenu:n,disabled:r=!1,textValue:s,...o}=e,a=Qx(ah,n),l=aR(n),c=v.useRef(null),i=it(t,c),[d,p]=v.useState(!1),[f,h]=v.useState("");return v.useEffect(()=>{const g=c.current;g&&h((g.textContent??"").trim())},[o.children]),u.jsx(ld.ItemSlot,{scope:n,disabled:r,textValue:s??f,children:u.jsx(Jj,{asChild:!0,...l,focusable:!r,children:u.jsx(Ne.div,{role:"menuitem","data-highlighted":d?"":void 0,"aria-disabled":r||void 0,"data-disabled":r?"":void 0,...o,ref:i,onPointerMove:Se(e.onPointerMove,ud(g=>{r?a.onItemLeave(g):(a.onItemEnter(g),g.defaultPrevented||g.currentTarget.focus({preventScroll:!0}))})),onPointerLeave:Se(e.onPointerLeave,ud(g=>a.onItemLeave(g))),onFocus:Se(e.onFocus,()=>p(!0)),onBlur:Se(e.onBlur,()=>p(!1))})})})}),BU="MenuCheckboxItem",pR=v.forwardRef((e,t)=>{const{checked:n=!1,onCheckedChange:r,...s}=e;return u.jsx(yR,{scope:e.__scopeMenu,checked:n,children:u.jsx(wg,{role:"menuitemcheckbox","aria-checked":ih(n)?"mixed":n,...s,ref:t,"data-state":ew(n),onSelect:Se(s.onSelect,()=>r==null?void 0:r(ih(n)?!0:!n),{checkForDefaultPrevented:!1})})})});pR.displayName=BU;var hR="MenuRadioGroup",[zU,UU]=Ii(hR,{value:void 0,onValueChange:()=>{}}),gR=v.forwardRef((e,t)=>{const{value:n,onValueChange:r,...s}=e,o=nn(r);return u.jsx(zU,{scope:e.__scopeMenu,value:n,onValueChange:o,children:u.jsx(Yx,{...s,ref:t})})});gR.displayName=hR;var mR="MenuRadioItem",vR=v.forwardRef((e,t)=>{const{value:n,...r}=e,s=UU(mR,e.__scopeMenu),o=n===s.value;return u.jsx(yR,{scope:e.__scopeMenu,checked:o,children:u.jsx(wg,{role:"menuitemradio","aria-checked":o,...r,ref:t,"data-state":ew(o),onSelect:Se(r.onSelect,()=>{var a;return(a=s.onValueChange)==null?void 0:a.call(s,n)},{checkForDefaultPrevented:!1})})})});vR.displayName=mR;var Xx="MenuItemIndicator",[yR,VU]=Ii(Xx,{checked:!1}),bR=v.forwardRef((e,t)=>{const{__scopeMenu:n,forceMount:r,...s}=e,o=VU(Xx,n);return u.jsx(or,{present:r||ih(o.checked)||o.checked===!0,children:u.jsx(Ne.span,{...s,ref:t,"data-state":ew(o.checked)})})});bR.displayName=Xx;var HU="MenuSeparator",xR=v.forwardRef((e,t)=>{const{__scopeMenu:n,...r}=e;return u.jsx(Ne.div,{role:"separator","aria-orientation":"horizontal",...r,ref:t})});xR.displayName=HU;var KU="MenuArrow",wR=v.forwardRef((e,t)=>{const{__scopeMenu:n,...r}=e,s=xg(n);return u.jsx(Uj,{...s,...r,ref:t})});wR.displayName=KU;var qU="MenuSub",[qse,SR]=Ii(qU),dc="MenuSubTrigger",CR=v.forwardRef((e,t)=>{const n=Di(dc,e.__scopeMenu),r=Zd(dc,e.__scopeMenu),s=SR(dc,e.__scopeMenu),o=Qx(dc,e.__scopeMenu),a=v.useRef(null),{pointerGraceTimerRef:l,onPointerGraceIntentChange:c}=o,i={__scopeMenu:e.__scopeMenu},d=v.useCallback(()=>{a.current&&window.clearTimeout(a.current),a.current=null},[]);return v.useEffect(()=>d,[d]),v.useEffect(()=>{const p=l.current;return()=>{window.clearTimeout(p),c(null)}},[l,c]),u.jsx(Gx,{asChild:!0,...i,children:u.jsx(fR,{id:s.triggerId,"aria-haspopup":"menu","aria-expanded":n.open,"aria-controls":s.contentId,"data-state":kR(n.open),...e,ref:ag(t,s.onTriggerChange),onClick:p=>{var f;(f=e.onClick)==null||f.call(e,p),!(e.disabled||p.defaultPrevented)&&(p.currentTarget.focus(),n.open||n.onOpenChange(!0))},onPointerMove:Se(e.onPointerMove,ud(p=>{o.onItemEnter(p),!p.defaultPrevented&&!e.disabled&&!n.open&&!a.current&&(o.onPointerGraceIntentChange(null),a.current=window.setTimeout(()=>{n.onOpenChange(!0),d()},100))})),onPointerLeave:Se(e.onPointerLeave,ud(p=>{var h,g;d();const f=(h=n.content)==null?void 0:h.getBoundingClientRect();if(f){const m=(g=n.content)==null?void 0:g.dataset.side,x=m==="right",b=x?-5:5,y=f[x?"left":"right"],w=f[x?"right":"left"];o.onPointerGraceIntentChange({area:[{x:p.clientX+b,y:p.clientY},{x:y,y:f.top},{x:w,y:f.top},{x:w,y:f.bottom},{x:y,y:f.bottom}],side:m}),window.clearTimeout(l.current),l.current=window.setTimeout(()=>o.onPointerGraceIntentChange(null),300)}else{if(o.onTriggerLeave(p),p.defaultPrevented)return;o.onPointerGraceIntentChange(null)}})),onKeyDown:Se(e.onKeyDown,p=>{var h;const f=o.searchRef.current!=="";e.disabled||f&&p.key===" "||_U[r.dir].includes(p.key)&&(n.onOpenChange(!0),(h=n.content)==null||h.focus(),p.preventDefault())})})})});CR.displayName=dc;var ER="MenuSubContent",TR=v.forwardRef((e,t)=>{const n=lR($r,e.__scopeMenu),{forceMount:r=n.forceMount,...s}=e,o=Di($r,e.__scopeMenu),a=Zd($r,e.__scopeMenu),l=SR(ER,e.__scopeMenu),c=v.useRef(null),i=it(t,c);return u.jsx(ld.Provider,{scope:e.__scopeMenu,children:u.jsx(or,{present:r||o.open,children:u.jsx(ld.Slot,{scope:e.__scopeMenu,children:u.jsx(Zx,{id:l.contentId,"aria-labelledby":l.triggerId,...s,ref:i,align:"start",side:a.dir==="rtl"?"left":"right",disableOutsidePointerEvents:!1,disableOutsideScroll:!1,trapFocus:!1,onOpenAutoFocus:d=>{var p;a.isUsingKeyboardRef.current&&((p=c.current)==null||p.focus()),d.preventDefault()},onCloseAutoFocus:d=>d.preventDefault(),onFocusOutside:Se(e.onFocusOutside,d=>{d.target!==l.trigger&&o.onOpenChange(!1)}),onEscapeKeyDown:Se(e.onEscapeKeyDown,d=>{a.onClose(),d.preventDefault()}),onKeyDown:Se(e.onKeyDown,d=>{var h;const p=d.currentTarget.contains(d.target),f=jU[a.dir].includes(d.key);p&&f&&(o.onOpenChange(!1),(h=l.trigger)==null||h.focus(),d.preventDefault())})})})})})});TR.displayName=ER;function kR(e){return e?"open":"closed"}function ih(e){return e==="indeterminate"}function ew(e){return ih(e)?"indeterminate":e?"checked":"unchecked"}function WU(e){const t=document.activeElement;for(const n of e)if(n===t||(n.focus(),document.activeElement!==t))return}function GU(e,t){return e.map((n,r)=>e[(t+r)%e.length])}function JU(e,t,n){const s=t.length>1&&Array.from(t).every(i=>i===t[0])?t[0]:t,o=n?e.indexOf(n):-1;let a=GU(e,Math.max(o,0));s.length===1&&(a=a.filter(i=>i!==n));const c=a.find(i=>i.toLowerCase().startsWith(s.toLowerCase()));return c!==n?c:void 0}function QU(e,t){const{x:n,y:r}=e;let s=!1;for(let o=0,a=t.length-1;or!=d>r&&n<(i-l)*(r-c)/(d-c)+l&&(s=!s)}return s}function ZU(e,t){if(!t)return!1;const n={x:e.clientX,y:e.clientY};return QU(n,t)}function ud(e){return t=>t.pointerType==="mouse"?e(t):void 0}var YU=iR,XU=Gx,e5=uR,t5=cR,n5=Yx,r5=dR,s5=wg,o5=pR,a5=gR,i5=vR,l5=bR,u5=xR,c5=wR,d5=CR,f5=TR,tw="DropdownMenu",[p5,Wse]=Vr(tw,[oR]),Gn=oR(),[h5,_R]=p5(tw),nw=e=>{const{__scopeDropdownMenu:t,children:n,dir:r,open:s,defaultOpen:o,onOpenChange:a,modal:l=!0}=e,c=Gn(t),i=v.useRef(null),[d=!1,p]=pa({prop:s,defaultProp:o,onChange:a});return u.jsx(h5,{scope:t,triggerId:os(),triggerRef:i,contentId:os(),open:d,onOpenChange:p,onOpenToggle:v.useCallback(()=>p(f=>!f),[p]),modal:l,children:u.jsx(YU,{...c,open:d,onOpenChange:p,dir:r,modal:l,children:n})})};nw.displayName=tw;var jR="DropdownMenuTrigger",rw=v.forwardRef((e,t)=>{const{__scopeDropdownMenu:n,disabled:r=!1,...s}=e,o=_R(jR,n),a=Gn(n);return u.jsx(XU,{asChild:!0,...a,children:u.jsx(Ne.button,{type:"button",id:o.triggerId,"aria-haspopup":"menu","aria-expanded":o.open,"aria-controls":o.open?o.contentId:void 0,"data-state":o.open?"open":"closed","data-disabled":r?"":void 0,disabled:r,...s,ref:ag(t,o.triggerRef),onPointerDown:Se(e.onPointerDown,l=>{!r&&l.button===0&&l.ctrlKey===!1&&(o.onOpenToggle(),o.open||l.preventDefault())}),onKeyDown:Se(e.onKeyDown,l=>{r||(["Enter"," "].includes(l.key)&&o.onOpenToggle(),l.key==="ArrowDown"&&o.onOpenChange(!0),["Enter"," ","ArrowDown"].includes(l.key)&&l.preventDefault())})})})});rw.displayName=jR;var g5="DropdownMenuPortal",RR=e=>{const{__scopeDropdownMenu:t,...n}=e,r=Gn(t);return u.jsx(e5,{...r,...n})};RR.displayName=g5;var PR="DropdownMenuContent",MR=v.forwardRef((e,t)=>{const{__scopeDropdownMenu:n,...r}=e,s=_R(PR,n),o=Gn(n),a=v.useRef(!1);return u.jsx(t5,{id:s.contentId,"aria-labelledby":s.triggerId,...o,...r,ref:t,onCloseAutoFocus:Se(e.onCloseAutoFocus,l=>{var c;a.current||(c=s.triggerRef.current)==null||c.focus(),a.current=!1,l.preventDefault()}),onInteractOutside:Se(e.onInteractOutside,l=>{const c=l.detail.originalEvent,i=c.button===0&&c.ctrlKey===!0,d=c.button===2||i;(!s.modal||d)&&(a.current=!0)}),style:{...e.style,"--radix-dropdown-menu-content-transform-origin":"var(--radix-popper-transform-origin)","--radix-dropdown-menu-content-available-width":"var(--radix-popper-available-width)","--radix-dropdown-menu-content-available-height":"var(--radix-popper-available-height)","--radix-dropdown-menu-trigger-width":"var(--radix-popper-anchor-width)","--radix-dropdown-menu-trigger-height":"var(--radix-popper-anchor-height)"}})});MR.displayName=PR;var m5="DropdownMenuGroup",v5=v.forwardRef((e,t)=>{const{__scopeDropdownMenu:n,...r}=e,s=Gn(n);return u.jsx(n5,{...s,...r,ref:t})});v5.displayName=m5;var y5="DropdownMenuLabel",OR=v.forwardRef((e,t)=>{const{__scopeDropdownMenu:n,...r}=e,s=Gn(n);return u.jsx(r5,{...s,...r,ref:t})});OR.displayName=y5;var b5="DropdownMenuItem",NR=v.forwardRef((e,t)=>{const{__scopeDropdownMenu:n,...r}=e,s=Gn(n);return u.jsx(s5,{...s,...r,ref:t})});NR.displayName=b5;var x5="DropdownMenuCheckboxItem",IR=v.forwardRef((e,t)=>{const{__scopeDropdownMenu:n,...r}=e,s=Gn(n);return u.jsx(o5,{...s,...r,ref:t})});IR.displayName=x5;var w5="DropdownMenuRadioGroup",S5=v.forwardRef((e,t)=>{const{__scopeDropdownMenu:n,...r}=e,s=Gn(n);return u.jsx(a5,{...s,...r,ref:t})});S5.displayName=w5;var C5="DropdownMenuRadioItem",DR=v.forwardRef((e,t)=>{const{__scopeDropdownMenu:n,...r}=e,s=Gn(n);return u.jsx(i5,{...s,...r,ref:t})});DR.displayName=C5;var E5="DropdownMenuItemIndicator",AR=v.forwardRef((e,t)=>{const{__scopeDropdownMenu:n,...r}=e,s=Gn(n);return u.jsx(l5,{...s,...r,ref:t})});AR.displayName=E5;var T5="DropdownMenuSeparator",FR=v.forwardRef((e,t)=>{const{__scopeDropdownMenu:n,...r}=e,s=Gn(n);return u.jsx(u5,{...s,...r,ref:t})});FR.displayName=T5;var k5="DropdownMenuArrow",_5=v.forwardRef((e,t)=>{const{__scopeDropdownMenu:n,...r}=e,s=Gn(n);return u.jsx(c5,{...s,...r,ref:t})});_5.displayName=k5;var j5="DropdownMenuSubTrigger",LR=v.forwardRef((e,t)=>{const{__scopeDropdownMenu:n,...r}=e,s=Gn(n);return u.jsx(d5,{...s,...r,ref:t})});LR.displayName=j5;var R5="DropdownMenuSubContent",$R=v.forwardRef((e,t)=>{const{__scopeDropdownMenu:n,...r}=e,s=Gn(n);return u.jsx(f5,{...s,...r,ref:t,style:{...e.style,"--radix-dropdown-menu-content-transform-origin":"var(--radix-popper-transform-origin)","--radix-dropdown-menu-content-available-width":"var(--radix-popper-available-width)","--radix-dropdown-menu-content-available-height":"var(--radix-popper-available-height)","--radix-dropdown-menu-trigger-width":"var(--radix-popper-anchor-width)","--radix-dropdown-menu-trigger-height":"var(--radix-popper-anchor-height)"}})});$R.displayName=R5;var P5=nw,M5=rw,O5=RR,BR=MR,zR=OR,UR=NR,VR=IR,HR=DR,KR=AR,Ra=FR,qR=LR,WR=$R;const Eo=P5,To=M5,N5=v.forwardRef(({className:e,inset:t,children:n,...r},s)=>u.jsxs(qR,{ref:s,className:ge("flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent",t&&"pl-8",e),...r,children:[n,u.jsx(R3,{className:"ml-auto h-4 w-4"})]}));N5.displayName=qR.displayName;const I5=v.forwardRef(({className:e,...t},n)=>u.jsx(WR,{ref:n,className:ge("z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",e),...t}));I5.displayName=WR.displayName;const ps=v.forwardRef(({className:e,sideOffset:t=4,...n},r)=>u.jsx(O5,{children:u.jsx(BR,{ref:r,sideOffset:t,className:ge("z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",e),...n})}));ps.displayName=BR.displayName;const ft=v.forwardRef(({className:e,inset:t,...n},r)=>u.jsx(UR,{ref:r,className:ge("relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",t&&"pl-8",e),...n}));ft.displayName=UR.displayName;const GR=v.forwardRef(({className:e,children:t,checked:n,...r},s)=>u.jsxs(VR,{ref:s,className:ge("relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",e),checked:n,...r,children:[u.jsx("span",{className:"absolute left-2 flex h-3.5 w-3.5 items-center justify-center",children:u.jsx(KR,{children:u.jsx(cj,{className:"h-4 w-4"})})}),t]}));GR.displayName=VR.displayName;const D5=v.forwardRef(({className:e,children:t,...n},r)=>u.jsxs(HR,{ref:r,className:ge("relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",e),...n,children:[u.jsx("span",{className:"absolute left-2 flex h-3.5 w-3.5 items-center justify-center",children:u.jsx(KR,{children:u.jsx(N3,{className:"h-2 w-2 fill-current"})})}),t]}));D5.displayName=HR.displayName;const Ai=v.forwardRef(({className:e,inset:t,...n},r)=>u.jsx(zR,{ref:r,className:ge("px-2 py-1.5 text-sm font-semibold",t&&"pl-8",e),...n}));Ai.displayName=zR.displayName;const Pa=v.forwardRef(({className:e,...t},n)=>u.jsx(Ra,{ref:n,className:ge("-mx-1 my-1 h-px bg-muted",e),...t}));Pa.displayName=Ra.displayName;function A5(){const{t:e,i18n:t}=ze(),n=r=>{t.changeLanguage(r),localStorage.setItem("i18nextLng",r),window.location.reload()};return u.jsxs(Eo,{children:[u.jsx(To,{asChild:!0,children:u.jsxs(q,{variant:"outline",size:"icon",children:[u.jsx(z3,{className:"h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all"}),u.jsx("span",{className:"sr-only",children:e("header.theme.label")})]})}),u.jsxs(ps,{align:"end",children:[u.jsx(ft,{className:t.language==="pt-BR"?"font-bold":"",onClick:()=>n("pt-BR"),children:e("header.language.portuguese")}),u.jsx(ft,{className:t.language==="en-US"?"font-bold":"",onClick:()=>n("en-US"),children:e("header.language.english")}),u.jsx(ft,{className:t.language==="es-ES"?"font-bold":"",onClick:()=>n("es-ES"),children:e("header.language.spanish")}),u.jsx(ft,{className:t.language==="fr-FR"?"font-bold":"",onClick:()=>n("fr-FR"),children:e("header.language.french")})]})]})}function F5(){const{t:e}=ze(),{setTheme:t}=R_();return u.jsxs(Eo,{children:[u.jsx(To,{asChild:!0,children:u.jsxs(q,{variant:"outline",size:"icon",children:[u.jsx(G3,{className:"h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0"}),u.jsx(K3,{className:"absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100"}),u.jsx("span",{className:"sr-only",children:e("header.theme.label")})]})}),u.jsxs(ps,{align:"end",children:[u.jsx(ft,{onClick:()=>t("light"),children:e("header.theme.light")}),u.jsx(ft,{onClick:()=>t("dark"),children:e("header.theme.dark")}),u.jsx(ft,{onClick:()=>t("system"),children:e("header.theme.system")})]})]})}var sw="Avatar",[L5,Gse]=Vr(sw),[$5,JR]=L5(sw),QR=v.forwardRef((e,t)=>{const{__scopeAvatar:n,...r}=e,[s,o]=v.useState("idle");return u.jsx($5,{scope:n,imageLoadingStatus:s,onImageLoadingStatusChange:o,children:u.jsx(Ne.span,{...r,ref:t})})});QR.displayName=sw;var ZR="AvatarImage",YR=v.forwardRef((e,t)=>{const{__scopeAvatar:n,src:r,onLoadingStatusChange:s=()=>{},...o}=e,a=JR(ZR,n),l=B5(r),c=nn(i=>{s(i),a.onImageLoadingStatusChange(i)});return fn(()=>{l!=="idle"&&c(l)},[l,c]),l==="loaded"?u.jsx(Ne.img,{...o,ref:t,src:r}):null});YR.displayName=ZR;var XR="AvatarFallback",eP=v.forwardRef((e,t)=>{const{__scopeAvatar:n,delayMs:r,...s}=e,o=JR(XR,n),[a,l]=v.useState(r===void 0);return v.useEffect(()=>{if(r!==void 0){const c=window.setTimeout(()=>l(!0),r);return()=>window.clearTimeout(c)}},[r]),a&&o.imageLoadingStatus!=="loaded"?u.jsx(Ne.span,{...s,ref:t}):null});eP.displayName=XR;function B5(e){const[t,n]=v.useState("idle");return fn(()=>{if(!e){n("error");return}let r=!0;const s=new window.Image,o=a=>()=>{r&&n(a)};return n("loading"),s.onload=o("loaded"),s.onerror=o("error"),s.src=e,()=>{r=!1}},[e]),t}var tP=QR,nP=YR,rP=eP;const Sg=v.forwardRef(({className:e,...t},n)=>u.jsx(tP,{ref:n,className:ge("relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",e),...t}));Sg.displayName=tP.displayName;const Cg=v.forwardRef(({className:e,...t},n)=>u.jsx(nP,{ref:n,className:ge("aspect-square h-full w-full",e),...t}));Cg.displayName=nP.displayName;const z5=v.forwardRef(({className:e,...t},n)=>u.jsx(rP,{ref:n,className:ge("flex h-full w-full items-center justify-center rounded-full bg-muted",e),...t}));z5.displayName=rP.displayName;var ow="Dialog",[sP,Jse]=Vr(ow),[U5,hs]=sP(ow),oP=e=>{const{__scopeDialog:t,children:n,open:r,defaultOpen:s,onOpenChange:o,modal:a=!0}=e,l=v.useRef(null),c=v.useRef(null),[i=!1,d]=pa({prop:r,defaultProp:s,onChange:o});return u.jsx(U5,{scope:t,triggerRef:l,contentRef:c,contentId:os(),titleId:os(),descriptionId:os(),open:i,onOpenChange:d,onOpenToggle:v.useCallback(()=>d(p=>!p),[d]),modal:a,children:n})};oP.displayName=ow;var aP="DialogTrigger",iP=v.forwardRef((e,t)=>{const{__scopeDialog:n,...r}=e,s=hs(aP,n),o=it(t,s.triggerRef);return u.jsx(Ne.button,{type:"button","aria-haspopup":"dialog","aria-expanded":s.open,"aria-controls":s.contentId,"data-state":lw(s.open),...r,ref:o,onClick:Se(e.onClick,s.onOpenToggle)})});iP.displayName=aP;var aw="DialogPortal",[V5,lP]=sP(aw,{forceMount:void 0}),uP=e=>{const{__scopeDialog:t,forceMount:n,children:r,container:s}=e,o=hs(aw,t);return u.jsx(V5,{scope:t,forceMount:n,children:v.Children.map(r,a=>u.jsx(or,{present:n||o.open,children:u.jsx(gg,{asChild:!0,container:s,children:a})}))})};uP.displayName=aw;var lh="DialogOverlay",cP=v.forwardRef((e,t)=>{const n=lP(lh,e.__scopeDialog),{forceMount:r=n.forceMount,...s}=e,o=hs(lh,e.__scopeDialog);return o.modal?u.jsx(or,{present:r||o.open,children:u.jsx(H5,{...s,ref:t})}):null});cP.displayName=lh;var H5=v.forwardRef((e,t)=>{const{__scopeDialog:n,...r}=e,s=hs(lh,n);return u.jsx(bg,{as:mo,allowPinchZoom:!0,shards:[s.contentRef],children:u.jsx(Ne.div,{"data-state":lw(s.open),...r,ref:t,style:{pointerEvents:"auto",...r.style}})})}),Ei="DialogContent",dP=v.forwardRef((e,t)=>{const n=lP(Ei,e.__scopeDialog),{forceMount:r=n.forceMount,...s}=e,o=hs(Ei,e.__scopeDialog);return u.jsx(or,{present:r||o.open,children:o.modal?u.jsx(K5,{...s,ref:t}):u.jsx(q5,{...s,ref:t})})});dP.displayName=Ei;var K5=v.forwardRef((e,t)=>{const n=hs(Ei,e.__scopeDialog),r=v.useRef(null),s=it(t,n.contentRef,r);return v.useEffect(()=>{const o=r.current;if(o)return Wx(o)},[]),u.jsx(fP,{...e,ref:s,trapFocus:n.open,disableOutsidePointerEvents:!0,onCloseAutoFocus:Se(e.onCloseAutoFocus,o=>{var a;o.preventDefault(),(a=n.triggerRef.current)==null||a.focus()}),onPointerDownOutside:Se(e.onPointerDownOutside,o=>{const a=o.detail.originalEvent,l=a.button===0&&a.ctrlKey===!0;(a.button===2||l)&&o.preventDefault()}),onFocusOutside:Se(e.onFocusOutside,o=>o.preventDefault())})}),q5=v.forwardRef((e,t)=>{const n=hs(Ei,e.__scopeDialog),r=v.useRef(!1),s=v.useRef(!1);return u.jsx(fP,{...e,ref:t,trapFocus:!1,disableOutsidePointerEvents:!1,onCloseAutoFocus:o=>{var a,l;(a=e.onCloseAutoFocus)==null||a.call(e,o),o.defaultPrevented||(r.current||(l=n.triggerRef.current)==null||l.focus(),o.preventDefault()),r.current=!1,s.current=!1},onInteractOutside:o=>{var c,i;(c=e.onInteractOutside)==null||c.call(e,o),o.defaultPrevented||(r.current=!0,o.detail.originalEvent.type==="pointerdown"&&(s.current=!0));const a=o.target;((i=n.triggerRef.current)==null?void 0:i.contains(a))&&o.preventDefault(),o.detail.originalEvent.type==="focusin"&&s.current&&o.preventDefault()}})}),fP=v.forwardRef((e,t)=>{const{__scopeDialog:n,trapFocus:r,onOpenAutoFocus:s,onCloseAutoFocus:o,...a}=e,l=hs(Ei,n),c=v.useRef(null),i=it(t,c);return Lx(),u.jsxs(u.Fragment,{children:[u.jsx(dg,{asChild:!0,loop:!0,trapped:r,onMountAutoFocus:s,onUnmountAutoFocus:o,children:u.jsx(cg,{role:"dialog",id:l.contentId,"aria-describedby":l.descriptionId,"aria-labelledby":l.titleId,"data-state":lw(l.open),...a,ref:i,onDismiss:()=>l.onOpenChange(!1)})}),u.jsxs(u.Fragment,{children:[u.jsx(W5,{titleId:l.titleId}),u.jsx(J5,{contentRef:c,descriptionId:l.descriptionId})]})]})}),iw="DialogTitle",pP=v.forwardRef((e,t)=>{const{__scopeDialog:n,...r}=e,s=hs(iw,n);return u.jsx(Ne.h2,{id:s.titleId,...r,ref:t})});pP.displayName=iw;var hP="DialogDescription",gP=v.forwardRef((e,t)=>{const{__scopeDialog:n,...r}=e,s=hs(hP,n);return u.jsx(Ne.p,{id:s.descriptionId,...r,ref:t})});gP.displayName=hP;var mP="DialogClose",vP=v.forwardRef((e,t)=>{const{__scopeDialog:n,...r}=e,s=hs(mP,n);return u.jsx(Ne.button,{type:"button",...r,ref:t,onClick:Se(e.onClick,()=>s.onOpenChange(!1))})});vP.displayName=mP;function lw(e){return e?"open":"closed"}var yP="DialogTitleWarning",[Qse,bP]=X3(yP,{contentName:Ei,titleName:iw,docsSlug:"dialog"}),W5=({titleId:e})=>{const t=bP(yP),n=`\`${t.contentName}\` requires a \`${t.titleName}\` for the component to be accessible for screen reader users. + +If you want to hide the \`${t.titleName}\`, you can wrap it with our VisuallyHidden component. + +For more information, see https://radix-ui.com/primitives/docs/components/${t.docsSlug}`;return v.useEffect(()=>{e&&(document.getElementById(e)||console.error(n))},[n,e]),null},G5="DialogDescriptionWarning",J5=({contentRef:e,descriptionId:t})=>{const r=`Warning: Missing \`Description\` or \`aria-describedby={undefined}\` for {${bP(G5).contentName}}.`;return v.useEffect(()=>{var o;const s=(o=e.current)==null?void 0:o.getAttribute("aria-describedby");t&&s&&(document.getElementById(t)||console.warn(r))},[r,e,t]),null},Q5=oP,Z5=iP,Y5=uP,xP=cP,wP=dP,SP=pP,CP=gP,EP=vP;const Tt=Q5,Nt=Z5,X5=Y5,TP=EP,kP=v.forwardRef(({className:e,...t},n)=>u.jsx(xP,{ref:n,className:ge("fixed inset-0 z-50 bg-background/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",e),...t}));kP.displayName=xP.displayName;const xt=v.forwardRef(({className:e,children:t,closeBtn:n=!0,...r},s)=>u.jsx(X5,{children:u.jsx(kP,{className:"fixed inset-0 grid place-items-center overflow-y-auto",children:u.jsxs(wP,{ref:s,className:ge("relative z-50 grid w-full max-w-lg gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:m-4 sm:rounded-lg md:w-full",e),...r,children:[t,n&&u.jsxs(EP,{className:"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground",children:[u.jsx(Q3,{className:"h-4 w-4"}),u.jsx("span",{className:"sr-only",children:"Close"})]})]})})}));xt.displayName=wP.displayName;const wt=({className:e,...t})=>u.jsx("div",{className:ge("flex flex-col space-y-1.5 text-center sm:text-left",e),...t});wt.displayName="DialogHeader";const rn=({className:e,...t})=>u.jsx("div",{className:ge("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",e),...t});rn.displayName="DialogFooter";const Ut=v.forwardRef(({className:e,...t},n)=>u.jsx(SP,{ref:n,className:ge("text-lg font-semibold leading-none tracking-tight",e),...t}));Ut.displayName=SP.displayName;const Fi=v.forwardRef(({className:e,...t},n)=>u.jsx(CP,{ref:n,className:ge("text-sm text-muted-foreground",e),...t}));Fi.displayName=CP.displayName;function _P({instanceId:e}){const[t,n]=v.useState(!1),r=An(),s=()=>{M_(),r("/manager/login")},o=()=>{r("/manager/")},{data:a}=hj({instanceId:e});return u.jsxs("header",{className:"flex items-center justify-between px-4 py-2",children:[u.jsxs(nd,{to:"/manager",onClick:o,className:"flex h-8 items-center gap-4",children:[u.jsx("img",{src:"/assets/images/evolution-logo.png",alt:"Logo",className:"h-full"}),u.jsx("span",{children:"Evolution Manager"})]}),u.jsxs("div",{className:"flex items-center gap-4",children:[e&&u.jsx(Sg,{className:"h-8 w-8",children:u.jsx(Cg,{src:(a==null?void 0:a.profilePicUrl)||"/assets/images/evolution-logo.png",alt:a==null?void 0:a.name})}),u.jsx(A5,{}),u.jsx(F5,{}),u.jsx(q,{onClick:()=>n(!0),variant:"destructive",size:"icon",children:u.jsx(D3,{size:"18"})})]}),t&&u.jsx(Tt,{onOpenChange:n,open:t,children:u.jsxs(xt,{children:[u.jsx(TP,{}),u.jsx(wt,{children:"Deseja realmente sair?"}),u.jsx(rn,{children:u.jsxs("div",{className:"flex items-center gap-4",children:[u.jsx(q,{onClick:()=>n(!1),size:"sm",variant:"outline",children:"Cancelar"}),u.jsx(q,{onClick:s,variant:"destructive",children:"Sair"})]})})]})})]})}const jP=v.createContext(null),nt=()=>{const e=v.useContext(jP);if(!e)throw new Error("useInstance must be used within an InstanceProvider");return e},eV=({children:e})=>{const t=So(),[n,r]=v.useState(null),{data:s,refetch:o}=hj({instanceId:n});return v.useEffect(()=>{t.instanceId?r(t.instanceId):r(null)},[t]),u.jsx(jP.Provider,{value:{instance:s??null,reloadInstance:async()=>{await o()}},children:e})};var uw="Collapsible",[tV,Zse]=Vr(uw),[nV,cw]=tV(uw),RP=v.forwardRef((e,t)=>{const{__scopeCollapsible:n,open:r,defaultOpen:s,disabled:o,onOpenChange:a,...l}=e,[c=!1,i]=pa({prop:r,defaultProp:s,onChange:a});return u.jsx(nV,{scope:n,disabled:o,contentId:os(),open:c,onOpenToggle:v.useCallback(()=>i(d=>!d),[i]),children:u.jsx(Ne.div,{"data-state":fw(c),"data-disabled":o?"":void 0,...l,ref:t})})});RP.displayName=uw;var PP="CollapsibleTrigger",MP=v.forwardRef((e,t)=>{const{__scopeCollapsible:n,...r}=e,s=cw(PP,n);return u.jsx(Ne.button,{type:"button","aria-controls":s.contentId,"aria-expanded":s.open||!1,"data-state":fw(s.open),"data-disabled":s.disabled?"":void 0,disabled:s.disabled,...r,ref:t,onClick:Se(e.onClick,s.onOpenToggle)})});MP.displayName=PP;var dw="CollapsibleContent",OP=v.forwardRef((e,t)=>{const{forceMount:n,...r}=e,s=cw(dw,e.__scopeCollapsible);return u.jsx(or,{present:n||s.open,children:({present:o})=>u.jsx(rV,{...r,ref:t,present:o})})});OP.displayName=dw;var rV=v.forwardRef((e,t)=>{const{__scopeCollapsible:n,present:r,children:s,...o}=e,a=cw(dw,n),[l,c]=v.useState(r),i=v.useRef(null),d=it(t,i),p=v.useRef(0),f=p.current,h=v.useRef(0),g=h.current,m=a.open||l,x=v.useRef(m),b=v.useRef();return v.useEffect(()=>{const y=requestAnimationFrame(()=>x.current=!1);return()=>cancelAnimationFrame(y)},[]),fn(()=>{const y=i.current;if(y){b.current=b.current||{transitionDuration:y.style.transitionDuration,animationName:y.style.animationName},y.style.transitionDuration="0s",y.style.animationName="none";const w=y.getBoundingClientRect();p.current=w.height,h.current=w.width,x.current||(y.style.transitionDuration=b.current.transitionDuration,y.style.animationName=b.current.animationName),c(r)}},[a.open,r]),u.jsx(Ne.div,{"data-state":fw(a.open),"data-disabled":a.disabled?"":void 0,id:a.contentId,hidden:!m,...o,ref:d,style:{"--radix-collapsible-content-height":f?`${f}px`:void 0,"--radix-collapsible-content-width":g?`${g}px`:void 0,...e.style},children:m&&s})});function fw(e){return e?"open":"closed"}var sV=RP;const oV=sV,aV=MP,iV=OP;function lV(){const{t:e}=ze(),t=v.useMemo(()=>[{id:"dashboard",title:e("sidebar.dashboard"),icon:U3,path:"dashboard"},{navLabel:!0,title:e("sidebar.configurations"),icon:Oi,children:[{id:"settings",title:e("sidebar.settings"),path:"settings"},{id:"proxy",title:e("sidebar.proxy"),path:"proxy"}]},{title:e("sidebar.events"),icon:B3,children:[{id:"webhook",title:e("sidebar.webhook"),path:"webhook"},{id:"websocket",title:e("sidebar.websocket"),path:"websocket"},{id:"rabbitmq",title:e("sidebar.rabbitmq"),path:"rabbitmq"},{id:"sqs",title:e("sidebar.sqs"),path:"sqs"}]},{title:e("sidebar.integrations"),icon:pj,children:[{id:"evolutionBot",title:e("sidebar.evolutionBot"),path:"evolutionBot"},{id:"chatwoot",title:e("sidebar.chatwoot"),path:"chatwoot"},{id:"typebot",title:e("sidebar.typebot"),path:"typebot"},{id:"openai",title:e("sidebar.openai"),path:"openai"},{id:"dify",title:e("sidebar.dify"),path:"dify"},{id:"flowise",title:e("sidebar.flowise"),path:"flowise"}]},{id:"documentation",title:e("sidebar.documentation"),icon:L3,link:"https://doc.evolution-api.com",divider:!0},{id:"postman",title:e("sidebar.postman"),icon:O3,link:"https://evolution-api.com/postman"},{id:"discord",title:e("sidebar.discord"),icon:ug,link:"https://evolution-api.com/discord"},{id:"support-premium",title:e("sidebar.supportPremium"),icon:V3,link:"https://evolution-api.com/suporte-pro"}],[e]),n=An(),{pathname:r}=pu(),{instance:s}=nt(),o=l=>{!l||!s||(l.path&&n(`/manager/instance/${s.id}/${l.path}`),l.link&&window.open(l.link,"_blank"))},a=v.useMemo(()=>t.map(l=>{var c;return{...l,children:"children"in l?(c=l.children)==null?void 0:c.map(i=>({...i,isActive:"path"in i?r.includes(i.path):!1})):void 0,isActive:"path"in l&&l.path?r.includes(l.path):!1}}).map(l=>{var c;return{...l,isActive:l.isActive||"children"in l&&((c=l.children)==null?void 0:c.some(i=>i.isActive))}}),[t,r]);return u.jsx("ul",{className:"flex h-full w-full flex-col gap-2 border-r border-border px-2",children:a.map(l=>u.jsx("li",{className:"divider"in l?"mt-auto":void 0,children:l.children?u.jsxs(oV,{defaultOpen:l.isActive,children:[u.jsx(aV,{asChild:!0,children:u.jsxs(q,{className:ge("flex w-full items-center justify-start gap-2"),variant:l.isActive?"secondary":"link",children:[l.icon&&u.jsx(l.icon,{size:"15"}),u.jsx("span",{children:l.title}),u.jsx(lg,{size:"15",className:"ml-auto"})]})}),u.jsx(iV,{children:u.jsx("ul",{className:"my-4 ml-6 flex flex-col gap-2 text-sm",children:l.children.map(c=>u.jsx("li",{children:u.jsx("button",{onClick:()=>o(c),className:ge(c.isActive?"text-foreground":"text-muted-foreground"),children:u.jsx("span",{className:"nav-label",children:c.title})})},c.id))})})]}):u.jsxs(q,{className:ge("relative flex w-full items-center justify-start gap-2",l.isActive&&"pointer-events-none"),variant:l.isActive?"secondary":"link",children:["link"in l&&u.jsx("a",{href:l.link,target:"_blank",rel:"noreferrer",className:"absolute inset-0 h-full w-full"}),"path"in l&&u.jsx(nd,{to:`/manager/instance/${s==null?void 0:s.id}/${l.path}`,className:"absolute inset-0 h-full w-full"}),l.icon&&u.jsx(l.icon,{size:"15"}),u.jsx("span",{children:l.title})]})},l.title))})}function Zy(e,[t,n]){return Math.min(n,Math.max(t,e))}function uV(e,t){return v.useReducer((n,r)=>t[n][r]??n,e)}var pw="ScrollArea",[NP,Yse]=Vr(pw),[cV,Hr]=NP(pw),IP=v.forwardRef((e,t)=>{const{__scopeScrollArea:n,type:r="hover",dir:s,scrollHideDelay:o=600,...a}=e,[l,c]=v.useState(null),[i,d]=v.useState(null),[p,f]=v.useState(null),[h,g]=v.useState(null),[m,x]=v.useState(null),[b,y]=v.useState(0),[w,S]=v.useState(0),[E,C]=v.useState(!1),[k,T]=v.useState(!1),P=it(t,U=>c(U)),N=Gd(s);return u.jsx(cV,{scope:n,type:r,dir:N,scrollHideDelay:o,scrollArea:l,viewport:i,onViewportChange:d,content:p,onContentChange:f,scrollbarX:h,onScrollbarXChange:g,scrollbarXEnabled:E,onScrollbarXEnabledChange:C,scrollbarY:m,onScrollbarYChange:x,scrollbarYEnabled:k,onScrollbarYEnabledChange:T,onCornerWidthChange:y,onCornerHeightChange:S,children:u.jsx(Ne.div,{dir:N,...a,ref:P,style:{position:"relative","--radix-scroll-area-corner-width":b+"px","--radix-scroll-area-corner-height":w+"px",...e.style}})})});IP.displayName=pw;var DP="ScrollAreaViewport",AP=v.forwardRef((e,t)=>{const{__scopeScrollArea:n,children:r,nonce:s,...o}=e,a=Hr(DP,n),l=v.useRef(null),c=it(t,l,a.onViewportChange);return u.jsxs(u.Fragment,{children:[u.jsx("style",{dangerouslySetInnerHTML:{__html:"[data-radix-scroll-area-viewport]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}[data-radix-scroll-area-viewport]::-webkit-scrollbar{display:none}"},nonce:s}),u.jsx(Ne.div,{"data-radix-scroll-area-viewport":"",...o,ref:c,style:{overflowX:a.scrollbarXEnabled?"scroll":"hidden",overflowY:a.scrollbarYEnabled?"scroll":"hidden",...e.style},children:u.jsx("div",{ref:a.onContentChange,style:{minWidth:"100%",display:"table"},children:r})})]})});AP.displayName=DP;var Hs="ScrollAreaScrollbar",hw=v.forwardRef((e,t)=>{const{forceMount:n,...r}=e,s=Hr(Hs,e.__scopeScrollArea),{onScrollbarXEnabledChange:o,onScrollbarYEnabledChange:a}=s,l=e.orientation==="horizontal";return v.useEffect(()=>(l?o(!0):a(!0),()=>{l?o(!1):a(!1)}),[l,o,a]),s.type==="hover"?u.jsx(dV,{...r,ref:t,forceMount:n}):s.type==="scroll"?u.jsx(fV,{...r,ref:t,forceMount:n}):s.type==="auto"?u.jsx(FP,{...r,ref:t,forceMount:n}):s.type==="always"?u.jsx(gw,{...r,ref:t}):null});hw.displayName=Hs;var dV=v.forwardRef((e,t)=>{const{forceMount:n,...r}=e,s=Hr(Hs,e.__scopeScrollArea),[o,a]=v.useState(!1);return v.useEffect(()=>{const l=s.scrollArea;let c=0;if(l){const i=()=>{window.clearTimeout(c),a(!0)},d=()=>{c=window.setTimeout(()=>a(!1),s.scrollHideDelay)};return l.addEventListener("pointerenter",i),l.addEventListener("pointerleave",d),()=>{window.clearTimeout(c),l.removeEventListener("pointerenter",i),l.removeEventListener("pointerleave",d)}}},[s.scrollArea,s.scrollHideDelay]),u.jsx(or,{present:n||o,children:u.jsx(FP,{"data-state":o?"visible":"hidden",...r,ref:t})})}),fV=v.forwardRef((e,t)=>{const{forceMount:n,...r}=e,s=Hr(Hs,e.__scopeScrollArea),o=e.orientation==="horizontal",a=Tg(()=>c("SCROLL_END"),100),[l,c]=uV("hidden",{hidden:{SCROLL:"scrolling"},scrolling:{SCROLL_END:"idle",POINTER_ENTER:"interacting"},interacting:{SCROLL:"interacting",POINTER_LEAVE:"idle"},idle:{HIDE:"hidden",SCROLL:"scrolling",POINTER_ENTER:"interacting"}});return v.useEffect(()=>{if(l==="idle"){const i=window.setTimeout(()=>c("HIDE"),s.scrollHideDelay);return()=>window.clearTimeout(i)}},[l,s.scrollHideDelay,c]),v.useEffect(()=>{const i=s.viewport,d=o?"scrollLeft":"scrollTop";if(i){let p=i[d];const f=()=>{const h=i[d];p!==h&&(c("SCROLL"),a()),p=h};return i.addEventListener("scroll",f),()=>i.removeEventListener("scroll",f)}},[s.viewport,o,c,a]),u.jsx(or,{present:n||l!=="hidden",children:u.jsx(gw,{"data-state":l==="hidden"?"hidden":"visible",...r,ref:t,onPointerEnter:Se(e.onPointerEnter,()=>c("POINTER_ENTER")),onPointerLeave:Se(e.onPointerLeave,()=>c("POINTER_LEAVE"))})})}),FP=v.forwardRef((e,t)=>{const n=Hr(Hs,e.__scopeScrollArea),{forceMount:r,...s}=e,[o,a]=v.useState(!1),l=e.orientation==="horizontal",c=Tg(()=>{if(n.viewport){const i=n.viewport.offsetWidth{const{orientation:n="vertical",...r}=e,s=Hr(Hs,e.__scopeScrollArea),o=v.useRef(null),a=v.useRef(0),[l,c]=v.useState({content:0,viewport:0,scrollbar:{size:0,paddingStart:0,paddingEnd:0}}),i=UP(l.viewport,l.content),d={...r,sizes:l,onSizesChange:c,hasThumb:i>0&&i<1,onThumbChange:f=>o.current=f,onThumbPointerUp:()=>a.current=0,onThumbPointerDown:f=>a.current=f};function p(f,h){return yV(f,a.current,l,h)}return n==="horizontal"?u.jsx(pV,{...d,ref:t,onThumbPositionChange:()=>{if(s.viewport&&o.current){const f=s.viewport.scrollLeft,h=SC(f,l,s.dir);o.current.style.transform=`translate3d(${h}px, 0, 0)`}},onWheelScroll:f=>{s.viewport&&(s.viewport.scrollLeft=f)},onDragScroll:f=>{s.viewport&&(s.viewport.scrollLeft=p(f,s.dir))}}):n==="vertical"?u.jsx(hV,{...d,ref:t,onThumbPositionChange:()=>{if(s.viewport&&o.current){const f=s.viewport.scrollTop,h=SC(f,l);o.current.style.transform=`translate3d(0, ${h}px, 0)`}},onWheelScroll:f=>{s.viewport&&(s.viewport.scrollTop=f)},onDragScroll:f=>{s.viewport&&(s.viewport.scrollTop=p(f))}}):null}),pV=v.forwardRef((e,t)=>{const{sizes:n,onSizesChange:r,...s}=e,o=Hr(Hs,e.__scopeScrollArea),[a,l]=v.useState(),c=v.useRef(null),i=it(t,c,o.onScrollbarXChange);return v.useEffect(()=>{c.current&&l(getComputedStyle(c.current))},[c]),u.jsx($P,{"data-orientation":"horizontal",...s,ref:i,sizes:n,style:{bottom:0,left:o.dir==="rtl"?"var(--radix-scroll-area-corner-width)":0,right:o.dir==="ltr"?"var(--radix-scroll-area-corner-width)":0,"--radix-scroll-area-thumb-width":Eg(n)+"px",...e.style},onThumbPointerDown:d=>e.onThumbPointerDown(d.x),onDragScroll:d=>e.onDragScroll(d.x),onWheelScroll:(d,p)=>{if(o.viewport){const f=o.viewport.scrollLeft+d.deltaX;e.onWheelScroll(f),HP(f,p)&&d.preventDefault()}},onResize:()=>{c.current&&o.viewport&&a&&r({content:o.viewport.scrollWidth,viewport:o.viewport.offsetWidth,scrollbar:{size:c.current.clientWidth,paddingStart:ch(a.paddingLeft),paddingEnd:ch(a.paddingRight)}})}})}),hV=v.forwardRef((e,t)=>{const{sizes:n,onSizesChange:r,...s}=e,o=Hr(Hs,e.__scopeScrollArea),[a,l]=v.useState(),c=v.useRef(null),i=it(t,c,o.onScrollbarYChange);return v.useEffect(()=>{c.current&&l(getComputedStyle(c.current))},[c]),u.jsx($P,{"data-orientation":"vertical",...s,ref:i,sizes:n,style:{top:0,right:o.dir==="ltr"?0:void 0,left:o.dir==="rtl"?0:void 0,bottom:"var(--radix-scroll-area-corner-height)","--radix-scroll-area-thumb-height":Eg(n)+"px",...e.style},onThumbPointerDown:d=>e.onThumbPointerDown(d.y),onDragScroll:d=>e.onDragScroll(d.y),onWheelScroll:(d,p)=>{if(o.viewport){const f=o.viewport.scrollTop+d.deltaY;e.onWheelScroll(f),HP(f,p)&&d.preventDefault()}},onResize:()=>{c.current&&o.viewport&&a&&r({content:o.viewport.scrollHeight,viewport:o.viewport.offsetHeight,scrollbar:{size:c.current.clientHeight,paddingStart:ch(a.paddingTop),paddingEnd:ch(a.paddingBottom)}})}})}),[gV,LP]=NP(Hs),$P=v.forwardRef((e,t)=>{const{__scopeScrollArea:n,sizes:r,hasThumb:s,onThumbChange:o,onThumbPointerUp:a,onThumbPointerDown:l,onThumbPositionChange:c,onDragScroll:i,onWheelScroll:d,onResize:p,...f}=e,h=Hr(Hs,n),[g,m]=v.useState(null),x=it(t,P=>m(P)),b=v.useRef(null),y=v.useRef(""),w=h.viewport,S=r.content-r.viewport,E=nn(d),C=nn(c),k=Tg(p,10);function T(P){if(b.current){const N=P.clientX-b.current.left,U=P.clientY-b.current.top;i({x:N,y:U})}}return v.useEffect(()=>{const P=N=>{const U=N.target;(g==null?void 0:g.contains(U))&&E(N,S)};return document.addEventListener("wheel",P,{passive:!1}),()=>document.removeEventListener("wheel",P,{passive:!1})},[w,g,S,E]),v.useEffect(C,[r,C]),tu(g,k),tu(h.content,k),u.jsx(gV,{scope:n,scrollbar:g,hasThumb:s,onThumbChange:nn(o),onThumbPointerUp:nn(a),onThumbPositionChange:C,onThumbPointerDown:nn(l),children:u.jsx(Ne.div,{...f,ref:x,style:{position:"absolute",...f.style},onPointerDown:Se(e.onPointerDown,P=>{P.button===0&&(P.target.setPointerCapture(P.pointerId),b.current=g.getBoundingClientRect(),y.current=document.body.style.webkitUserSelect,document.body.style.webkitUserSelect="none",h.viewport&&(h.viewport.style.scrollBehavior="auto"),T(P))}),onPointerMove:Se(e.onPointerMove,T),onPointerUp:Se(e.onPointerUp,P=>{const N=P.target;N.hasPointerCapture(P.pointerId)&&N.releasePointerCapture(P.pointerId),document.body.style.webkitUserSelect=y.current,h.viewport&&(h.viewport.style.scrollBehavior=""),b.current=null})})})}),uh="ScrollAreaThumb",BP=v.forwardRef((e,t)=>{const{forceMount:n,...r}=e,s=LP(uh,e.__scopeScrollArea);return u.jsx(or,{present:n||s.hasThumb,children:u.jsx(mV,{ref:t,...r})})}),mV=v.forwardRef((e,t)=>{const{__scopeScrollArea:n,style:r,...s}=e,o=Hr(uh,n),a=LP(uh,n),{onThumbPositionChange:l}=a,c=it(t,p=>a.onThumbChange(p)),i=v.useRef(),d=Tg(()=>{i.current&&(i.current(),i.current=void 0)},100);return v.useEffect(()=>{const p=o.viewport;if(p){const f=()=>{if(d(),!i.current){const h=bV(p,l);i.current=h,l()}};return l(),p.addEventListener("scroll",f),()=>p.removeEventListener("scroll",f)}},[o.viewport,d,l]),u.jsx(Ne.div,{"data-state":a.hasThumb?"visible":"hidden",...s,ref:c,style:{width:"var(--radix-scroll-area-thumb-width)",height:"var(--radix-scroll-area-thumb-height)",...r},onPointerDownCapture:Se(e.onPointerDownCapture,p=>{const h=p.target.getBoundingClientRect(),g=p.clientX-h.left,m=p.clientY-h.top;a.onThumbPointerDown({x:g,y:m})}),onPointerUp:Se(e.onPointerUp,a.onThumbPointerUp)})});BP.displayName=uh;var mw="ScrollAreaCorner",zP=v.forwardRef((e,t)=>{const n=Hr(mw,e.__scopeScrollArea),r=!!(n.scrollbarX&&n.scrollbarY);return n.type!=="scroll"&&r?u.jsx(vV,{...e,ref:t}):null});zP.displayName=mw;var vV=v.forwardRef((e,t)=>{const{__scopeScrollArea:n,...r}=e,s=Hr(mw,n),[o,a]=v.useState(0),[l,c]=v.useState(0),i=!!(o&&l);return tu(s.scrollbarX,()=>{var p;const d=((p=s.scrollbarX)==null?void 0:p.offsetHeight)||0;s.onCornerHeightChange(d),c(d)}),tu(s.scrollbarY,()=>{var p;const d=((p=s.scrollbarY)==null?void 0:p.offsetWidth)||0;s.onCornerWidthChange(d),a(d)}),i?u.jsx(Ne.div,{...r,ref:t,style:{width:o,height:l,position:"absolute",right:s.dir==="ltr"?0:void 0,left:s.dir==="rtl"?0:void 0,bottom:0,...e.style}}):null});function ch(e){return e?parseInt(e,10):0}function UP(e,t){const n=e/t;return isNaN(n)?0:n}function Eg(e){const t=UP(e.viewport,e.content),n=e.scrollbar.paddingStart+e.scrollbar.paddingEnd,r=(e.scrollbar.size-n)*t;return Math.max(r,18)}function yV(e,t,n,r="ltr"){const s=Eg(n),o=s/2,a=t||o,l=s-a,c=n.scrollbar.paddingStart+a,i=n.scrollbar.size-n.scrollbar.paddingEnd-l,d=n.content-n.viewport,p=r==="ltr"?[0,d]:[d*-1,0];return VP([c,i],p)(e)}function SC(e,t,n="ltr"){const r=Eg(t),s=t.scrollbar.paddingStart+t.scrollbar.paddingEnd,o=t.scrollbar.size-s,a=t.content-t.viewport,l=o-r,c=n==="ltr"?[0,a]:[a*-1,0],i=Zy(e,c);return VP([0,a],[0,l])(i)}function VP(e,t){return n=>{if(e[0]===e[1]||t[0]===t[1])return t[0];const r=(t[1]-t[0])/(e[1]-e[0]);return t[0]+r*(n-e[0])}}function HP(e,t){return e>0&&e{})=>{let n={left:e.scrollLeft,top:e.scrollTop},r=0;return function s(){const o={left:e.scrollLeft,top:e.scrollTop},a=n.left!==o.left,l=n.top!==o.top;(a||l)&&t(),n=o,r=window.requestAnimationFrame(s)}(),()=>window.cancelAnimationFrame(r)};function Tg(e,t){const n=nn(e),r=v.useRef(0);return v.useEffect(()=>()=>window.clearTimeout(r.current),[]),v.useCallback(()=>{window.clearTimeout(r.current),r.current=window.setTimeout(n,t)},[n,t])}function tu(e,t){const n=nn(t);fn(()=>{let r=0;if(e){const s=new ResizeObserver(()=>{cancelAnimationFrame(r),r=window.requestAnimationFrame(n)});return s.observe(e),()=>{window.cancelAnimationFrame(r),s.unobserve(e)}}},[e,n])}var KP=IP,xV=AP,wV=zP;const Yy=v.forwardRef(({className:e,children:t,...n},r)=>u.jsxs(KP,{ref:r,className:ge("relative overflow-hidden",e),...n,children:[u.jsx(xV,{className:"h-full w-full rounded-[inherit] [&>div[style]]:!block [&>div[style]]:h-full",children:t}),u.jsx(qP,{}),u.jsx(wV,{})]}));Yy.displayName=KP.displayName;const qP=v.forwardRef(({className:e,orientation:t="vertical",...n},r)=>u.jsx(hw,{ref:r,orientation:t,className:ge("flex touch-none select-none transition-colors",t==="vertical"&&"h-full w-2.5 border-l border-l-transparent p-[1px]",t==="horizontal"&&"h-2.5 border-t border-t-transparent p-[1px]",e),...n,children:u.jsx(BP,{className:ge("relative rounded-full bg-border",t==="vertical"&&"flex-1")})}));qP.displayName=hw.displayName;function Xt({children:e}){const{instanceId:t}=So();return u.jsx(eV,{children:u.jsxs("div",{className:"flex h-screen flex-col",children:[u.jsx(_P,{instanceId:t}),u.jsxs("div",{className:"flex min-h-[calc(100vh_-_56px)] flex-1 flex-col md:flex-row",children:[u.jsx(Yy,{className:"mr-2 py-6 md:w-64",children:u.jsx("div",{className:"flex h-full",children:u.jsx(lV,{})})}),u.jsx(Yy,{className:"w-full",children:u.jsxs("div",{className:"flex h-full flex-col",children:[u.jsx("div",{className:"my-6 flex flex-1 flex-col gap-2 pl-2 pr-4",children:e}),u.jsx(Ax,{})]})})]})]})})}function SV({children:e}){return u.jsxs("div",{className:"flex h-full min-h-screen flex-col",children:[u.jsx(_P,{}),u.jsx("main",{className:"flex-1",children:e}),u.jsx(Ax,{})]})}const CV=ig("inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",{variants:{variant:{default:"border-transparent bg-primary text-primary-foreground hover:bg-primary/80",secondary:"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",destructive:"border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",outline:"text-foreground",warning:"border-transparent bg-amber-600 text-amber-100 hover:bg-amber-600/80"}},defaultVariants:{variant:"default"}});function Ff({className:e,variant:t,...n}){return u.jsx("div",{className:ge(CV({variant:t}),e),...n})}function WP({status:e}){const{t}=ze();return e?e==="open"?u.jsx(Ff,{children:t("status.open")}):e==="connecting"?u.jsx(Ff,{variant:"warning",children:t("status.connecting")}):e==="close"||e==="closed"?u.jsx(Ff,{variant:"destructive",children:t("status.closed")}):u.jsx(Ff,{variant:"secondary",children:e}):null}const EV=e=>{navigator.clipboard.writeText(e),X.success("Copiado para a área de transferência")};function GP({token:e,className:t}){const[n,r]=v.useState(!1);return u.jsxs("div",{className:ge("flex items-center gap-3 truncate rounded-sm bg-primary/20 px-2 py-1",t),children:[u.jsx("pre",{className:"block truncate text-xs",children:n?e:e==null?void 0:e.replace(/\w/g,"*")}),u.jsx(q,{variant:"ghost",size:"icon",onClick:()=>{EV(e)},children:u.jsx(I3,{size:"15"})}),u.jsx(q,{variant:"ghost",size:"icon",onClick:()=>{r(s=>!s)},children:n?u.jsx(A3,{size:"15"}):u.jsx(F3,{size:"15"})})]})}const Ja=v.forwardRef(({className:e,...t},n)=>u.jsx("div",{ref:n,className:ge("flex flex-col rounded-lg border bg-card text-card-foreground shadow-sm",e),...t}));Ja.displayName="Card";const Qa=v.forwardRef(({className:e,...t},n)=>u.jsx("div",{ref:n,className:ge("flex flex-col space-y-1.5 p-6",e),...t}));Qa.displayName="CardHeader";const jc=v.forwardRef(({className:e,...t},n)=>u.jsx("h3",{ref:n,className:ge("text-2xl font-semibold leading-none tracking-tight",e),...t}));jc.displayName="CardTitle";const JP=v.forwardRef(({className:e,...t},n)=>u.jsx("p",{ref:n,className:ge("text-sm text-muted-foreground",e),...t}));JP.displayName="CardDescription";const Za=v.forwardRef(({className:e,...t},n)=>u.jsx("div",{ref:n,className:ge("p-6 pt-0",e),...t}));Za.displayName="CardContent";const kg=v.forwardRef(({className:e,...t},n)=>u.jsx("div",{ref:n,className:ge("flex items-center p-6 pt-0",e),...t}));kg.displayName="CardFooter";const QP="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",K=v.forwardRef(({className:e,type:t,...n},r)=>u.jsx("input",{type:t,className:ge(QP,e),ref:r,...n}));K.displayName="Input";const TV=["instance","fetchInstances"],kV=async()=>(await he.get("/instance/fetchInstances")).data,_V=e=>lt({...e,queryKey:TV,queryFn:()=>kV()});function Ye(e,t){const n=Ab(),r=WD({mutationFn:e});return(s,o)=>r.mutateAsync(s,{onSuccess:async(a,l,c)=>{var i;t!=null&&t.invalidateKeys&&await Promise.all(t.invalidateKeys.map(d=>n.invalidateQueries({queryKey:d}))),(i=o==null?void 0:o.onSuccess)==null||i.call(o,a,l,c)},onError(a,l,c){var i;(i=o==null?void 0:o.onError)==null||i.call(o,a,l,c)},onSettled(a,l,c,i){var d;(d=o==null?void 0:o.onSettled)==null||d.call(o,a,l,c,i)}})}const jV=async e=>(await he.post("/instance/create",e)).data,RV=async e=>(await he.post(`/instance/restart/${e}`)).data,PV=async e=>(await he.delete(`/instance/logout/${e}`)).data,MV=async e=>(await he.delete(`/instance/delete/${e}`)).data,OV=async({instanceName:e,token:t,number:n})=>(await he.get(`/instance/connect/${e}`,{headers:{apikey:t},params:{number:n}})).data,NV=async({instanceName:e,token:t,data:n})=>(await he.post(`/settings/set/${e}`,n,{headers:{apikey:t}})).data;function _g(){const e=Ye(OV,{invalidateKeys:[["instance","fetchInstance"],["instance","fetchInstances"]]}),t=Ye(NV,{invalidateKeys:[["instance","fetchSettings"]]}),n=Ye(MV,{invalidateKeys:[["instance","fetchInstance"],["instance","fetchInstances"]]}),r=Ye(PV,{invalidateKeys:[["instance","fetchInstance"],["instance","fetchInstances"]]}),s=Ye(RV,{invalidateKeys:[["instance","fetchInstance"],["instance","fetchInstances"]]}),o=Ye(jV,{invalidateKeys:[["instance","fetchInstances"]]});return{connect:e,updateSettings:t,deleteInstance:n,logout:r,restart:s,createInstance:o}}var Yd=e=>e.type==="checkbox",ml=e=>e instanceof Date,Un=e=>e==null;const ZP=e=>typeof e=="object";var pn=e=>!Un(e)&&!Array.isArray(e)&&ZP(e)&&!ml(e),YP=e=>pn(e)&&e.target?Yd(e.target)?e.target.checked:e.target.value:e,IV=e=>e.substring(0,e.search(/\.\d+(\.|$)/))||e,XP=(e,t)=>e.has(IV(t)),DV=e=>{const t=e.constructor&&e.constructor.prototype;return pn(t)&&t.hasOwnProperty("isPrototypeOf")},vw=typeof window<"u"&&typeof window.HTMLElement<"u"&&typeof document<"u";function Jn(e){let t;const n=Array.isArray(e);if(e instanceof Date)t=new Date(e);else if(e instanceof Set)t=new Set(e);else if(!(vw&&(e instanceof Blob||e instanceof FileList))&&(n||pn(e)))if(t=n?[]:{},!n&&!DV(e))t=e;else for(const r in e)e.hasOwnProperty(r)&&(t[r]=Jn(e[r]));else return e;return t}var jg=e=>Array.isArray(e)?e.filter(Boolean):[],qt=e=>e===void 0,ce=(e,t,n)=>{if(!t||!pn(e))return n;const r=jg(t.split(/[,[\].]+?/)).reduce((s,o)=>Un(s)?s:s[o],e);return qt(r)||r===e?qt(e[t])?n:e[t]:r},js=e=>typeof e=="boolean",yw=e=>/^\w*$/.test(e),eM=e=>jg(e.replace(/["|']|\]/g,"").split(/\.|\[/)),ht=(e,t,n)=>{let r=-1;const s=yw(t)?[t]:eM(t),o=s.length,a=o-1;for(;++rTe.useContext(tM),Tr=e=>{const{children:t,...n}=e;return Te.createElement(tM.Provider,{value:n},t)};var nM=(e,t,n,r=!0)=>{const s={defaultValues:t._defaultValues};for(const o in e)Object.defineProperty(s,o,{get:()=>{const a=o;return t._proxyFormState[a]!==Yr.all&&(t._proxyFormState[a]=!r||Yr.all),n&&(n[a]=!0),e[a]}});return s},ur=e=>pn(e)&&!Object.keys(e).length,rM=(e,t,n,r)=>{n(e);const{name:s,...o}=e;return ur(o)||Object.keys(o).length>=Object.keys(t).length||Object.keys(o).find(a=>t[a]===(!r||Yr.all))},Rc=e=>Array.isArray(e)?e:[e],sM=(e,t,n)=>!e||!t||e===t||Rc(e).some(r=>r&&(n?r===t:r.startsWith(t)||t.startsWith(r)));function bw(e){const t=Te.useRef(e);t.current=e,Te.useEffect(()=>{const n=!e.disabled&&t.current.subject&&t.current.subject.subscribe({next:t.current.next});return()=>{n&&n.unsubscribe()}},[e.disabled])}function AV(e){const t=Rg(),{control:n=t.control,disabled:r,name:s,exact:o}=e||{},[a,l]=Te.useState(n._formState),c=Te.useRef(!0),i=Te.useRef({isDirty:!1,isLoading:!1,dirtyFields:!1,touchedFields:!1,validatingFields:!1,isValidating:!1,isValid:!1,errors:!1}),d=Te.useRef(s);return d.current=s,bw({disabled:r,next:p=>c.current&&sM(d.current,p.name,o)&&rM(p,i.current,n._updateFormState)&&l({...n._formState,...p}),subject:n._subjects.state}),Te.useEffect(()=>(c.current=!0,i.current.isValid&&n._updateValid(!0),()=>{c.current=!1}),[n]),nM(a,n,i.current,!1)}var Os=e=>typeof e=="string",oM=(e,t,n,r,s)=>Os(e)?(r&&t.watch.add(e),ce(n,e,s)):Array.isArray(e)?e.map(o=>(r&&t.watch.add(o),ce(n,o))):(r&&(t.watchAll=!0),n);function FV(e){const t=Rg(),{control:n=t.control,name:r,defaultValue:s,disabled:o,exact:a}=e||{},l=Te.useRef(r);l.current=r,bw({disabled:o,subject:n._subjects.values,next:d=>{sM(l.current,d.name,a)&&i(Jn(oM(l.current,n._names,d.values||n._formValues,!1,s)))}});const[c,i]=Te.useState(n._getWatch(r,s));return Te.useEffect(()=>n._removeUnmounted()),c}function LV(e){const t=Rg(),{name:n,disabled:r,control:s=t.control,shouldUnregister:o}=e,a=XP(s._names.array,n),l=FV({control:s,name:n,defaultValue:ce(s._formValues,n,ce(s._defaultValues,n,e.defaultValue)),exact:!0}),c=AV({control:s,name:n}),i=Te.useRef(s.register(n,{...e.rules,value:l,...js(e.disabled)?{disabled:e.disabled}:{}}));return Te.useEffect(()=>{const d=s._options.shouldUnregister||o,p=(f,h)=>{const g=ce(s._fields,f);g&&g._f&&(g._f.mount=h)};if(p(n,!0),d){const f=Jn(ce(s._options.defaultValues,n));ht(s._defaultValues,n,f),qt(ce(s._formValues,n))&&ht(s._formValues,n,f)}return()=>{(a?d&&!s._state.action:d)?s.unregister(n):p(n,!1)}},[n,s,a,o]),Te.useEffect(()=>{ce(s._fields,n)&&s._updateDisabledField({disabled:r,fields:s._fields,name:n,value:ce(s._fields,n)._f.value})},[r,n,s]),{field:{name:n,value:l,...js(r)||c.disabled?{disabled:c.disabled||r}:{},onChange:Te.useCallback(d=>i.current.onChange({target:{value:YP(d),name:n},type:dh.CHANGE}),[n]),onBlur:Te.useCallback(()=>i.current.onBlur({target:{value:ce(s._formValues,n),name:n},type:dh.BLUR}),[n,s]),ref:d=>{const p=ce(s._fields,n);p&&d&&(p._f.ref={focus:()=>d.focus(),select:()=>d.select(),setCustomValidity:f=>d.setCustomValidity(f),reportValidity:()=>d.reportValidity()})}},formState:c,fieldState:Object.defineProperties({},{invalid:{enumerable:!0,get:()=>!!ce(c.errors,n)},isDirty:{enumerable:!0,get:()=>!!ce(c.dirtyFields,n)},isTouched:{enumerable:!0,get:()=>!!ce(c.touchedFields,n)},isValidating:{enumerable:!0,get:()=>!!ce(c.validatingFields,n)},error:{enumerable:!0,get:()=>ce(c.errors,n)}})}}const $V=e=>e.render(LV(e));var aM=(e,t,n,r,s)=>t?{...n[e],types:{...n[e]&&n[e].types?n[e].types:{},[r]:s||!0}}:{},CC=e=>({isOnSubmit:!e||e===Yr.onSubmit,isOnBlur:e===Yr.onBlur,isOnChange:e===Yr.onChange,isOnAll:e===Yr.all,isOnTouch:e===Yr.onTouched}),EC=(e,t,n)=>!n&&(t.watchAll||t.watch.has(e)||[...t.watch].some(r=>e.startsWith(r)&&/^\.\w+/.test(e.slice(r.length))));const Pc=(e,t,n,r)=>{for(const s of n||Object.keys(e)){const o=ce(e,s);if(o){const{_f:a,...l}=o;if(a){if(a.refs&&a.refs[0]&&t(a.refs[0],s)&&!r)break;if(a.ref&&t(a.ref,a.name)&&!r)break;Pc(l,t)}else pn(l)&&Pc(l,t)}}};var BV=(e,t,n)=>{const r=Rc(ce(e,n));return ht(r,"root",t[n]),ht(e,n,r),e},xw=e=>e.type==="file",ta=e=>typeof e=="function",fh=e=>{if(!vw)return!1;const t=e?e.ownerDocument:0;return e instanceof(t&&t.defaultView?t.defaultView.HTMLElement:HTMLElement)},vp=e=>Os(e),ww=e=>e.type==="radio",ph=e=>e instanceof RegExp;const TC={value:!1,isValid:!1},kC={value:!0,isValid:!0};var iM=e=>{if(Array.isArray(e)){if(e.length>1){const t=e.filter(n=>n&&n.checked&&!n.disabled).map(n=>n.value);return{value:t,isValid:!!t.length}}return e[0].checked&&!e[0].disabled?e[0].attributes&&!qt(e[0].attributes.value)?qt(e[0].value)||e[0].value===""?kC:{value:e[0].value,isValid:!0}:kC:TC}return TC};const _C={isValid:!1,value:null};var lM=e=>Array.isArray(e)?e.reduce((t,n)=>n&&n.checked&&!n.disabled?{isValid:!0,value:n.value}:t,_C):_C;function jC(e,t,n="validate"){if(vp(e)||Array.isArray(e)&&e.every(vp)||js(e)&&!e)return{type:n,message:vp(e)?e:"",ref:t}}var Gi=e=>pn(e)&&!ph(e)?e:{value:e,message:""},RC=async(e,t,n,r,s)=>{const{ref:o,refs:a,required:l,maxLength:c,minLength:i,min:d,max:p,pattern:f,validate:h,name:g,valueAsNumber:m,mount:x,disabled:b}=e._f,y=ce(t,g);if(!x||b)return{};const w=a?a[0]:o,S=I=>{r&&w.reportValidity&&(w.setCustomValidity(js(I)?"":I||""),w.reportValidity())},E={},C=ww(o),k=Yd(o),T=C||k,P=(m||xw(o))&&qt(o.value)&&qt(y)||fh(o)&&o.value===""||y===""||Array.isArray(y)&&!y.length,N=aM.bind(null,g,n,E),U=(I,Z,V,Q=Ws.maxLength,ee=Ws.minLength)=>{const W=I?Z:V;E[g]={type:I?Q:ee,message:W,ref:o,...N(I?Q:ee,W)}};if(s?!Array.isArray(y)||!y.length:l&&(!T&&(P||Un(y))||js(y)&&!y||k&&!iM(a).isValid||C&&!lM(a).isValid)){const{value:I,message:Z}=vp(l)?{value:!!l,message:l}:Gi(l);if(I&&(E[g]={type:Ws.required,message:Z,ref:w,...N(Ws.required,Z)},!n))return S(Z),E}if(!P&&(!Un(d)||!Un(p))){let I,Z;const V=Gi(p),Q=Gi(d);if(!Un(y)&&!isNaN(y)){const ee=o.valueAsNumber||y&&+y;Un(V.value)||(I=ee>V.value),Un(Q.value)||(Z=eenew Date(new Date().toDateString()+" "+Y),F=o.type=="time",A=o.type=="week";Os(V.value)&&y&&(I=F?W(y)>W(V.value):A?y>V.value:ee>new Date(V.value)),Os(Q.value)&&y&&(Z=F?W(y)+I.value,Q=!Un(Z.value)&&y.length<+Z.value;if((V||Q)&&(U(V,I.message,Z.message),!n))return S(E[g].message),E}if(f&&!P&&Os(y)){const{value:I,message:Z}=Gi(f);if(ph(I)&&!y.match(I)&&(E[g]={type:Ws.pattern,message:Z,ref:o,...N(Ws.pattern,Z)},!n))return S(Z),E}if(h){if(ta(h)){const I=await h(y,t),Z=jC(I,w);if(Z&&(E[g]={...Z,...N(Ws.validate,Z.message)},!n))return S(Z.message),E}else if(pn(h)){let I={};for(const Z in h){if(!ur(I)&&!n)break;const V=jC(await h[Z](y,t),w,Z);V&&(I={...V,...N(Z,V.message)},S(V.message),n&&(E[g]=I))}if(!ur(I)&&(E[g]={ref:w,...I},!n))return E}}return S(!0),E};function zV(e,t){const n=t.slice(0,-1).length;let r=0;for(;r{let e=[];return{get observers(){return e},next:s=>{for(const o of e)o.next&&o.next(s)},subscribe:s=>(e.push(s),{unsubscribe:()=>{e=e.filter(o=>o!==s)}}),unsubscribe:()=>{e=[]}}},hh=e=>Un(e)||!ZP(e);function Ya(e,t){if(hh(e)||hh(t))return e===t;if(ml(e)&&ml(t))return e.getTime()===t.getTime();const n=Object.keys(e),r=Object.keys(t);if(n.length!==r.length)return!1;for(const s of n){const o=e[s];if(!r.includes(s))return!1;if(s!=="ref"){const a=t[s];if(ml(o)&&ml(a)||pn(o)&&pn(a)||Array.isArray(o)&&Array.isArray(a)?!Ya(o,a):o!==a)return!1}}return!0}var uM=e=>e.type==="select-multiple",VV=e=>ww(e)||Yd(e),Zm=e=>fh(e)&&e.isConnected,cM=e=>{for(const t in e)if(ta(e[t]))return!0;return!1};function gh(e,t={}){const n=Array.isArray(e);if(pn(e)||n)for(const r in e)Array.isArray(e[r])||pn(e[r])&&!cM(e[r])?(t[r]=Array.isArray(e[r])?[]:{},gh(e[r],t[r])):Un(e[r])||(t[r]=!0);return t}function dM(e,t,n){const r=Array.isArray(e);if(pn(e)||r)for(const s in e)Array.isArray(e[s])||pn(e[s])&&!cM(e[s])?qt(t)||hh(n[s])?n[s]=Array.isArray(e[s])?gh(e[s],[]):{...gh(e[s])}:dM(e[s],Un(t)?{}:t[s],n[s]):n[s]=!Ya(e[s],t[s]);return n}var Lf=(e,t)=>dM(e,t,gh(t)),fM=(e,{valueAsNumber:t,valueAsDate:n,setValueAs:r})=>qt(e)?e:t?e===""?NaN:e&&+e:n&&Os(e)?new Date(e):r?r(e):e;function Ym(e){const t=e.ref;if(!(e.refs?e.refs.every(n=>n.disabled):t.disabled))return xw(t)?t.files:ww(t)?lM(e.refs).value:uM(t)?[...t.selectedOptions].map(({value:n})=>n):Yd(t)?iM(e.refs).value:fM(qt(t.value)?e.ref.value:t.value,e)}var HV=(e,t,n,r)=>{const s={};for(const o of e){const a=ce(t,o);a&&ht(s,o,a._f)}return{criteriaMode:n,names:[...e],fields:s,shouldUseNativeValidation:r}},Zu=e=>qt(e)?e:ph(e)?e.source:pn(e)?ph(e.value)?e.value.source:e.value:e,KV=e=>e.mount&&(e.required||e.min||e.max||e.maxLength||e.minLength||e.pattern||e.validate);function PC(e,t,n){const r=ce(e,n);if(r||yw(n))return{error:r,name:n};const s=n.split(".");for(;s.length;){const o=s.join("."),a=ce(t,o),l=ce(e,o);if(a&&!Array.isArray(a)&&n!==o)return{name:n};if(l&&l.type)return{name:o,error:l};s.pop()}return{name:n}}var qV=(e,t,n,r,s)=>s.isOnAll?!1:!n&&s.isOnTouch?!(t||e):(n?r.isOnBlur:s.isOnBlur)?!e:(n?r.isOnChange:s.isOnChange)?e:!0,WV=(e,t)=>!jg(ce(e,t)).length&&ln(e,t);const GV={mode:Yr.onSubmit,reValidateMode:Yr.onChange,shouldFocusError:!0};function JV(e={}){let t={...GV,...e},n={submitCount:0,isDirty:!1,isLoading:ta(t.defaultValues),isValidating:!1,isSubmitted:!1,isSubmitting:!1,isSubmitSuccessful:!1,isValid:!1,touchedFields:{},dirtyFields:{},validatingFields:{},errors:t.errors||{},disabled:t.disabled||!1},r={},s=pn(t.defaultValues)||pn(t.values)?Jn(t.defaultValues||t.values)||{}:{},o=t.shouldUnregister?{}:Jn(s),a={action:!1,mount:!1,watch:!1},l={mount:new Set,unMount:new Set,array:new Set,watch:new Set},c,i=0;const d={isDirty:!1,dirtyFields:!1,validatingFields:!1,touchedFields:!1,isValidating:!1,isValid:!1,errors:!1},p={values:Qm(),array:Qm(),state:Qm()},f=CC(t.mode),h=CC(t.reValidateMode),g=t.criteriaMode===Yr.all,m=j=>D=>{clearTimeout(i),i=setTimeout(j,D)},x=async j=>{if(d.isValid||j){const D=t.resolver?ur((await T()).errors):await N(r,!0);D!==n.isValid&&p.state.next({isValid:D})}},b=(j,D)=>{(d.isValidating||d.validatingFields)&&((j||Array.from(l.mount)).forEach(B=>{B&&(D?ht(n.validatingFields,B,D):ln(n.validatingFields,B))}),p.state.next({validatingFields:n.validatingFields,isValidating:!ur(n.validatingFields)}))},y=(j,D=[],B,pe,le=!0,ae=!0)=>{if(pe&&B){if(a.action=!0,ae&&Array.isArray(ce(r,j))){const Ee=B(ce(r,j),pe.argA,pe.argB);le&&ht(r,j,Ee)}if(ae&&Array.isArray(ce(n.errors,j))){const Ee=B(ce(n.errors,j),pe.argA,pe.argB);le&&ht(n.errors,j,Ee),WV(n.errors,j)}if(d.touchedFields&&ae&&Array.isArray(ce(n.touchedFields,j))){const Ee=B(ce(n.touchedFields,j),pe.argA,pe.argB);le&&ht(n.touchedFields,j,Ee)}d.dirtyFields&&(n.dirtyFields=Lf(s,o)),p.state.next({name:j,isDirty:I(j,D),dirtyFields:n.dirtyFields,errors:n.errors,isValid:n.isValid})}else ht(o,j,D)},w=(j,D)=>{ht(n.errors,j,D),p.state.next({errors:n.errors})},S=j=>{n.errors=j,p.state.next({errors:n.errors,isValid:!1})},E=(j,D,B,pe)=>{const le=ce(r,j);if(le){const ae=ce(o,j,qt(B)?ce(s,j):B);qt(ae)||pe&&pe.defaultChecked||D?ht(o,j,D?ae:Ym(le._f)):Q(j,ae),a.mount&&x()}},C=(j,D,B,pe,le)=>{let ae=!1,Ee=!1;const et={name:j},kt=!!(ce(r,j)&&ce(r,j)._f&&ce(r,j)._f.disabled);if(!B||pe){d.isDirty&&(Ee=n.isDirty,n.isDirty=et.isDirty=I(),ae=Ee!==et.isDirty);const hn=kt||Ya(ce(s,j),D);Ee=!!(!kt&&ce(n.dirtyFields,j)),hn||kt?ln(n.dirtyFields,j):ht(n.dirtyFields,j,!0),et.dirtyFields=n.dirtyFields,ae=ae||d.dirtyFields&&Ee!==!hn}if(B){const hn=ce(n.touchedFields,j);hn||(ht(n.touchedFields,j,B),et.touchedFields=n.touchedFields,ae=ae||d.touchedFields&&hn!==B)}return ae&&le&&p.state.next(et),ae?et:{}},k=(j,D,B,pe)=>{const le=ce(n.errors,j),ae=d.isValid&&js(D)&&n.isValid!==D;if(e.delayError&&B?(c=m(()=>w(j,B)),c(e.delayError)):(clearTimeout(i),c=null,B?ht(n.errors,j,B):ln(n.errors,j)),(B?!Ya(le,B):le)||!ur(pe)||ae){const Ee={...pe,...ae&&js(D)?{isValid:D}:{},errors:n.errors,name:j};n={...n,...Ee},p.state.next(Ee)}},T=async j=>{b(j,!0);const D=await t.resolver(o,t.context,HV(j||l.mount,r,t.criteriaMode,t.shouldUseNativeValidation));return b(j),D},P=async j=>{const{errors:D}=await T(j);if(j)for(const B of j){const pe=ce(D,B);pe?ht(n.errors,B,pe):ln(n.errors,B)}else n.errors=D;return D},N=async(j,D,B={valid:!0})=>{for(const pe in j){const le=j[pe];if(le){const{_f:ae,...Ee}=le;if(ae){const et=l.array.has(ae.name);b([pe],!0);const kt=await RC(le,o,g,t.shouldUseNativeValidation&&!D,et);if(b([pe]),kt[ae.name]&&(B.valid=!1,D))break;!D&&(ce(kt,ae.name)?et?BV(n.errors,kt,ae.name):ht(n.errors,ae.name,kt[ae.name]):ln(n.errors,ae.name))}Ee&&await N(Ee,D,B)}}return B.valid},U=()=>{for(const j of l.unMount){const D=ce(r,j);D&&(D._f.refs?D._f.refs.every(B=>!Zm(B)):!Zm(D._f.ref))&&oe(j)}l.unMount=new Set},I=(j,D)=>(j&&D&&ht(o,j,D),!Ya(de(),s)),Z=(j,D,B)=>oM(j,l,{...a.mount?o:qt(D)?s:Os(j)?{[j]:D}:D},B,D),V=j=>jg(ce(a.mount?o:s,j,e.shouldUnregister?ce(s,j,[]):[])),Q=(j,D,B={})=>{const pe=ce(r,j);let le=D;if(pe){const ae=pe._f;ae&&(!ae.disabled&&ht(o,j,fM(D,ae)),le=fh(ae.ref)&&Un(D)?"":D,uM(ae.ref)?[...ae.ref.options].forEach(Ee=>Ee.selected=le.includes(Ee.value)):ae.refs?Yd(ae.ref)?ae.refs.length>1?ae.refs.forEach(Ee=>(!Ee.defaultChecked||!Ee.disabled)&&(Ee.checked=Array.isArray(le)?!!le.find(et=>et===Ee.value):le===Ee.value)):ae.refs[0]&&(ae.refs[0].checked=!!le):ae.refs.forEach(Ee=>Ee.checked=Ee.value===le):xw(ae.ref)?ae.ref.value="":(ae.ref.value=le,ae.ref.type||p.values.next({name:j,values:{...o}})))}(B.shouldDirty||B.shouldTouch)&&C(j,le,B.shouldTouch,B.shouldDirty,!0),B.shouldValidate&&Y(j)},ee=(j,D,B)=>{for(const pe in D){const le=D[pe],ae=`${j}.${pe}`,Ee=ce(r,ae);(l.array.has(j)||!hh(le)||Ee&&!Ee._f)&&!ml(le)?ee(ae,le,B):Q(ae,le,B)}},W=(j,D,B={})=>{const pe=ce(r,j),le=l.array.has(j),ae=Jn(D);ht(o,j,ae),le?(p.array.next({name:j,values:{...o}}),(d.isDirty||d.dirtyFields)&&B.shouldDirty&&p.state.next({name:j,dirtyFields:Lf(s,o),isDirty:I(j,ae)})):pe&&!pe._f&&!Un(ae)?ee(j,ae,B):Q(j,ae,B),EC(j,l)&&p.state.next({...n}),p.values.next({name:a.mount?j:void 0,values:{...o}})},F=async j=>{a.mount=!0;const D=j.target;let B=D.name,pe=!0;const le=ce(r,B),ae=()=>D.type?Ym(le._f):YP(j),Ee=et=>{pe=Number.isNaN(et)||et===ce(o,B,et)};if(le){let et,kt;const hn=ae(),yn=j.type===dh.BLUR||j.type===dh.FOCUS_OUT,gn=!KV(le._f)&&!t.resolver&&!ce(n.errors,B)&&!le._f.deps||qV(yn,ce(n.touchedFields,B),n.isSubmitted,h,f),jo=EC(B,l,yn);ht(o,B,hn),yn?(le._f.onBlur&&le._f.onBlur(j),c&&c(0)):le._f.onChange&&le._f.onChange(j);const gs=C(B,hn,yn,!1),Aa=!ur(gs)||jo;if(!yn&&p.values.next({name:B,type:j.type,values:{...o}}),gn)return d.isValid&&x(),Aa&&p.state.next({name:B,...jo?{}:gs});if(!yn&&jo&&p.state.next({...n}),t.resolver){const{errors:Fn}=await T([B]);if(Ee(hn),pe){const ue=PC(n.errors,r,B),Ue=PC(Fn,r,ue.name||B);et=Ue.error,B=Ue.name,kt=ur(Fn)}}else b([B],!0),et=(await RC(le,o,g,t.shouldUseNativeValidation))[B],b([B]),Ee(hn),pe&&(et?kt=!1:d.isValid&&(kt=await N(r,!0)));pe&&(le._f.deps&&Y(le._f.deps),k(B,kt,et,gs))}},A=(j,D)=>{if(ce(n.errors,D)&&j.focus)return j.focus(),1},Y=async(j,D={})=>{let B,pe;const le=Rc(j);if(t.resolver){const ae=await P(qt(j)?j:le);B=ur(ae),pe=j?!le.some(Ee=>ce(ae,Ee)):B}else j?(pe=(await Promise.all(le.map(async ae=>{const Ee=ce(r,ae);return await N(Ee&&Ee._f?{[ae]:Ee}:Ee)}))).every(Boolean),!(!pe&&!n.isValid)&&x()):pe=B=await N(r);return p.state.next({...!Os(j)||d.isValid&&B!==n.isValid?{}:{name:j},...t.resolver||!j?{isValid:B}:{},errors:n.errors}),D.shouldFocus&&!pe&&Pc(r,A,j?le:l.mount),pe},de=j=>{const D={...a.mount?o:s};return qt(j)?D:Os(j)?ce(D,j):j.map(B=>ce(D,B))},z=(j,D)=>({invalid:!!ce((D||n).errors,j),isDirty:!!ce((D||n).dirtyFields,j),error:ce((D||n).errors,j),isValidating:!!ce(n.validatingFields,j),isTouched:!!ce((D||n).touchedFields,j)}),se=j=>{j&&Rc(j).forEach(D=>ln(n.errors,D)),p.state.next({errors:j?n.errors:{}})},ne=(j,D,B)=>{const pe=(ce(r,j,{_f:{}})._f||{}).ref,le=ce(n.errors,j)||{},{ref:ae,message:Ee,type:et,...kt}=le;ht(n.errors,j,{...kt,...D,ref:pe}),p.state.next({name:j,errors:n.errors,isValid:!1}),B&&B.shouldFocus&&pe&&pe.focus&&pe.focus()},ie=(j,D)=>ta(j)?p.values.subscribe({next:B=>j(Z(void 0,D),B)}):Z(j,D,!0),oe=(j,D={})=>{for(const B of j?Rc(j):l.mount)l.mount.delete(B),l.array.delete(B),D.keepValue||(ln(r,B),ln(o,B)),!D.keepError&&ln(n.errors,B),!D.keepDirty&&ln(n.dirtyFields,B),!D.keepTouched&&ln(n.touchedFields,B),!D.keepIsValidating&&ln(n.validatingFields,B),!t.shouldUnregister&&!D.keepDefaultValue&&ln(s,B);p.values.next({values:{...o}}),p.state.next({...n,...D.keepDirty?{isDirty:I()}:{}}),!D.keepIsValid&&x()},J=({disabled:j,name:D,field:B,fields:pe,value:le})=>{if(js(j)&&a.mount||j){const ae=j?void 0:qt(le)?Ym(B?B._f:ce(pe,D)._f):le;ht(o,D,ae),C(D,ae,!1,!1,!0)}},Ce=(j,D={})=>{let B=ce(r,j);const pe=js(D.disabled);return ht(r,j,{...B||{},_f:{...B&&B._f?B._f:{ref:{name:j}},name:j,mount:!0,...D}}),l.mount.add(j),B?J({field:B,disabled:D.disabled,name:j,value:D.value}):E(j,!0,D.value),{...pe?{disabled:D.disabled}:{},...t.progressive?{required:!!D.required,min:Zu(D.min),max:Zu(D.max),minLength:Zu(D.minLength),maxLength:Zu(D.maxLength),pattern:Zu(D.pattern)}:{},name:j,onChange:F,onBlur:F,ref:le=>{if(le){Ce(j,D),B=ce(r,j);const ae=qt(le.value)&&le.querySelectorAll&&le.querySelectorAll("input,select,textarea")[0]||le,Ee=VV(ae),et=B._f.refs||[];if(Ee?et.find(kt=>kt===ae):ae===B._f.ref)return;ht(r,j,{_f:{...B._f,...Ee?{refs:[...et.filter(Zm),ae,...Array.isArray(ce(s,j))?[{}]:[]],ref:{type:ae.type,name:j}}:{ref:ae}}}),E(j,!1,void 0,ae)}else B=ce(r,j,{}),B._f&&(B._f.mount=!1),(t.shouldUnregister||D.shouldUnregister)&&!(XP(l.array,j)&&a.action)&&l.unMount.add(j)}}},Pe=()=>t.shouldFocusError&&Pc(r,A,l.mount),Le=j=>{js(j)&&(p.state.next({disabled:j}),Pc(r,(D,B)=>{const pe=ce(r,B);pe&&(D.disabled=pe._f.disabled||j,Array.isArray(pe._f.refs)&&pe._f.refs.forEach(le=>{le.disabled=pe._f.disabled||j}))},0,!1))},Me=(j,D)=>async B=>{let pe;B&&(B.preventDefault&&B.preventDefault(),B.persist&&B.persist());let le=Jn(o);if(p.state.next({isSubmitting:!0}),t.resolver){const{errors:ae,values:Ee}=await T();n.errors=ae,le=Ee}else await N(r);if(ln(n.errors,"root"),ur(n.errors)){p.state.next({errors:{}});try{await j(le,B)}catch(ae){pe=ae}}else D&&await D({...n.errors},B),Pe(),setTimeout(Pe);if(p.state.next({isSubmitted:!0,isSubmitting:!1,isSubmitSuccessful:ur(n.errors)&&!pe,submitCount:n.submitCount+1,errors:n.errors}),pe)throw pe},me=(j,D={})=>{ce(r,j)&&(qt(D.defaultValue)?W(j,Jn(ce(s,j))):(W(j,D.defaultValue),ht(s,j,Jn(D.defaultValue))),D.keepTouched||ln(n.touchedFields,j),D.keepDirty||(ln(n.dirtyFields,j),n.isDirty=D.defaultValue?I(j,Jn(ce(s,j))):I()),D.keepError||(ln(n.errors,j),d.isValid&&x()),p.state.next({...n}))},rt=(j,D={})=>{const B=j?Jn(j):s,pe=Jn(B),le=ur(j),ae=le?s:pe;if(D.keepDefaultValues||(s=B),!D.keepValues){if(D.keepDirtyValues)for(const Ee of l.mount)ce(n.dirtyFields,Ee)?ht(ae,Ee,ce(o,Ee)):W(Ee,ce(ae,Ee));else{if(vw&&qt(j))for(const Ee of l.mount){const et=ce(r,Ee);if(et&&et._f){const kt=Array.isArray(et._f.refs)?et._f.refs[0]:et._f.ref;if(fh(kt)){const hn=kt.closest("form");if(hn){hn.reset();break}}}}r={}}o=e.shouldUnregister?D.keepDefaultValues?Jn(s):{}:Jn(ae),p.array.next({values:{...ae}}),p.values.next({values:{...ae}})}l={mount:D.keepDirtyValues?l.mount:new Set,unMount:new Set,array:new Set,watch:new Set,watchAll:!1,focus:""},a.mount=!d.isValid||!!D.keepIsValid||!!D.keepDirtyValues,a.watch=!!e.shouldUnregister,p.state.next({submitCount:D.keepSubmitCount?n.submitCount:0,isDirty:le?!1:D.keepDirty?n.isDirty:!!(D.keepDefaultValues&&!Ya(j,s)),isSubmitted:D.keepIsSubmitted?n.isSubmitted:!1,dirtyFields:le?{}:D.keepDirtyValues?D.keepDefaultValues&&o?Lf(s,o):n.dirtyFields:D.keepDefaultValues&&j?Lf(s,j):D.keepDirty?n.dirtyFields:{},touchedFields:D.keepTouched?n.touchedFields:{},errors:D.keepErrors?n.errors:{},isSubmitSuccessful:D.keepIsSubmitSuccessful?n.isSubmitSuccessful:!1,isSubmitting:!1})},It=(j,D)=>rt(ta(j)?j(o):j,D);return{control:{register:Ce,unregister:oe,getFieldState:z,handleSubmit:Me,setError:ne,_executeSchema:T,_getWatch:Z,_getDirty:I,_updateValid:x,_removeUnmounted:U,_updateFieldArray:y,_updateDisabledField:J,_getFieldArray:V,_reset:rt,_resetDefaultValues:()=>ta(t.defaultValues)&&t.defaultValues().then(j=>{It(j,t.resetOptions),p.state.next({isLoading:!1})}),_updateFormState:j=>{n={...n,...j}},_disableForm:Le,_subjects:p,_proxyFormState:d,_setErrors:S,get _fields(){return r},get _formValues(){return o},get _state(){return a},set _state(j){a=j},get _defaultValues(){return s},get _names(){return l},set _names(j){l=j},get _formState(){return n},set _formState(j){n=j},get _options(){return t},set _options(j){t={...t,...j}}},trigger:Y,register:Ce,handleSubmit:Me,watch:ie,setValue:W,getValues:de,reset:It,resetField:me,clearErrors:se,unregister:oe,setError:ne,setFocus:(j,D={})=>{const B=ce(r,j),pe=B&&B._f;if(pe){const le=pe.refs?pe.refs[0]:pe.ref;le.focus&&(le.focus(),D.shouldSelect&&le.select())}},getFieldState:z}}function sn(e={}){const t=Te.useRef(),n=Te.useRef(),[r,s]=Te.useState({isDirty:!1,isValidating:!1,isLoading:ta(e.defaultValues),isSubmitted:!1,isSubmitting:!1,isSubmitSuccessful:!1,isValid:!1,submitCount:0,dirtyFields:{},touchedFields:{},validatingFields:{},errors:e.errors||{},disabled:e.disabled||!1,defaultValues:ta(e.defaultValues)?void 0:e.defaultValues});t.current||(t.current={...JV(e),formState:r});const o=t.current.control;return o._options=e,bw({subject:o._subjects.state,next:a=>{rM(a,o._proxyFormState,o._updateFormState,!0)&&s({...o._formState})}}),Te.useEffect(()=>o._disableForm(e.disabled),[o,e.disabled]),Te.useEffect(()=>{if(o._proxyFormState.isDirty){const a=o._getDirty();a!==r.isDirty&&o._subjects.state.next({isDirty:a})}},[o,r.isDirty]),Te.useEffect(()=>{e.values&&!Ya(e.values,n.current)?(o._reset(e.values,o._options.resetOptions),n.current=e.values,s(a=>({...a}))):o._resetDefaultValues()},[e.values,o]),Te.useEffect(()=>{e.errors&&o._setErrors(e.errors)},[e.errors,o]),Te.useEffect(()=>{o._state.mount||(o._updateValid(),o._state.mount=!0),o._state.watch&&(o._state.watch=!1,o._subjects.state.next({...o._formState})),o._removeUnmounted()}),Te.useEffect(()=>{e.shouldUnregister&&o._subjects.values.next({values:o._getWatch()})},[e.shouldUnregister,o]),t.current.formState=nM(r,o),t.current}const MC=(e,t,n)=>{if(e&&"reportValidity"in e){const r=ce(n,t);e.setCustomValidity(r&&r.message||""),e.reportValidity()}},pM=(e,t)=>{for(const n in t.fields){const r=t.fields[n];r&&r.ref&&"reportValidity"in r.ref?MC(r.ref,n,e):r.refs&&r.refs.forEach(s=>MC(s,n,e))}},QV=(e,t)=>{t.shouldUseNativeValidation&&pM(e,t);const n={};for(const r in e){const s=ce(t.fields,r),o=Object.assign(e[r]||{},{ref:s&&s.ref});if(ZV(t.names||Object.keys(e),r)){const a=Object.assign({},ce(n,r));ht(a,"root",o),ht(n,r,a)}else ht(n,r,o)}return n},ZV=(e,t)=>e.some(n=>n.startsWith(t+"."));var YV=function(e,t){for(var n={};e.length;){var r=e[0],s=r.code,o=r.message,a=r.path.join(".");if(!n[a])if("unionErrors"in r){var l=r.unionErrors[0].errors[0];n[a]={message:l.message,type:l.code}}else n[a]={message:o,type:s};if("unionErrors"in r&&r.unionErrors.forEach(function(d){return d.errors.forEach(function(p){return e.push(p)})}),t){var c=n[a].types,i=c&&c[r.code];n[a]=aM(a,t,n,s,i?[].concat(i,r.message):r.message)}e.shift()}return n},on=function(e,t,n){return n===void 0&&(n={}),function(r,s,o){try{return Promise.resolve(function(a,l){try{var c=Promise.resolve(e[n.mode==="sync"?"parse":"parseAsync"](r,t)).then(function(i){return o.shouldUseNativeValidation&&pM({},o),{errors:{},values:n.raw?r:i}})}catch(i){return l(i)}return c&&c.then?c.then(void 0,l):c}(0,function(a){if(function(l){return Array.isArray(l==null?void 0:l.errors)}(a))return{values:{},errors:QV(YV(a.errors,!o.shouldUseNativeValidation&&o.criteriaMode==="all"),o)};throw a}))}catch(a){return Promise.reject(a)}}},xn=[];for(var Xm=0;Xm<256;++Xm)xn.push((Xm+256).toString(16).slice(1));function XV(e,t=0){return(xn[e[t+0]]+xn[e[t+1]]+xn[e[t+2]]+xn[e[t+3]]+"-"+xn[e[t+4]]+xn[e[t+5]]+"-"+xn[e[t+6]]+xn[e[t+7]]+"-"+xn[e[t+8]]+xn[e[t+9]]+"-"+xn[e[t+10]]+xn[e[t+11]]+xn[e[t+12]]+xn[e[t+13]]+xn[e[t+14]]+xn[e[t+15]]).toLowerCase()}var $f,e6=new Uint8Array(16);function t6(){if(!$f&&($f=typeof crypto<"u"&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto),!$f))throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");return $f(e6)}var n6=typeof crypto<"u"&&crypto.randomUUID&&crypto.randomUUID.bind(crypto);const OC={randomUUID:n6};function NC(e,t,n){if(OC.randomUUID&&!t&&!e)return OC.randomUUID();e=e||{};var r=e.random||(e.rng||t6)();return r[6]=r[6]&15|64,r[8]=r[8]&63|128,XV(r)}var ut;(function(e){e.assertEqual=s=>s;function t(s){}e.assertIs=t;function n(s){throw new Error}e.assertNever=n,e.arrayToEnum=s=>{const o={};for(const a of s)o[a]=a;return o},e.getValidEnumValues=s=>{const o=e.objectKeys(s).filter(l=>typeof s[s[l]]!="number"),a={};for(const l of o)a[l]=s[l];return e.objectValues(a)},e.objectValues=s=>e.objectKeys(s).map(function(o){return s[o]}),e.objectKeys=typeof Object.keys=="function"?s=>Object.keys(s):s=>{const o=[];for(const a in s)Object.prototype.hasOwnProperty.call(s,a)&&o.push(a);return o},e.find=(s,o)=>{for(const a of s)if(o(a))return a},e.isInteger=typeof Number.isInteger=="function"?s=>Number.isInteger(s):s=>typeof s=="number"&&isFinite(s)&&Math.floor(s)===s;function r(s,o=" | "){return s.map(a=>typeof a=="string"?`'${a}'`:a).join(o)}e.joinValues=r,e.jsonStringifyReplacer=(s,o)=>typeof o=="bigint"?o.toString():o})(ut||(ut={}));var Xy;(function(e){e.mergeShapes=(t,n)=>({...t,...n})})(Xy||(Xy={}));const be=ut.arrayToEnum(["string","nan","number","integer","float","boolean","date","bigint","symbol","function","undefined","null","array","object","unknown","promise","void","never","map","set"]),Vo=e=>{switch(typeof e){case"undefined":return be.undefined;case"string":return be.string;case"number":return isNaN(e)?be.nan:be.number;case"boolean":return be.boolean;case"function":return be.function;case"bigint":return be.bigint;case"symbol":return be.symbol;case"object":return Array.isArray(e)?be.array:e===null?be.null:e.then&&typeof e.then=="function"&&e.catch&&typeof e.catch=="function"?be.promise:typeof Map<"u"&&e instanceof Map?be.map:typeof Set<"u"&&e instanceof Set?be.set:typeof Date<"u"&&e instanceof Date?be.date:be.object;default:return be.unknown}},re=ut.arrayToEnum(["invalid_type","invalid_literal","custom","invalid_union","invalid_union_discriminator","invalid_enum_value","unrecognized_keys","invalid_arguments","invalid_return_type","invalid_date","invalid_string","too_small","too_big","invalid_intersection_types","not_multiple_of","not_finite"]),r6=e=>JSON.stringify(e,null,2).replace(/"([^"]+)":/g,"$1:");class yr extends Error{constructor(t){super(),this.issues=[],this.addIssue=r=>{this.issues=[...this.issues,r]},this.addIssues=(r=[])=>{this.issues=[...this.issues,...r]};const n=new.target.prototype;Object.setPrototypeOf?Object.setPrototypeOf(this,n):this.__proto__=n,this.name="ZodError",this.issues=t}get errors(){return this.issues}format(t){const n=t||function(o){return o.message},r={_errors:[]},s=o=>{for(const a of o.issues)if(a.code==="invalid_union")a.unionErrors.map(s);else if(a.code==="invalid_return_type")s(a.returnTypeError);else if(a.code==="invalid_arguments")s(a.argumentsError);else if(a.path.length===0)r._errors.push(n(a));else{let l=r,c=0;for(;cn.message){const n={},r=[];for(const s of this.issues)s.path.length>0?(n[s.path[0]]=n[s.path[0]]||[],n[s.path[0]].push(t(s))):r.push(t(s));return{formErrors:r,fieldErrors:n}}get formErrors(){return this.flatten()}}yr.create=e=>new yr(e);const nu=(e,t)=>{let n;switch(e.code){case re.invalid_type:e.received===be.undefined?n="Required":n=`Expected ${e.expected}, received ${e.received}`;break;case re.invalid_literal:n=`Invalid literal value, expected ${JSON.stringify(e.expected,ut.jsonStringifyReplacer)}`;break;case re.unrecognized_keys:n=`Unrecognized key(s) in object: ${ut.joinValues(e.keys,", ")}`;break;case re.invalid_union:n="Invalid input";break;case re.invalid_union_discriminator:n=`Invalid discriminator value. Expected ${ut.joinValues(e.options)}`;break;case re.invalid_enum_value:n=`Invalid enum value. Expected ${ut.joinValues(e.options)}, received '${e.received}'`;break;case re.invalid_arguments:n="Invalid function arguments";break;case re.invalid_return_type:n="Invalid function return type";break;case re.invalid_date:n="Invalid date";break;case re.invalid_string:typeof e.validation=="object"?"includes"in e.validation?(n=`Invalid input: must include "${e.validation.includes}"`,typeof e.validation.position=="number"&&(n=`${n} at one or more positions greater than or equal to ${e.validation.position}`)):"startsWith"in e.validation?n=`Invalid input: must start with "${e.validation.startsWith}"`:"endsWith"in e.validation?n=`Invalid input: must end with "${e.validation.endsWith}"`:ut.assertNever(e.validation):e.validation!=="regex"?n=`Invalid ${e.validation}`:n="Invalid";break;case re.too_small:e.type==="array"?n=`Array must contain ${e.exact?"exactly":e.inclusive?"at least":"more than"} ${e.minimum} element(s)`:e.type==="string"?n=`String must contain ${e.exact?"exactly":e.inclusive?"at least":"over"} ${e.minimum} character(s)`:e.type==="number"?n=`Number must be ${e.exact?"exactly equal to ":e.inclusive?"greater than or equal to ":"greater than "}${e.minimum}`:e.type==="date"?n=`Date must be ${e.exact?"exactly equal to ":e.inclusive?"greater than or equal to ":"greater than "}${new Date(Number(e.minimum))}`:n="Invalid input";break;case re.too_big:e.type==="array"?n=`Array must contain ${e.exact?"exactly":e.inclusive?"at most":"less than"} ${e.maximum} element(s)`:e.type==="string"?n=`String must contain ${e.exact?"exactly":e.inclusive?"at most":"under"} ${e.maximum} character(s)`:e.type==="number"?n=`Number must be ${e.exact?"exactly":e.inclusive?"less than or equal to":"less than"} ${e.maximum}`:e.type==="bigint"?n=`BigInt must be ${e.exact?"exactly":e.inclusive?"less than or equal to":"less than"} ${e.maximum}`:e.type==="date"?n=`Date must be ${e.exact?"exactly":e.inclusive?"smaller than or equal to":"smaller than"} ${new Date(Number(e.maximum))}`:n="Invalid input";break;case re.custom:n="Invalid input";break;case re.invalid_intersection_types:n="Intersection results could not be merged";break;case re.not_multiple_of:n=`Number must be a multiple of ${e.multipleOf}`;break;case re.not_finite:n="Number must be finite";break;default:n=t.defaultError,ut.assertNever(e)}return{message:n}};let hM=nu;function s6(e){hM=e}function mh(){return hM}const vh=e=>{const{data:t,path:n,errorMaps:r,issueData:s}=e,o=[...n,...s.path||[]],a={...s,path:o};if(s.message!==void 0)return{...s,path:o,message:s.message};let l="";const c=r.filter(i=>!!i).slice().reverse();for(const i of c)l=i(a,{data:t,defaultError:l}).message;return{...s,path:o,message:l}},o6=[];function ve(e,t){const n=mh(),r=vh({issueData:t,data:e.data,path:e.path,errorMaps:[e.common.contextualErrorMap,e.schemaErrorMap,n,n===nu?void 0:nu].filter(s=>!!s)});e.common.issues.push(r)}class Dn{constructor(){this.value="valid"}dirty(){this.value==="valid"&&(this.value="dirty")}abort(){this.value!=="aborted"&&(this.value="aborted")}static mergeArray(t,n){const r=[];for(const s of n){if(s.status==="aborted")return Be;s.status==="dirty"&&t.dirty(),r.push(s.value)}return{status:t.value,value:r}}static async mergeObjectAsync(t,n){const r=[];for(const s of n){const o=await s.key,a=await s.value;r.push({key:o,value:a})}return Dn.mergeObjectSync(t,r)}static mergeObjectSync(t,n){const r={};for(const s of n){const{key:o,value:a}=s;if(o.status==="aborted"||a.status==="aborted")return Be;o.status==="dirty"&&t.dirty(),a.status==="dirty"&&t.dirty(),o.value!=="__proto__"&&(typeof a.value<"u"||s.alwaysSet)&&(r[o.value]=a.value)}return{status:t.value,value:r}}}const Be=Object.freeze({status:"aborted"}),vl=e=>({status:"dirty",value:e}),Kn=e=>({status:"valid",value:e}),eb=e=>e.status==="aborted",tb=e=>e.status==="dirty",cd=e=>e.status==="valid",dd=e=>typeof Promise<"u"&&e instanceof Promise;function yh(e,t,n,r){if(typeof t=="function"?e!==t||!r:!t.has(e))throw new TypeError("Cannot read private member from an object whose class did not declare it");return t.get(e)}function gM(e,t,n,r,s){if(typeof t=="function"?e!==t||!s:!t.has(e))throw new TypeError("Cannot write private member to an object whose class did not declare it");return t.set(e,n),n}var je;(function(e){e.errToObj=t=>typeof t=="string"?{message:t}:t||{},e.toString=t=>typeof t=="string"?t:t==null?void 0:t.message})(je||(je={}));var fc,pc;class zs{constructor(t,n,r,s){this._cachedPath=[],this.parent=t,this.data=n,this._path=r,this._key=s}get path(){return this._cachedPath.length||(this._key instanceof Array?this._cachedPath.push(...this._path,...this._key):this._cachedPath.push(...this._path,this._key)),this._cachedPath}}const IC=(e,t)=>{if(cd(t))return{success:!0,data:t.value};if(!e.common.issues.length)throw new Error("Validation failed but no issues detected.");return{success:!1,get error(){if(this._error)return this._error;const n=new yr(e.common.issues);return this._error=n,this._error}}};function Ke(e){if(!e)return{};const{errorMap:t,invalid_type_error:n,required_error:r,description:s}=e;if(t&&(n||r))throw new Error(`Can't use "invalid_type_error" or "required_error" in conjunction with custom error map.`);return t?{errorMap:t,description:s}:{errorMap:(a,l)=>{var c,i;const{message:d}=e;return a.code==="invalid_enum_value"?{message:d??l.defaultError}:typeof l.data>"u"?{message:(c=d??r)!==null&&c!==void 0?c:l.defaultError}:a.code!=="invalid_type"?{message:l.defaultError}:{message:(i=d??n)!==null&&i!==void 0?i:l.defaultError}},description:s}}class Qe{constructor(t){this.spa=this.safeParseAsync,this._def=t,this.parse=this.parse.bind(this),this.safeParse=this.safeParse.bind(this),this.parseAsync=this.parseAsync.bind(this),this.safeParseAsync=this.safeParseAsync.bind(this),this.spa=this.spa.bind(this),this.refine=this.refine.bind(this),this.refinement=this.refinement.bind(this),this.superRefine=this.superRefine.bind(this),this.optional=this.optional.bind(this),this.nullable=this.nullable.bind(this),this.nullish=this.nullish.bind(this),this.array=this.array.bind(this),this.promise=this.promise.bind(this),this.or=this.or.bind(this),this.and=this.and.bind(this),this.transform=this.transform.bind(this),this.brand=this.brand.bind(this),this.default=this.default.bind(this),this.catch=this.catch.bind(this),this.describe=this.describe.bind(this),this.pipe=this.pipe.bind(this),this.readonly=this.readonly.bind(this),this.isNullable=this.isNullable.bind(this),this.isOptional=this.isOptional.bind(this)}get description(){return this._def.description}_getType(t){return Vo(t.data)}_getOrReturnCtx(t,n){return n||{common:t.parent.common,data:t.data,parsedType:Vo(t.data),schemaErrorMap:this._def.errorMap,path:t.path,parent:t.parent}}_processInputParams(t){return{status:new Dn,ctx:{common:t.parent.common,data:t.data,parsedType:Vo(t.data),schemaErrorMap:this._def.errorMap,path:t.path,parent:t.parent}}}_parseSync(t){const n=this._parse(t);if(dd(n))throw new Error("Synchronous parse encountered promise.");return n}_parseAsync(t){const n=this._parse(t);return Promise.resolve(n)}parse(t,n){const r=this.safeParse(t,n);if(r.success)return r.data;throw r.error}safeParse(t,n){var r;const s={common:{issues:[],async:(r=n==null?void 0:n.async)!==null&&r!==void 0?r:!1,contextualErrorMap:n==null?void 0:n.errorMap},path:(n==null?void 0:n.path)||[],schemaErrorMap:this._def.errorMap,parent:null,data:t,parsedType:Vo(t)},o=this._parseSync({data:t,path:s.path,parent:s});return IC(s,o)}async parseAsync(t,n){const r=await this.safeParseAsync(t,n);if(r.success)return r.data;throw r.error}async safeParseAsync(t,n){const r={common:{issues:[],contextualErrorMap:n==null?void 0:n.errorMap,async:!0},path:(n==null?void 0:n.path)||[],schemaErrorMap:this._def.errorMap,parent:null,data:t,parsedType:Vo(t)},s=this._parse({data:t,path:r.path,parent:r}),o=await(dd(s)?s:Promise.resolve(s));return IC(r,o)}refine(t,n){const r=s=>typeof n=="string"||typeof n>"u"?{message:n}:typeof n=="function"?n(s):n;return this._refinement((s,o)=>{const a=t(s),l=()=>o.addIssue({code:re.custom,...r(s)});return typeof Promise<"u"&&a instanceof Promise?a.then(c=>c?!0:(l(),!1)):a?!0:(l(),!1)})}refinement(t,n){return this._refinement((r,s)=>t(r)?!0:(s.addIssue(typeof n=="function"?n(r,s):n),!1))}_refinement(t){return new ds({schema:this,typeName:Fe.ZodEffects,effect:{type:"refinement",refinement:t}})}superRefine(t){return this._refinement(t)}optional(){return Ls.create(this,this._def)}nullable(){return xa.create(this,this._def)}nullish(){return this.nullable().optional()}array(){return as.create(this,this._def)}promise(){return su.create(this,this._def)}or(t){return gd.create([this,t],this._def)}and(t){return md.create(this,t,this._def)}transform(t){return new ds({...Ke(this._def),schema:this,typeName:Fe.ZodEffects,effect:{type:"transform",transform:t}})}default(t){const n=typeof t=="function"?t:()=>t;return new wd({...Ke(this._def),innerType:this,defaultValue:n,typeName:Fe.ZodDefault})}brand(){return new Sw({typeName:Fe.ZodBranded,type:this,...Ke(this._def)})}catch(t){const n=typeof t=="function"?t:()=>t;return new Sd({...Ke(this._def),innerType:this,catchValue:n,typeName:Fe.ZodCatch})}describe(t){const n=this.constructor;return new n({...this._def,description:t})}pipe(t){return Xd.create(this,t)}readonly(){return Cd.create(this)}isOptional(){return this.safeParse(void 0).success}isNullable(){return this.safeParse(null).success}}const a6=/^c[^\s-]{8,}$/i,i6=/^[0-9a-z]+$/,l6=/^[0-9A-HJKMNP-TV-Z]{26}$/,u6=/^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/i,c6=/^[a-z0-9_-]{21}$/i,d6=/^[-+]?P(?!$)(?:(?:[-+]?\d+Y)|(?:[-+]?\d+[.,]\d+Y$))?(?:(?:[-+]?\d+M)|(?:[-+]?\d+[.,]\d+M$))?(?:(?:[-+]?\d+W)|(?:[-+]?\d+[.,]\d+W$))?(?:(?:[-+]?\d+D)|(?:[-+]?\d+[.,]\d+D$))?(?:T(?=[\d+-])(?:(?:[-+]?\d+H)|(?:[-+]?\d+[.,]\d+H$))?(?:(?:[-+]?\d+M)|(?:[-+]?\d+[.,]\d+M$))?(?:[-+]?\d+(?:[.,]\d+)?S)?)??$/,f6=/^(?!\.)(?!.*\.\.)([A-Z0-9_'+\-\.]*)[A-Z0-9_+-]@([A-Z0-9][A-Z0-9\-]*\.)+[A-Z]{2,}$/i,p6="^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$";let ev;const h6=/^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/,g6=/^(([a-f0-9]{1,4}:){7}|::([a-f0-9]{1,4}:){0,6}|([a-f0-9]{1,4}:){1}:([a-f0-9]{1,4}:){0,5}|([a-f0-9]{1,4}:){2}:([a-f0-9]{1,4}:){0,4}|([a-f0-9]{1,4}:){3}:([a-f0-9]{1,4}:){0,3}|([a-f0-9]{1,4}:){4}:([a-f0-9]{1,4}:){0,2}|([a-f0-9]{1,4}:){5}:([a-f0-9]{1,4}:){0,1})([a-f0-9]{1,4}|(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2})))$/,m6=/^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/,mM="((\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-((0[13578]|1[02])-(0[1-9]|[12]\\d|3[01])|(0[469]|11)-(0[1-9]|[12]\\d|30)|(02)-(0[1-9]|1\\d|2[0-8])))",v6=new RegExp(`^${mM}$`);function vM(e){let t="([01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d";return e.precision?t=`${t}\\.\\d{${e.precision}}`:e.precision==null&&(t=`${t}(\\.\\d+)?`),t}function y6(e){return new RegExp(`^${vM(e)}$`)}function yM(e){let t=`${mM}T${vM(e)}`;const n=[];return n.push(e.local?"Z?":"Z"),e.offset&&n.push("([+-]\\d{2}:?\\d{2})"),t=`${t}(${n.join("|")})`,new RegExp(`^${t}$`)}function b6(e,t){return!!((t==="v4"||!t)&&h6.test(e)||(t==="v6"||!t)&&g6.test(e))}class es extends Qe{_parse(t){if(this._def.coerce&&(t.data=String(t.data)),this._getType(t)!==be.string){const o=this._getOrReturnCtx(t);return ve(o,{code:re.invalid_type,expected:be.string,received:o.parsedType}),Be}const r=new Dn;let s;for(const o of this._def.checks)if(o.kind==="min")t.data.lengtho.value&&(s=this._getOrReturnCtx(t,s),ve(s,{code:re.too_big,maximum:o.value,type:"string",inclusive:!0,exact:!1,message:o.message}),r.dirty());else if(o.kind==="length"){const a=t.data.length>o.value,l=t.data.lengtht.test(s),{validation:n,code:re.invalid_string,...je.errToObj(r)})}_addCheck(t){return new es({...this._def,checks:[...this._def.checks,t]})}email(t){return this._addCheck({kind:"email",...je.errToObj(t)})}url(t){return this._addCheck({kind:"url",...je.errToObj(t)})}emoji(t){return this._addCheck({kind:"emoji",...je.errToObj(t)})}uuid(t){return this._addCheck({kind:"uuid",...je.errToObj(t)})}nanoid(t){return this._addCheck({kind:"nanoid",...je.errToObj(t)})}cuid(t){return this._addCheck({kind:"cuid",...je.errToObj(t)})}cuid2(t){return this._addCheck({kind:"cuid2",...je.errToObj(t)})}ulid(t){return this._addCheck({kind:"ulid",...je.errToObj(t)})}base64(t){return this._addCheck({kind:"base64",...je.errToObj(t)})}ip(t){return this._addCheck({kind:"ip",...je.errToObj(t)})}datetime(t){var n,r;return typeof t=="string"?this._addCheck({kind:"datetime",precision:null,offset:!1,local:!1,message:t}):this._addCheck({kind:"datetime",precision:typeof(t==null?void 0:t.precision)>"u"?null:t==null?void 0:t.precision,offset:(n=t==null?void 0:t.offset)!==null&&n!==void 0?n:!1,local:(r=t==null?void 0:t.local)!==null&&r!==void 0?r:!1,...je.errToObj(t==null?void 0:t.message)})}date(t){return this._addCheck({kind:"date",message:t})}time(t){return typeof t=="string"?this._addCheck({kind:"time",precision:null,message:t}):this._addCheck({kind:"time",precision:typeof(t==null?void 0:t.precision)>"u"?null:t==null?void 0:t.precision,...je.errToObj(t==null?void 0:t.message)})}duration(t){return this._addCheck({kind:"duration",...je.errToObj(t)})}regex(t,n){return this._addCheck({kind:"regex",regex:t,...je.errToObj(n)})}includes(t,n){return this._addCheck({kind:"includes",value:t,position:n==null?void 0:n.position,...je.errToObj(n==null?void 0:n.message)})}startsWith(t,n){return this._addCheck({kind:"startsWith",value:t,...je.errToObj(n)})}endsWith(t,n){return this._addCheck({kind:"endsWith",value:t,...je.errToObj(n)})}min(t,n){return this._addCheck({kind:"min",value:t,...je.errToObj(n)})}max(t,n){return this._addCheck({kind:"max",value:t,...je.errToObj(n)})}length(t,n){return this._addCheck({kind:"length",value:t,...je.errToObj(n)})}nonempty(t){return this.min(1,je.errToObj(t))}trim(){return new es({...this._def,checks:[...this._def.checks,{kind:"trim"}]})}toLowerCase(){return new es({...this._def,checks:[...this._def.checks,{kind:"toLowerCase"}]})}toUpperCase(){return new es({...this._def,checks:[...this._def.checks,{kind:"toUpperCase"}]})}get isDatetime(){return!!this._def.checks.find(t=>t.kind==="datetime")}get isDate(){return!!this._def.checks.find(t=>t.kind==="date")}get isTime(){return!!this._def.checks.find(t=>t.kind==="time")}get isDuration(){return!!this._def.checks.find(t=>t.kind==="duration")}get isEmail(){return!!this._def.checks.find(t=>t.kind==="email")}get isURL(){return!!this._def.checks.find(t=>t.kind==="url")}get isEmoji(){return!!this._def.checks.find(t=>t.kind==="emoji")}get isUUID(){return!!this._def.checks.find(t=>t.kind==="uuid")}get isNANOID(){return!!this._def.checks.find(t=>t.kind==="nanoid")}get isCUID(){return!!this._def.checks.find(t=>t.kind==="cuid")}get isCUID2(){return!!this._def.checks.find(t=>t.kind==="cuid2")}get isULID(){return!!this._def.checks.find(t=>t.kind==="ulid")}get isIP(){return!!this._def.checks.find(t=>t.kind==="ip")}get isBase64(){return!!this._def.checks.find(t=>t.kind==="base64")}get minLength(){let t=null;for(const n of this._def.checks)n.kind==="min"&&(t===null||n.value>t)&&(t=n.value);return t}get maxLength(){let t=null;for(const n of this._def.checks)n.kind==="max"&&(t===null||n.value{var t;return new es({checks:[],typeName:Fe.ZodString,coerce:(t=e==null?void 0:e.coerce)!==null&&t!==void 0?t:!1,...Ke(e)})};function x6(e,t){const n=(e.toString().split(".")[1]||"").length,r=(t.toString().split(".")[1]||"").length,s=n>r?n:r,o=parseInt(e.toFixed(s).replace(".","")),a=parseInt(t.toFixed(s).replace(".",""));return o%a/Math.pow(10,s)}class va extends Qe{constructor(){super(...arguments),this.min=this.gte,this.max=this.lte,this.step=this.multipleOf}_parse(t){if(this._def.coerce&&(t.data=Number(t.data)),this._getType(t)!==be.number){const o=this._getOrReturnCtx(t);return ve(o,{code:re.invalid_type,expected:be.number,received:o.parsedType}),Be}let r;const s=new Dn;for(const o of this._def.checks)o.kind==="int"?ut.isInteger(t.data)||(r=this._getOrReturnCtx(t,r),ve(r,{code:re.invalid_type,expected:"integer",received:"float",message:o.message}),s.dirty()):o.kind==="min"?(o.inclusive?t.datao.value:t.data>=o.value)&&(r=this._getOrReturnCtx(t,r),ve(r,{code:re.too_big,maximum:o.value,type:"number",inclusive:o.inclusive,exact:!1,message:o.message}),s.dirty()):o.kind==="multipleOf"?x6(t.data,o.value)!==0&&(r=this._getOrReturnCtx(t,r),ve(r,{code:re.not_multiple_of,multipleOf:o.value,message:o.message}),s.dirty()):o.kind==="finite"?Number.isFinite(t.data)||(r=this._getOrReturnCtx(t,r),ve(r,{code:re.not_finite,message:o.message}),s.dirty()):ut.assertNever(o);return{status:s.value,value:t.data}}gte(t,n){return this.setLimit("min",t,!0,je.toString(n))}gt(t,n){return this.setLimit("min",t,!1,je.toString(n))}lte(t,n){return this.setLimit("max",t,!0,je.toString(n))}lt(t,n){return this.setLimit("max",t,!1,je.toString(n))}setLimit(t,n,r,s){return new va({...this._def,checks:[...this._def.checks,{kind:t,value:n,inclusive:r,message:je.toString(s)}]})}_addCheck(t){return new va({...this._def,checks:[...this._def.checks,t]})}int(t){return this._addCheck({kind:"int",message:je.toString(t)})}positive(t){return this._addCheck({kind:"min",value:0,inclusive:!1,message:je.toString(t)})}negative(t){return this._addCheck({kind:"max",value:0,inclusive:!1,message:je.toString(t)})}nonpositive(t){return this._addCheck({kind:"max",value:0,inclusive:!0,message:je.toString(t)})}nonnegative(t){return this._addCheck({kind:"min",value:0,inclusive:!0,message:je.toString(t)})}multipleOf(t,n){return this._addCheck({kind:"multipleOf",value:t,message:je.toString(n)})}finite(t){return this._addCheck({kind:"finite",message:je.toString(t)})}safe(t){return this._addCheck({kind:"min",inclusive:!0,value:Number.MIN_SAFE_INTEGER,message:je.toString(t)})._addCheck({kind:"max",inclusive:!0,value:Number.MAX_SAFE_INTEGER,message:je.toString(t)})}get minValue(){let t=null;for(const n of this._def.checks)n.kind==="min"&&(t===null||n.value>t)&&(t=n.value);return t}get maxValue(){let t=null;for(const n of this._def.checks)n.kind==="max"&&(t===null||n.valuet.kind==="int"||t.kind==="multipleOf"&&ut.isInteger(t.value))}get isFinite(){let t=null,n=null;for(const r of this._def.checks){if(r.kind==="finite"||r.kind==="int"||r.kind==="multipleOf")return!0;r.kind==="min"?(n===null||r.value>n)&&(n=r.value):r.kind==="max"&&(t===null||r.valuenew va({checks:[],typeName:Fe.ZodNumber,coerce:(e==null?void 0:e.coerce)||!1,...Ke(e)});class ya extends Qe{constructor(){super(...arguments),this.min=this.gte,this.max=this.lte}_parse(t){if(this._def.coerce&&(t.data=BigInt(t.data)),this._getType(t)!==be.bigint){const o=this._getOrReturnCtx(t);return ve(o,{code:re.invalid_type,expected:be.bigint,received:o.parsedType}),Be}let r;const s=new Dn;for(const o of this._def.checks)o.kind==="min"?(o.inclusive?t.datao.value:t.data>=o.value)&&(r=this._getOrReturnCtx(t,r),ve(r,{code:re.too_big,type:"bigint",maximum:o.value,inclusive:o.inclusive,message:o.message}),s.dirty()):o.kind==="multipleOf"?t.data%o.value!==BigInt(0)&&(r=this._getOrReturnCtx(t,r),ve(r,{code:re.not_multiple_of,multipleOf:o.value,message:o.message}),s.dirty()):ut.assertNever(o);return{status:s.value,value:t.data}}gte(t,n){return this.setLimit("min",t,!0,je.toString(n))}gt(t,n){return this.setLimit("min",t,!1,je.toString(n))}lte(t,n){return this.setLimit("max",t,!0,je.toString(n))}lt(t,n){return this.setLimit("max",t,!1,je.toString(n))}setLimit(t,n,r,s){return new ya({...this._def,checks:[...this._def.checks,{kind:t,value:n,inclusive:r,message:je.toString(s)}]})}_addCheck(t){return new ya({...this._def,checks:[...this._def.checks,t]})}positive(t){return this._addCheck({kind:"min",value:BigInt(0),inclusive:!1,message:je.toString(t)})}negative(t){return this._addCheck({kind:"max",value:BigInt(0),inclusive:!1,message:je.toString(t)})}nonpositive(t){return this._addCheck({kind:"max",value:BigInt(0),inclusive:!0,message:je.toString(t)})}nonnegative(t){return this._addCheck({kind:"min",value:BigInt(0),inclusive:!0,message:je.toString(t)})}multipleOf(t,n){return this._addCheck({kind:"multipleOf",value:t,message:je.toString(n)})}get minValue(){let t=null;for(const n of this._def.checks)n.kind==="min"&&(t===null||n.value>t)&&(t=n.value);return t}get maxValue(){let t=null;for(const n of this._def.checks)n.kind==="max"&&(t===null||n.value{var t;return new ya({checks:[],typeName:Fe.ZodBigInt,coerce:(t=e==null?void 0:e.coerce)!==null&&t!==void 0?t:!1,...Ke(e)})};class fd extends Qe{_parse(t){if(this._def.coerce&&(t.data=!!t.data),this._getType(t)!==be.boolean){const r=this._getOrReturnCtx(t);return ve(r,{code:re.invalid_type,expected:be.boolean,received:r.parsedType}),Be}return Kn(t.data)}}fd.create=e=>new fd({typeName:Fe.ZodBoolean,coerce:(e==null?void 0:e.coerce)||!1,...Ke(e)});class Ti extends Qe{_parse(t){if(this._def.coerce&&(t.data=new Date(t.data)),this._getType(t)!==be.date){const o=this._getOrReturnCtx(t);return ve(o,{code:re.invalid_type,expected:be.date,received:o.parsedType}),Be}if(isNaN(t.data.getTime())){const o=this._getOrReturnCtx(t);return ve(o,{code:re.invalid_date}),Be}const r=new Dn;let s;for(const o of this._def.checks)o.kind==="min"?t.data.getTime()o.value&&(s=this._getOrReturnCtx(t,s),ve(s,{code:re.too_big,message:o.message,inclusive:!0,exact:!1,maximum:o.value,type:"date"}),r.dirty()):ut.assertNever(o);return{status:r.value,value:new Date(t.data.getTime())}}_addCheck(t){return new Ti({...this._def,checks:[...this._def.checks,t]})}min(t,n){return this._addCheck({kind:"min",value:t.getTime(),message:je.toString(n)})}max(t,n){return this._addCheck({kind:"max",value:t.getTime(),message:je.toString(n)})}get minDate(){let t=null;for(const n of this._def.checks)n.kind==="min"&&(t===null||n.value>t)&&(t=n.value);return t!=null?new Date(t):null}get maxDate(){let t=null;for(const n of this._def.checks)n.kind==="max"&&(t===null||n.valuenew Ti({checks:[],coerce:(e==null?void 0:e.coerce)||!1,typeName:Fe.ZodDate,...Ke(e)});class bh extends Qe{_parse(t){if(this._getType(t)!==be.symbol){const r=this._getOrReturnCtx(t);return ve(r,{code:re.invalid_type,expected:be.symbol,received:r.parsedType}),Be}return Kn(t.data)}}bh.create=e=>new bh({typeName:Fe.ZodSymbol,...Ke(e)});class pd extends Qe{_parse(t){if(this._getType(t)!==be.undefined){const r=this._getOrReturnCtx(t);return ve(r,{code:re.invalid_type,expected:be.undefined,received:r.parsedType}),Be}return Kn(t.data)}}pd.create=e=>new pd({typeName:Fe.ZodUndefined,...Ke(e)});class hd extends Qe{_parse(t){if(this._getType(t)!==be.null){const r=this._getOrReturnCtx(t);return ve(r,{code:re.invalid_type,expected:be.null,received:r.parsedType}),Be}return Kn(t.data)}}hd.create=e=>new hd({typeName:Fe.ZodNull,...Ke(e)});class ru extends Qe{constructor(){super(...arguments),this._any=!0}_parse(t){return Kn(t.data)}}ru.create=e=>new ru({typeName:Fe.ZodAny,...Ke(e)});class fi extends Qe{constructor(){super(...arguments),this._unknown=!0}_parse(t){return Kn(t.data)}}fi.create=e=>new fi({typeName:Fe.ZodUnknown,...Ke(e)});class bo extends Qe{_parse(t){const n=this._getOrReturnCtx(t);return ve(n,{code:re.invalid_type,expected:be.never,received:n.parsedType}),Be}}bo.create=e=>new bo({typeName:Fe.ZodNever,...Ke(e)});class xh extends Qe{_parse(t){if(this._getType(t)!==be.undefined){const r=this._getOrReturnCtx(t);return ve(r,{code:re.invalid_type,expected:be.void,received:r.parsedType}),Be}return Kn(t.data)}}xh.create=e=>new xh({typeName:Fe.ZodVoid,...Ke(e)});class as extends Qe{_parse(t){const{ctx:n,status:r}=this._processInputParams(t),s=this._def;if(n.parsedType!==be.array)return ve(n,{code:re.invalid_type,expected:be.array,received:n.parsedType}),Be;if(s.exactLength!==null){const a=n.data.length>s.exactLength.value,l=n.data.lengths.maxLength.value&&(ve(n,{code:re.too_big,maximum:s.maxLength.value,type:"array",inclusive:!0,exact:!1,message:s.maxLength.message}),r.dirty()),n.common.async)return Promise.all([...n.data].map((a,l)=>s.type._parseAsync(new zs(n,a,n.path,l)))).then(a=>Dn.mergeArray(r,a));const o=[...n.data].map((a,l)=>s.type._parseSync(new zs(n,a,n.path,l)));return Dn.mergeArray(r,o)}get element(){return this._def.type}min(t,n){return new as({...this._def,minLength:{value:t,message:je.toString(n)}})}max(t,n){return new as({...this._def,maxLength:{value:t,message:je.toString(n)}})}length(t,n){return new as({...this._def,exactLength:{value:t,message:je.toString(n)}})}nonempty(t){return this.min(1,t)}}as.create=(e,t)=>new as({type:e,minLength:null,maxLength:null,exactLength:null,typeName:Fe.ZodArray,...Ke(t)});function tl(e){if(e instanceof Dt){const t={};for(const n in e.shape){const r=e.shape[n];t[n]=Ls.create(tl(r))}return new Dt({...e._def,shape:()=>t})}else return e instanceof as?new as({...e._def,type:tl(e.element)}):e instanceof Ls?Ls.create(tl(e.unwrap())):e instanceof xa?xa.create(tl(e.unwrap())):e instanceof Us?Us.create(e.items.map(t=>tl(t))):e}class Dt extends Qe{constructor(){super(...arguments),this._cached=null,this.nonstrict=this.passthrough,this.augment=this.extend}_getCached(){if(this._cached!==null)return this._cached;const t=this._def.shape(),n=ut.objectKeys(t);return this._cached={shape:t,keys:n}}_parse(t){if(this._getType(t)!==be.object){const i=this._getOrReturnCtx(t);return ve(i,{code:re.invalid_type,expected:be.object,received:i.parsedType}),Be}const{status:r,ctx:s}=this._processInputParams(t),{shape:o,keys:a}=this._getCached(),l=[];if(!(this._def.catchall instanceof bo&&this._def.unknownKeys==="strip"))for(const i in s.data)a.includes(i)||l.push(i);const c=[];for(const i of a){const d=o[i],p=s.data[i];c.push({key:{status:"valid",value:i},value:d._parse(new zs(s,p,s.path,i)),alwaysSet:i in s.data})}if(this._def.catchall instanceof bo){const i=this._def.unknownKeys;if(i==="passthrough")for(const d of l)c.push({key:{status:"valid",value:d},value:{status:"valid",value:s.data[d]}});else if(i==="strict")l.length>0&&(ve(s,{code:re.unrecognized_keys,keys:l}),r.dirty());else if(i!=="strip")throw new Error("Internal ZodObject error: invalid unknownKeys value.")}else{const i=this._def.catchall;for(const d of l){const p=s.data[d];c.push({key:{status:"valid",value:d},value:i._parse(new zs(s,p,s.path,d)),alwaysSet:d in s.data})}}return s.common.async?Promise.resolve().then(async()=>{const i=[];for(const d of c){const p=await d.key,f=await d.value;i.push({key:p,value:f,alwaysSet:d.alwaysSet})}return i}).then(i=>Dn.mergeObjectSync(r,i)):Dn.mergeObjectSync(r,c)}get shape(){return this._def.shape()}strict(t){return je.errToObj,new Dt({...this._def,unknownKeys:"strict",...t!==void 0?{errorMap:(n,r)=>{var s,o,a,l;const c=(a=(o=(s=this._def).errorMap)===null||o===void 0?void 0:o.call(s,n,r).message)!==null&&a!==void 0?a:r.defaultError;return n.code==="unrecognized_keys"?{message:(l=je.errToObj(t).message)!==null&&l!==void 0?l:c}:{message:c}}}:{}})}strip(){return new Dt({...this._def,unknownKeys:"strip"})}passthrough(){return new Dt({...this._def,unknownKeys:"passthrough"})}extend(t){return new Dt({...this._def,shape:()=>({...this._def.shape(),...t})})}merge(t){return new Dt({unknownKeys:t._def.unknownKeys,catchall:t._def.catchall,shape:()=>({...this._def.shape(),...t._def.shape()}),typeName:Fe.ZodObject})}setKey(t,n){return this.augment({[t]:n})}catchall(t){return new Dt({...this._def,catchall:t})}pick(t){const n={};return ut.objectKeys(t).forEach(r=>{t[r]&&this.shape[r]&&(n[r]=this.shape[r])}),new Dt({...this._def,shape:()=>n})}omit(t){const n={};return ut.objectKeys(this.shape).forEach(r=>{t[r]||(n[r]=this.shape[r])}),new Dt({...this._def,shape:()=>n})}deepPartial(){return tl(this)}partial(t){const n={};return ut.objectKeys(this.shape).forEach(r=>{const s=this.shape[r];t&&!t[r]?n[r]=s:n[r]=s.optional()}),new Dt({...this._def,shape:()=>n})}required(t){const n={};return ut.objectKeys(this.shape).forEach(r=>{if(t&&!t[r])n[r]=this.shape[r];else{let o=this.shape[r];for(;o instanceof Ls;)o=o._def.innerType;n[r]=o}}),new Dt({...this._def,shape:()=>n})}keyof(){return bM(ut.objectKeys(this.shape))}}Dt.create=(e,t)=>new Dt({shape:()=>e,unknownKeys:"strip",catchall:bo.create(),typeName:Fe.ZodObject,...Ke(t)});Dt.strictCreate=(e,t)=>new Dt({shape:()=>e,unknownKeys:"strict",catchall:bo.create(),typeName:Fe.ZodObject,...Ke(t)});Dt.lazycreate=(e,t)=>new Dt({shape:e,unknownKeys:"strip",catchall:bo.create(),typeName:Fe.ZodObject,...Ke(t)});class gd extends Qe{_parse(t){const{ctx:n}=this._processInputParams(t),r=this._def.options;function s(o){for(const l of o)if(l.result.status==="valid")return l.result;for(const l of o)if(l.result.status==="dirty")return n.common.issues.push(...l.ctx.common.issues),l.result;const a=o.map(l=>new yr(l.ctx.common.issues));return ve(n,{code:re.invalid_union,unionErrors:a}),Be}if(n.common.async)return Promise.all(r.map(async o=>{const a={...n,common:{...n.common,issues:[]},parent:null};return{result:await o._parseAsync({data:n.data,path:n.path,parent:a}),ctx:a}})).then(s);{let o;const a=[];for(const c of r){const i={...n,common:{...n.common,issues:[]},parent:null},d=c._parseSync({data:n.data,path:n.path,parent:i});if(d.status==="valid")return d;d.status==="dirty"&&!o&&(o={result:d,ctx:i}),i.common.issues.length&&a.push(i.common.issues)}if(o)return n.common.issues.push(...o.ctx.common.issues),o.result;const l=a.map(c=>new yr(c));return ve(n,{code:re.invalid_union,unionErrors:l}),Be}}get options(){return this._def.options}}gd.create=(e,t)=>new gd({options:e,typeName:Fe.ZodUnion,...Ke(t)});const Qs=e=>e instanceof yd?Qs(e.schema):e instanceof ds?Qs(e.innerType()):e instanceof bd?[e.value]:e instanceof ba?e.options:e instanceof xd?ut.objectValues(e.enum):e instanceof wd?Qs(e._def.innerType):e instanceof pd?[void 0]:e instanceof hd?[null]:e instanceof Ls?[void 0,...Qs(e.unwrap())]:e instanceof xa?[null,...Qs(e.unwrap())]:e instanceof Sw||e instanceof Cd?Qs(e.unwrap()):e instanceof Sd?Qs(e._def.innerType):[];class Pg extends Qe{_parse(t){const{ctx:n}=this._processInputParams(t);if(n.parsedType!==be.object)return ve(n,{code:re.invalid_type,expected:be.object,received:n.parsedType}),Be;const r=this.discriminator,s=n.data[r],o=this.optionsMap.get(s);return o?n.common.async?o._parseAsync({data:n.data,path:n.path,parent:n}):o._parseSync({data:n.data,path:n.path,parent:n}):(ve(n,{code:re.invalid_union_discriminator,options:Array.from(this.optionsMap.keys()),path:[r]}),Be)}get discriminator(){return this._def.discriminator}get options(){return this._def.options}get optionsMap(){return this._def.optionsMap}static create(t,n,r){const s=new Map;for(const o of n){const a=Qs(o.shape[t]);if(!a.length)throw new Error(`A discriminator value for key \`${t}\` could not be extracted from all schema options`);for(const l of a){if(s.has(l))throw new Error(`Discriminator property ${String(t)} has duplicate value ${String(l)}`);s.set(l,o)}}return new Pg({typeName:Fe.ZodDiscriminatedUnion,discriminator:t,options:n,optionsMap:s,...Ke(r)})}}function nb(e,t){const n=Vo(e),r=Vo(t);if(e===t)return{valid:!0,data:e};if(n===be.object&&r===be.object){const s=ut.objectKeys(t),o=ut.objectKeys(e).filter(l=>s.indexOf(l)!==-1),a={...e,...t};for(const l of o){const c=nb(e[l],t[l]);if(!c.valid)return{valid:!1};a[l]=c.data}return{valid:!0,data:a}}else if(n===be.array&&r===be.array){if(e.length!==t.length)return{valid:!1};const s=[];for(let o=0;o{if(eb(o)||eb(a))return Be;const l=nb(o.value,a.value);return l.valid?((tb(o)||tb(a))&&n.dirty(),{status:n.value,value:l.data}):(ve(r,{code:re.invalid_intersection_types}),Be)};return r.common.async?Promise.all([this._def.left._parseAsync({data:r.data,path:r.path,parent:r}),this._def.right._parseAsync({data:r.data,path:r.path,parent:r})]).then(([o,a])=>s(o,a)):s(this._def.left._parseSync({data:r.data,path:r.path,parent:r}),this._def.right._parseSync({data:r.data,path:r.path,parent:r}))}}md.create=(e,t,n)=>new md({left:e,right:t,typeName:Fe.ZodIntersection,...Ke(n)});class Us extends Qe{_parse(t){const{status:n,ctx:r}=this._processInputParams(t);if(r.parsedType!==be.array)return ve(r,{code:re.invalid_type,expected:be.array,received:r.parsedType}),Be;if(r.data.lengththis._def.items.length&&(ve(r,{code:re.too_big,maximum:this._def.items.length,inclusive:!0,exact:!1,type:"array"}),n.dirty());const o=[...r.data].map((a,l)=>{const c=this._def.items[l]||this._def.rest;return c?c._parse(new zs(r,a,r.path,l)):null}).filter(a=>!!a);return r.common.async?Promise.all(o).then(a=>Dn.mergeArray(n,a)):Dn.mergeArray(n,o)}get items(){return this._def.items}rest(t){return new Us({...this._def,rest:t})}}Us.create=(e,t)=>{if(!Array.isArray(e))throw new Error("You must pass an array of schemas to z.tuple([ ... ])");return new Us({items:e,typeName:Fe.ZodTuple,rest:null,...Ke(t)})};class vd extends Qe{get keySchema(){return this._def.keyType}get valueSchema(){return this._def.valueType}_parse(t){const{status:n,ctx:r}=this._processInputParams(t);if(r.parsedType!==be.object)return ve(r,{code:re.invalid_type,expected:be.object,received:r.parsedType}),Be;const s=[],o=this._def.keyType,a=this._def.valueType;for(const l in r.data)s.push({key:o._parse(new zs(r,l,r.path,l)),value:a._parse(new zs(r,r.data[l],r.path,l)),alwaysSet:l in r.data});return r.common.async?Dn.mergeObjectAsync(n,s):Dn.mergeObjectSync(n,s)}get element(){return this._def.valueType}static create(t,n,r){return n instanceof Qe?new vd({keyType:t,valueType:n,typeName:Fe.ZodRecord,...Ke(r)}):new vd({keyType:es.create(),valueType:t,typeName:Fe.ZodRecord,...Ke(n)})}}class wh extends Qe{get keySchema(){return this._def.keyType}get valueSchema(){return this._def.valueType}_parse(t){const{status:n,ctx:r}=this._processInputParams(t);if(r.parsedType!==be.map)return ve(r,{code:re.invalid_type,expected:be.map,received:r.parsedType}),Be;const s=this._def.keyType,o=this._def.valueType,a=[...r.data.entries()].map(([l,c],i)=>({key:s._parse(new zs(r,l,r.path,[i,"key"])),value:o._parse(new zs(r,c,r.path,[i,"value"]))}));if(r.common.async){const l=new Map;return Promise.resolve().then(async()=>{for(const c of a){const i=await c.key,d=await c.value;if(i.status==="aborted"||d.status==="aborted")return Be;(i.status==="dirty"||d.status==="dirty")&&n.dirty(),l.set(i.value,d.value)}return{status:n.value,value:l}})}else{const l=new Map;for(const c of a){const i=c.key,d=c.value;if(i.status==="aborted"||d.status==="aborted")return Be;(i.status==="dirty"||d.status==="dirty")&&n.dirty(),l.set(i.value,d.value)}return{status:n.value,value:l}}}}wh.create=(e,t,n)=>new wh({valueType:t,keyType:e,typeName:Fe.ZodMap,...Ke(n)});class ki extends Qe{_parse(t){const{status:n,ctx:r}=this._processInputParams(t);if(r.parsedType!==be.set)return ve(r,{code:re.invalid_type,expected:be.set,received:r.parsedType}),Be;const s=this._def;s.minSize!==null&&r.data.sizes.maxSize.value&&(ve(r,{code:re.too_big,maximum:s.maxSize.value,type:"set",inclusive:!0,exact:!1,message:s.maxSize.message}),n.dirty());const o=this._def.valueType;function a(c){const i=new Set;for(const d of c){if(d.status==="aborted")return Be;d.status==="dirty"&&n.dirty(),i.add(d.value)}return{status:n.value,value:i}}const l=[...r.data.values()].map((c,i)=>o._parse(new zs(r,c,r.path,i)));return r.common.async?Promise.all(l).then(c=>a(c)):a(l)}min(t,n){return new ki({...this._def,minSize:{value:t,message:je.toString(n)}})}max(t,n){return new ki({...this._def,maxSize:{value:t,message:je.toString(n)}})}size(t,n){return this.min(t,n).max(t,n)}nonempty(t){return this.min(1,t)}}ki.create=(e,t)=>new ki({valueType:e,minSize:null,maxSize:null,typeName:Fe.ZodSet,...Ke(t)});class jl extends Qe{constructor(){super(...arguments),this.validate=this.implement}_parse(t){const{ctx:n}=this._processInputParams(t);if(n.parsedType!==be.function)return ve(n,{code:re.invalid_type,expected:be.function,received:n.parsedType}),Be;function r(l,c){return vh({data:l,path:n.path,errorMaps:[n.common.contextualErrorMap,n.schemaErrorMap,mh(),nu].filter(i=>!!i),issueData:{code:re.invalid_arguments,argumentsError:c}})}function s(l,c){return vh({data:l,path:n.path,errorMaps:[n.common.contextualErrorMap,n.schemaErrorMap,mh(),nu].filter(i=>!!i),issueData:{code:re.invalid_return_type,returnTypeError:c}})}const o={errorMap:n.common.contextualErrorMap},a=n.data;if(this._def.returns instanceof su){const l=this;return Kn(async function(...c){const i=new yr([]),d=await l._def.args.parseAsync(c,o).catch(h=>{throw i.addIssue(r(c,h)),i}),p=await Reflect.apply(a,this,d);return await l._def.returns._def.type.parseAsync(p,o).catch(h=>{throw i.addIssue(s(p,h)),i})})}else{const l=this;return Kn(function(...c){const i=l._def.args.safeParse(c,o);if(!i.success)throw new yr([r(c,i.error)]);const d=Reflect.apply(a,this,i.data),p=l._def.returns.safeParse(d,o);if(!p.success)throw new yr([s(d,p.error)]);return p.data})}}parameters(){return this._def.args}returnType(){return this._def.returns}args(...t){return new jl({...this._def,args:Us.create(t).rest(fi.create())})}returns(t){return new jl({...this._def,returns:t})}implement(t){return this.parse(t)}strictImplement(t){return this.parse(t)}static create(t,n,r){return new jl({args:t||Us.create([]).rest(fi.create()),returns:n||fi.create(),typeName:Fe.ZodFunction,...Ke(r)})}}class yd extends Qe{get schema(){return this._def.getter()}_parse(t){const{ctx:n}=this._processInputParams(t);return this._def.getter()._parse({data:n.data,path:n.path,parent:n})}}yd.create=(e,t)=>new yd({getter:e,typeName:Fe.ZodLazy,...Ke(t)});class bd extends Qe{_parse(t){if(t.data!==this._def.value){const n=this._getOrReturnCtx(t);return ve(n,{received:n.data,code:re.invalid_literal,expected:this._def.value}),Be}return{status:"valid",value:t.data}}get value(){return this._def.value}}bd.create=(e,t)=>new bd({value:e,typeName:Fe.ZodLiteral,...Ke(t)});function bM(e,t){return new ba({values:e,typeName:Fe.ZodEnum,...Ke(t)})}class ba extends Qe{constructor(){super(...arguments),fc.set(this,void 0)}_parse(t){if(typeof t.data!="string"){const n=this._getOrReturnCtx(t),r=this._def.values;return ve(n,{expected:ut.joinValues(r),received:n.parsedType,code:re.invalid_type}),Be}if(yh(this,fc)||gM(this,fc,new Set(this._def.values)),!yh(this,fc).has(t.data)){const n=this._getOrReturnCtx(t),r=this._def.values;return ve(n,{received:n.data,code:re.invalid_enum_value,options:r}),Be}return Kn(t.data)}get options(){return this._def.values}get enum(){const t={};for(const n of this._def.values)t[n]=n;return t}get Values(){const t={};for(const n of this._def.values)t[n]=n;return t}get Enum(){const t={};for(const n of this._def.values)t[n]=n;return t}extract(t,n=this._def){return ba.create(t,{...this._def,...n})}exclude(t,n=this._def){return ba.create(this.options.filter(r=>!t.includes(r)),{...this._def,...n})}}fc=new WeakMap;ba.create=bM;class xd extends Qe{constructor(){super(...arguments),pc.set(this,void 0)}_parse(t){const n=ut.getValidEnumValues(this._def.values),r=this._getOrReturnCtx(t);if(r.parsedType!==be.string&&r.parsedType!==be.number){const s=ut.objectValues(n);return ve(r,{expected:ut.joinValues(s),received:r.parsedType,code:re.invalid_type}),Be}if(yh(this,pc)||gM(this,pc,new Set(ut.getValidEnumValues(this._def.values))),!yh(this,pc).has(t.data)){const s=ut.objectValues(n);return ve(r,{received:r.data,code:re.invalid_enum_value,options:s}),Be}return Kn(t.data)}get enum(){return this._def.values}}pc=new WeakMap;xd.create=(e,t)=>new xd({values:e,typeName:Fe.ZodNativeEnum,...Ke(t)});class su extends Qe{unwrap(){return this._def.type}_parse(t){const{ctx:n}=this._processInputParams(t);if(n.parsedType!==be.promise&&n.common.async===!1)return ve(n,{code:re.invalid_type,expected:be.promise,received:n.parsedType}),Be;const r=n.parsedType===be.promise?n.data:Promise.resolve(n.data);return Kn(r.then(s=>this._def.type.parseAsync(s,{path:n.path,errorMap:n.common.contextualErrorMap})))}}su.create=(e,t)=>new su({type:e,typeName:Fe.ZodPromise,...Ke(t)});class ds extends Qe{innerType(){return this._def.schema}sourceType(){return this._def.schema._def.typeName===Fe.ZodEffects?this._def.schema.sourceType():this._def.schema}_parse(t){const{status:n,ctx:r}=this._processInputParams(t),s=this._def.effect||null,o={addIssue:a=>{ve(r,a),a.fatal?n.abort():n.dirty()},get path(){return r.path}};if(o.addIssue=o.addIssue.bind(o),s.type==="preprocess"){const a=s.transform(r.data,o);if(r.common.async)return Promise.resolve(a).then(async l=>{if(n.value==="aborted")return Be;const c=await this._def.schema._parseAsync({data:l,path:r.path,parent:r});return c.status==="aborted"?Be:c.status==="dirty"||n.value==="dirty"?vl(c.value):c});{if(n.value==="aborted")return Be;const l=this._def.schema._parseSync({data:a,path:r.path,parent:r});return l.status==="aborted"?Be:l.status==="dirty"||n.value==="dirty"?vl(l.value):l}}if(s.type==="refinement"){const a=l=>{const c=s.refinement(l,o);if(r.common.async)return Promise.resolve(c);if(c instanceof Promise)throw new Error("Async refinement encountered during synchronous parse operation. Use .parseAsync instead.");return l};if(r.common.async===!1){const l=this._def.schema._parseSync({data:r.data,path:r.path,parent:r});return l.status==="aborted"?Be:(l.status==="dirty"&&n.dirty(),a(l.value),{status:n.value,value:l.value})}else return this._def.schema._parseAsync({data:r.data,path:r.path,parent:r}).then(l=>l.status==="aborted"?Be:(l.status==="dirty"&&n.dirty(),a(l.value).then(()=>({status:n.value,value:l.value}))))}if(s.type==="transform")if(r.common.async===!1){const a=this._def.schema._parseSync({data:r.data,path:r.path,parent:r});if(!cd(a))return a;const l=s.transform(a.value,o);if(l instanceof Promise)throw new Error("Asynchronous transform encountered during synchronous parse operation. Use .parseAsync instead.");return{status:n.value,value:l}}else return this._def.schema._parseAsync({data:r.data,path:r.path,parent:r}).then(a=>cd(a)?Promise.resolve(s.transform(a.value,o)).then(l=>({status:n.value,value:l})):a);ut.assertNever(s)}}ds.create=(e,t,n)=>new ds({schema:e,typeName:Fe.ZodEffects,effect:t,...Ke(n)});ds.createWithPreprocess=(e,t,n)=>new ds({schema:t,effect:{type:"preprocess",transform:e},typeName:Fe.ZodEffects,...Ke(n)});class Ls extends Qe{_parse(t){return this._getType(t)===be.undefined?Kn(void 0):this._def.innerType._parse(t)}unwrap(){return this._def.innerType}}Ls.create=(e,t)=>new Ls({innerType:e,typeName:Fe.ZodOptional,...Ke(t)});class xa extends Qe{_parse(t){return this._getType(t)===be.null?Kn(null):this._def.innerType._parse(t)}unwrap(){return this._def.innerType}}xa.create=(e,t)=>new xa({innerType:e,typeName:Fe.ZodNullable,...Ke(t)});class wd extends Qe{_parse(t){const{ctx:n}=this._processInputParams(t);let r=n.data;return n.parsedType===be.undefined&&(r=this._def.defaultValue()),this._def.innerType._parse({data:r,path:n.path,parent:n})}removeDefault(){return this._def.innerType}}wd.create=(e,t)=>new wd({innerType:e,typeName:Fe.ZodDefault,defaultValue:typeof t.default=="function"?t.default:()=>t.default,...Ke(t)});class Sd extends Qe{_parse(t){const{ctx:n}=this._processInputParams(t),r={...n,common:{...n.common,issues:[]}},s=this._def.innerType._parse({data:r.data,path:r.path,parent:{...r}});return dd(s)?s.then(o=>({status:"valid",value:o.status==="valid"?o.value:this._def.catchValue({get error(){return new yr(r.common.issues)},input:r.data})})):{status:"valid",value:s.status==="valid"?s.value:this._def.catchValue({get error(){return new yr(r.common.issues)},input:r.data})}}removeCatch(){return this._def.innerType}}Sd.create=(e,t)=>new Sd({innerType:e,typeName:Fe.ZodCatch,catchValue:typeof t.catch=="function"?t.catch:()=>t.catch,...Ke(t)});class Sh extends Qe{_parse(t){if(this._getType(t)!==be.nan){const r=this._getOrReturnCtx(t);return ve(r,{code:re.invalid_type,expected:be.nan,received:r.parsedType}),Be}return{status:"valid",value:t.data}}}Sh.create=e=>new Sh({typeName:Fe.ZodNaN,...Ke(e)});const w6=Symbol("zod_brand");class Sw extends Qe{_parse(t){const{ctx:n}=this._processInputParams(t),r=n.data;return this._def.type._parse({data:r,path:n.path,parent:n})}unwrap(){return this._def.type}}class Xd extends Qe{_parse(t){const{status:n,ctx:r}=this._processInputParams(t);if(r.common.async)return(async()=>{const o=await this._def.in._parseAsync({data:r.data,path:r.path,parent:r});return o.status==="aborted"?Be:o.status==="dirty"?(n.dirty(),vl(o.value)):this._def.out._parseAsync({data:o.value,path:r.path,parent:r})})();{const s=this._def.in._parseSync({data:r.data,path:r.path,parent:r});return s.status==="aborted"?Be:s.status==="dirty"?(n.dirty(),{status:"dirty",value:s.value}):this._def.out._parseSync({data:s.value,path:r.path,parent:r})}}static create(t,n){return new Xd({in:t,out:n,typeName:Fe.ZodPipeline})}}class Cd extends Qe{_parse(t){const n=this._def.innerType._parse(t),r=s=>(cd(s)&&(s.value=Object.freeze(s.value)),s);return dd(n)?n.then(s=>r(s)):r(n)}unwrap(){return this._def.innerType}}Cd.create=(e,t)=>new Cd({innerType:e,typeName:Fe.ZodReadonly,...Ke(t)});function xM(e,t={},n){return e?ru.create().superRefine((r,s)=>{var o,a;if(!e(r)){const l=typeof t=="function"?t(r):typeof t=="string"?{message:t}:t,c=(a=(o=l.fatal)!==null&&o!==void 0?o:n)!==null&&a!==void 0?a:!0,i=typeof l=="string"?{message:l}:l;s.addIssue({code:"custom",...i,fatal:c})}}):ru.create()}const S6={object:Dt.lazycreate};var Fe;(function(e){e.ZodString="ZodString",e.ZodNumber="ZodNumber",e.ZodNaN="ZodNaN",e.ZodBigInt="ZodBigInt",e.ZodBoolean="ZodBoolean",e.ZodDate="ZodDate",e.ZodSymbol="ZodSymbol",e.ZodUndefined="ZodUndefined",e.ZodNull="ZodNull",e.ZodAny="ZodAny",e.ZodUnknown="ZodUnknown",e.ZodNever="ZodNever",e.ZodVoid="ZodVoid",e.ZodArray="ZodArray",e.ZodObject="ZodObject",e.ZodUnion="ZodUnion",e.ZodDiscriminatedUnion="ZodDiscriminatedUnion",e.ZodIntersection="ZodIntersection",e.ZodTuple="ZodTuple",e.ZodRecord="ZodRecord",e.ZodMap="ZodMap",e.ZodSet="ZodSet",e.ZodFunction="ZodFunction",e.ZodLazy="ZodLazy",e.ZodLiteral="ZodLiteral",e.ZodEnum="ZodEnum",e.ZodEffects="ZodEffects",e.ZodNativeEnum="ZodNativeEnum",e.ZodOptional="ZodOptional",e.ZodNullable="ZodNullable",e.ZodDefault="ZodDefault",e.ZodCatch="ZodCatch",e.ZodPromise="ZodPromise",e.ZodBranded="ZodBranded",e.ZodPipeline="ZodPipeline",e.ZodReadonly="ZodReadonly"})(Fe||(Fe={}));const C6=(e,t={message:`Input not instance of ${e.name}`})=>xM(n=>n instanceof e,t),wM=es.create,SM=va.create,E6=Sh.create,T6=ya.create,CM=fd.create,k6=Ti.create,_6=bh.create,j6=pd.create,R6=hd.create,P6=ru.create,M6=fi.create,O6=bo.create,N6=xh.create,I6=as.create,D6=Dt.create,A6=Dt.strictCreate,F6=gd.create,L6=Pg.create,$6=md.create,B6=Us.create,z6=vd.create,U6=wh.create,V6=ki.create,H6=jl.create,K6=yd.create,q6=bd.create,W6=ba.create,G6=xd.create,J6=su.create,DC=ds.create,Q6=Ls.create,Z6=xa.create,Y6=ds.createWithPreprocess,X6=Xd.create,e8=()=>wM().optional(),t8=()=>SM().optional(),n8=()=>CM().optional(),r8={string:e=>es.create({...e,coerce:!0}),number:e=>va.create({...e,coerce:!0}),boolean:e=>fd.create({...e,coerce:!0}),bigint:e=>ya.create({...e,coerce:!0}),date:e=>Ti.create({...e,coerce:!0})},s8=Be;var _=Object.freeze({__proto__:null,defaultErrorMap:nu,setErrorMap:s6,getErrorMap:mh,makeIssue:vh,EMPTY_PATH:o6,addIssueToContext:ve,ParseStatus:Dn,INVALID:Be,DIRTY:vl,OK:Kn,isAborted:eb,isDirty:tb,isValid:cd,isAsync:dd,get util(){return ut},get objectUtil(){return Xy},ZodParsedType:be,getParsedType:Vo,ZodType:Qe,datetimeRegex:yM,ZodString:es,ZodNumber:va,ZodBigInt:ya,ZodBoolean:fd,ZodDate:Ti,ZodSymbol:bh,ZodUndefined:pd,ZodNull:hd,ZodAny:ru,ZodUnknown:fi,ZodNever:bo,ZodVoid:xh,ZodArray:as,ZodObject:Dt,ZodUnion:gd,ZodDiscriminatedUnion:Pg,ZodIntersection:md,ZodTuple:Us,ZodRecord:vd,ZodMap:wh,ZodSet:ki,ZodFunction:jl,ZodLazy:yd,ZodLiteral:bd,ZodEnum:ba,ZodNativeEnum:xd,ZodPromise:su,ZodEffects:ds,ZodTransformer:ds,ZodOptional:Ls,ZodNullable:xa,ZodDefault:wd,ZodCatch:Sd,ZodNaN:Sh,BRAND:w6,ZodBranded:Sw,ZodPipeline:Xd,ZodReadonly:Cd,custom:xM,Schema:Qe,ZodSchema:Qe,late:S6,get ZodFirstPartyTypeKind(){return Fe},coerce:r8,any:P6,array:I6,bigint:T6,boolean:CM,date:k6,discriminatedUnion:L6,effect:DC,enum:W6,function:H6,instanceof:C6,intersection:$6,lazy:K6,literal:q6,map:U6,nan:E6,nativeEnum:G6,never:O6,null:R6,nullable:Z6,number:SM,object:D6,oboolean:n8,onumber:t8,optional:Q6,ostring:e8,pipeline:X6,preprocess:Y6,promise:J6,record:z6,set:V6,strictObject:A6,string:wM,symbol:_6,transformer:DC,tuple:B6,undefined:j6,union:F6,unknown:M6,void:N6,NEVER:s8,ZodIssueCode:re,quotelessJson:r6,ZodError:yr}),EM=v.createContext({dragDropManager:void 0}),Dr;(function(e){e.SOURCE="SOURCE",e.TARGET="TARGET"})(Dr||(Dr={}));function Ve(e,t){for(var n=arguments.length,r=new Array(n>2?n-2:0),s=2;s-1})}var u8={type:Cw,payload:{clientOffset:null,sourceClientOffset:null}};function c8(e){return function(){var n=arguments.length>0&&arguments[0]!==void 0?arguments[0]:[],r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{publishSource:!0},s=r.publishSource,o=s===void 0?!0:s,a=r.clientOffset,l=r.getSourceClientOffset,c=e.getMonitor(),i=e.getRegistry();e.dispatch(AC(a)),d8(n,c,i);var d=h8(n,c);if(d===null){e.dispatch(u8);return}var p=null;if(a){if(!l)throw new Error("getSourceClientOffset must be defined");f8(l),p=l(d)}e.dispatch(AC(a,p));var f=i.getSource(d),h=f.beginDrag(c,d);if(h!=null){p8(h),i.pinSource(d);var g=i.getSourceType(d);return{type:Mg,payload:{itemType:g,item:h,sourceId:d,clientOffset:a||null,sourceClientOffset:p||null,isSourcePublic:!!o}}}}}function d8(e,t,n){Ve(!t.isDragging(),"Cannot call beginDrag while dragging."),e.forEach(function(r){Ve(n.getSource(r),"Expected sourceIds to be registered.")})}function f8(e){Ve(typeof e=="function","When clientOffset is provided, getSourceClientOffset must be a function.")}function p8(e){Ve(TM(e),"Item must be an object.")}function h8(e,t){for(var n=null,r=e.length-1;r>=0;r--)if(t.canDragSource(e[r])){n=e[r];break}return n}function g8(e){return function(){var n=e.getMonitor();if(n.isDragging())return{type:Ew}}}function rb(e,t){return t===null?e===null:Array.isArray(e)?e.some(function(n){return n===t}):e===t}function m8(e){return function(n){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},s=r.clientOffset;v8(n);var o=n.slice(0),a=e.getMonitor(),l=e.getRegistry();y8(o,a,l);var c=a.getItemType();return b8(o,l,c),x8(o,a,l),{type:Og,payload:{targetIds:o,clientOffset:s||null}}}}function v8(e){Ve(Array.isArray(e),"Expected targetIds to be an array.")}function y8(e,t,n){Ve(t.isDragging(),"Cannot call hover while not dragging."),Ve(!t.didDrop(),"Cannot call hover after drop.");for(var r=0;r=0;r--){var s=e[r],o=t.getTargetType(s);rb(o,n)||e.splice(r,1)}}function x8(e,t,n){e.forEach(function(r){var s=n.getTarget(r);s.hover(t,r)})}function FC(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter(function(s){return Object.getOwnPropertyDescriptor(e,s).enumerable})),n.push.apply(n,r)}return n}function LC(e){for(var t=1;t0&&arguments[0]!==void 0?arguments[0]:{},r=e.getMonitor(),s=e.getRegistry();C8(r);var o=k8(r);o.forEach(function(a,l){var c=E8(a,l,s,r),i={type:Ng,payload:{dropResult:LC(LC({},n),c)}};e.dispatch(i)})}}function C8(e){Ve(e.isDragging(),"Cannot call drop while not dragging."),Ve(!e.didDrop(),"Cannot call drop twice during one drag operation.")}function E8(e,t,n,r){var s=n.getTarget(e),o=s?s.drop(r,e):void 0;return T8(o),typeof o>"u"&&(o=t===0?{}:r.getDropResult()),o}function T8(e){Ve(typeof e>"u"||TM(e),"Drop result must either be an object or undefined.")}function k8(e){var t=e.getTargetIds().filter(e.canDropOnTarget,e);return t.reverse(),t}function _8(e){return function(){var n=e.getMonitor(),r=e.getRegistry();j8(n);var s=n.getSourceId();if(s!=null){var o=r.getSource(s,!0);o.endDrag(n,s),r.unpinSource()}return{type:Ig}}}function j8(e){Ve(e.isDragging(),"Cannot call endDrag while not dragging.")}function R8(e){return{beginDrag:c8(e),publishDragSource:g8(e),hover:m8(e),drop:S8(e),endDrag:_8(e)}}function P8(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function M8(e,t){for(var n=0;n0;r.backend&&(s&&!r.isSetUp?(r.backend.setup(),r.isSetUp=!0):!s&&r.isSetUp&&(r.backend.teardown(),r.isSetUp=!1))}),this.store=t,this.monitor=n,t.subscribe(this.handleRefCountChange)}return O8(e,[{key:"receiveBackend",value:function(n){this.backend=n}},{key:"getMonitor",value:function(){return this.monitor}},{key:"getBackend",value:function(){return this.backend}},{key:"getRegistry",value:function(){return this.monitor.registry}},{key:"getActions",value:function(){var n=this,r=this.store.dispatch;function s(a){return function(){for(var l=arguments.length,c=new Array(l),i=0;i"u"&&(n=t,t=void 0),typeof n<"u"){if(typeof n!="function")throw new Error(_r(1));return n(kM)(e,t)}if(typeof e!="function")throw new Error(_r(2));var s=e,o=t,a=[],l=a,c=!1;function i(){l===a&&(l=a.slice())}function d(){if(c)throw new Error(_r(3));return o}function p(m){if(typeof m!="function")throw new Error(_r(4));if(c)throw new Error(_r(5));var x=!0;return i(),l.push(m),function(){if(x){if(c)throw new Error(_r(6));x=!1,i();var y=l.indexOf(m);l.splice(y,1),a=null}}}function f(m){if(!I8(m))throw new Error(_r(7));if(typeof m.type>"u")throw new Error(_r(8));if(c)throw new Error(_r(9));try{c=!0,o=s(o,m)}finally{c=!1}for(var x=a=l,b=0;b2&&arguments[2]!==void 0?arguments[2]:D8;if(e.length!==t.length)return!1;for(var r=0;r0&&arguments[0]!==void 0?arguments[0]:VC,t=arguments.length>1?arguments[1]:void 0,n=t.payload;switch(t.type){case Cw:case Mg:return{initialSourceClientOffset:n.sourceClientOffset,initialClientOffset:n.clientOffset,clientOffset:n.clientOffset};case Og:return A8(e.clientOffset,n.clientOffset)?e:UC(UC({},e),{},{clientOffset:n.clientOffset});case Ig:case Ng:return VC;default:return e}}var Tw="dnd-core/ADD_SOURCE",kw="dnd-core/ADD_TARGET",_w="dnd-core/REMOVE_SOURCE",Dg="dnd-core/REMOVE_TARGET";function B8(e){return{type:Tw,payload:{sourceId:e}}}function z8(e){return{type:kw,payload:{targetId:e}}}function U8(e){return{type:_w,payload:{sourceId:e}}}function V8(e){return{type:Dg,payload:{targetId:e}}}function HC(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter(function(s){return Object.getOwnPropertyDescriptor(e,s).enumerable})),n.push.apply(n,r)}return n}function jr(e){for(var t=1;t0&&arguments[0]!==void 0?arguments[0]:K8,t=arguments.length>1?arguments[1]:void 0,n=t.payload;switch(t.type){case Mg:return jr(jr({},e),{},{itemType:n.itemType,item:n.item,sourceId:n.sourceId,isSourcePublic:n.isSourcePublic,dropResult:null,didDrop:!1});case Ew:return jr(jr({},e),{},{isSourcePublic:!0});case Og:return jr(jr({},e),{},{targetIds:n.targetIds});case Dg:return e.targetIds.indexOf(n.targetId)===-1?e:jr(jr({},e),{},{targetIds:a8(e.targetIds,n.targetId)});case Ng:return jr(jr({},e),{},{dropResult:n.dropResult,didDrop:!0,targetIds:[]});case Ig:return jr(jr({},e),{},{itemType:null,item:null,sourceId:null,dropResult:null,didDrop:!1,isSourcePublic:null,targetIds:[]});default:return e}}function W8(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:0,t=arguments.length>1?arguments[1]:void 0;switch(t.type){case Tw:case kw:return e+1;case _w:case Dg:return e-1;default:return e}}var Ch=[],jw=[];Ch.__IS_NONE__=!0;jw.__IS_ALL__=!0;function G8(e,t){if(e===Ch)return!1;if(e===jw||typeof t>"u")return!0;var n=l8(t,e);return n.length>0}function J8(){var e=arguments.length>1?arguments[1]:void 0;switch(e.type){case Og:break;case Tw:case kw:case Dg:case _w:return Ch;case Mg:case Ew:case Ig:case Ng:default:return jw}var t=e.payload,n=t.targetIds,r=n===void 0?[]:n,s=t.prevTargetIds,o=s===void 0?[]:s,a=i8(r,o),l=a.length>0||!F8(r,o);if(!l)return Ch;var c=o[o.length-1],i=r[r.length-1];return c!==i&&(c&&a.push(c),i&&a.push(i)),a}function Q8(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:0;return e+1}function KC(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter(function(s){return Object.getOwnPropertyDescriptor(e,s).enumerable})),n.push.apply(n,r)}return n}function qC(e){for(var t=1;t0&&arguments[0]!==void 0?arguments[0]:{},t=arguments.length>1?arguments[1]:void 0;return{dirtyHandlerIds:J8(e.dirtyHandlerIds,{type:t.type,payload:qC(qC({},t.payload),{},{prevTargetIds:o8(e,"dragOperation.targetIds",[])})}),dragOffset:$8(e.dragOffset,t),refCount:W8(e.refCount,t),dragOperation:q8(e.dragOperation,t),stateId:Q8(e.stateId)}}function X8(e,t){return{x:e.x+t.x,y:e.y+t.y}}function _M(e,t){return{x:e.x-t.x,y:e.y-t.y}}function eH(e){var t=e.clientOffset,n=e.initialClientOffset,r=e.initialSourceClientOffset;return!t||!n||!r?null:_M(X8(t,r),n)}function tH(e){var t=e.clientOffset,n=e.initialClientOffset;return!t||!n?null:_M(t,n)}function nH(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function rH(e,t){for(var n=0;n1&&arguments[1]!==void 0?arguments[1]:{handlerIds:void 0},o=s.handlerIds;Ve(typeof n=="function","listener must be a function."),Ve(typeof o>"u"||Array.isArray(o),"handlerIds, when specified, must be an array of strings.");var a=this.store.getState().stateId,l=function(){var i=r.store.getState(),d=i.stateId;try{var p=d===a||d===a+1&&!G8(i.dirtyHandlerIds,o);p||n()}finally{a=d}};return this.store.subscribe(l)}},{key:"subscribeToOffsetChange",value:function(n){var r=this;Ve(typeof n=="function","listener must be a function.");var s=this.store.getState().dragOffset,o=function(){var l=r.store.getState().dragOffset;l!==s&&(s=l,n())};return this.store.subscribe(o)}},{key:"canDragSource",value:function(n){if(!n)return!1;var r=this.registry.getSource(n);return Ve(r,"Expected to find a valid source. sourceId=".concat(n)),this.isDragging()?!1:r.canDrag(this,n)}},{key:"canDropOnTarget",value:function(n){if(!n)return!1;var r=this.registry.getTarget(n);if(Ve(r,"Expected to find a valid target. targetId=".concat(n)),!this.isDragging()||this.didDrop())return!1;var s=this.registry.getTargetType(n),o=this.getItemType();return rb(s,o)&&r.canDrop(this,n)}},{key:"isDragging",value:function(){return!!this.getItemType()}},{key:"isDraggingSource",value:function(n){if(!n)return!1;var r=this.registry.getSource(n,!0);if(Ve(r,"Expected to find a valid source. sourceId=".concat(n)),!this.isDragging()||!this.isSourcePublic())return!1;var s=this.registry.getSourceType(n),o=this.getItemType();return s!==o?!1:r.isDragging(this,n)}},{key:"isOverTarget",value:function(n){var r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{shallow:!1};if(!n)return!1;var s=r.shallow;if(!this.isDragging())return!1;var o=this.registry.getTargetType(n),a=this.getItemType();if(a&&!rb(o,a))return!1;var l=this.getTargetIds();if(!l.length)return!1;var c=l.indexOf(n);return s?c===l.length-1:c>-1}},{key:"getItemType",value:function(){return this.store.getState().dragOperation.itemType}},{key:"getItem",value:function(){return this.store.getState().dragOperation.item}},{key:"getSourceId",value:function(){return this.store.getState().dragOperation.sourceId}},{key:"getTargetIds",value:function(){return this.store.getState().dragOperation.targetIds}},{key:"getDropResult",value:function(){return this.store.getState().dragOperation.dropResult}},{key:"didDrop",value:function(){return this.store.getState().dragOperation.didDrop}},{key:"isSourcePublic",value:function(){return!!this.store.getState().dragOperation.isSourcePublic}},{key:"getInitialClientOffset",value:function(){return this.store.getState().dragOffset.initialClientOffset}},{key:"getInitialSourceClientOffset",value:function(){return this.store.getState().dragOffset.initialSourceClientOffset}},{key:"getClientOffset",value:function(){return this.store.getState().dragOffset.clientOffset}},{key:"getSourceClientOffset",value:function(){return eH(this.store.getState().dragOffset)}},{key:"getDifferenceFromInitialOffset",value:function(){return tH(this.store.getState().dragOffset)}}]),e}(),aH=0;function iH(){return aH++}function bp(e){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?bp=function(n){return typeof n}:bp=function(n){return n&&typeof Symbol=="function"&&n.constructor===Symbol&&n!==Symbol.prototype?"symbol":typeof n},bp(e)}function lH(e){Ve(typeof e.canDrag=="function","Expected canDrag to be a function."),Ve(typeof e.beginDrag=="function","Expected beginDrag to be a function."),Ve(typeof e.endDrag=="function","Expected endDrag to be a function.")}function uH(e){Ve(typeof e.canDrop=="function","Expected canDrop to be a function."),Ve(typeof e.hover=="function","Expected hover to be a function."),Ve(typeof e.drop=="function","Expected beginDrag to be a function.")}function sb(e,t){if(t&&Array.isArray(e)){e.forEach(function(n){return sb(n,!1)});return}Ve(typeof e=="string"||bp(e)==="symbol",t?"Type can only be a string, a symbol, or an array of either.":"Type can only be a string or a symbol.")}const GC=typeof global<"u"?global:self,jM=GC.MutationObserver||GC.WebKitMutationObserver;function RM(e){return function(){const n=setTimeout(s,0),r=setInterval(s,50);function s(){clearTimeout(n),clearInterval(r),e()}}}function cH(e){let t=1;const n=new jM(e),r=document.createTextNode("");return n.observe(r,{characterData:!0}),function(){t=-t,r.data=t}}const dH=typeof jM=="function"?cH:RM;class fH{enqueueTask(t){const{queue:n,requestFlush:r}=this;n.length||(r(),this.flushing=!0),n[n.length]=t}constructor(){this.queue=[],this.pendingErrors=[],this.flushing=!1,this.index=0,this.capacity=1024,this.flush=()=>{const{queue:t}=this;for(;this.indexthis.capacity){for(let r=0,s=t.length-this.index;r{this.pendingErrors.push(t),this.requestErrorThrow()},this.requestFlush=dH(this.flush),this.requestErrorThrow=RM(()=>{if(this.pendingErrors.length)throw this.pendingErrors.shift()})}}class pH{call(){try{this.task&&this.task()}catch(t){this.onError(t)}finally{this.task=null,this.release(this)}}constructor(t,n){this.onError=t,this.release=n,this.task=null}}class hH{create(t){const n=this.freeTasks,r=n.length?n.pop():new pH(this.onError,s=>n[n.length]=s);return r.task=t,r}constructor(t){this.onError=t,this.freeTasks=[]}}const PM=new fH,gH=new hH(PM.registerPendingError);function mH(e){PM.enqueueTask(gH.create(e))}function vH(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function yH(e,t){for(var n=0;ne.length)&&(t=e.length);for(var n=0,r=new Array(t);n1&&arguments[1]!==void 0?arguments[1]:!1;Ve(this.isSourceId(n),"Expected a valid source ID.");var s=r&&n===this.pinnedSourceId,o=s?this.pinnedSource:this.dragSources.get(n);return o}},{key:"getTarget",value:function(n){return Ve(this.isTargetId(n),"Expected a valid target ID."),this.dropTargets.get(n)}},{key:"getSourceType",value:function(n){return Ve(this.isSourceId(n),"Expected a valid source ID."),this.types.get(n)}},{key:"getTargetType",value:function(n){return Ve(this.isTargetId(n),"Expected a valid target ID."),this.types.get(n)}},{key:"isSourceId",value:function(n){var r=QC(n);return r===Dr.SOURCE}},{key:"isTargetId",value:function(n){var r=QC(n);return r===Dr.TARGET}},{key:"removeSource",value:function(n){var r=this;Ve(this.getSource(n),"Expected an existing source."),this.store.dispatch(U8(n)),mH(function(){r.dragSources.delete(n),r.types.delete(n)})}},{key:"removeTarget",value:function(n){Ve(this.getTarget(n),"Expected an existing target."),this.store.dispatch(V8(n)),this.dropTargets.delete(n),this.types.delete(n)}},{key:"pinSource",value:function(n){var r=this.getSource(n);Ve(r,"Expected an existing source."),this.pinnedSourceId=n,this.pinnedSource=r}},{key:"unpinSource",value:function(){Ve(this.pinnedSource,"No source is pinned at the time."),this.pinnedSourceId=null,this.pinnedSource=null}},{key:"addHandler",value:function(n,r,s){var o=TH(n);return this.types.set(o,r),n===Dr.SOURCE?this.dragSources.set(o,s):n===Dr.TARGET&&this.dropTargets.set(o,s),o}}]),e}();function _H(e){var t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:void 0,n=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{},r=arguments.length>3&&arguments[3]!==void 0?arguments[3]:!1,s=jH(r),o=new oH(s,new kH(s)),a=new N8(s,o),l=e(a,t,n);return a.receiveBackend(l),a}function jH(e){var t=typeof window<"u"&&window.__REDUX_DEVTOOLS_EXTENSION__;return kM(Y8,e&&t&&t({name:"dnd-core",instanceId:"dnd-core"}))}var RH=["children"];function PH(e,t){return IH(e)||NH(e,t)||OH(e,t)||MH()}function MH(){throw new TypeError(`Invalid attempt to destructure non-iterable instance. +In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function OH(e,t){if(e){if(typeof e=="string")return YC(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);if(n==="Object"&&e.constructor&&(n=e.constructor.name),n==="Map"||n==="Set")return Array.from(e);if(n==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return YC(e,t)}}function YC(e,t){(t==null||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n=0)&&Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}function AH(e,t){if(e==null)return{};var n={},r=Object.keys(e),s,o;for(o=0;o=0)&&(n[s]=e[s]);return n}var XC=0,xp=Symbol.for("__REACT_DND_CONTEXT_INSTANCE__"),FH=v.memo(function(t){var n=t.children,r=DH(t,RH),s=LH(r),o=PH(s,2),a=o[0],l=o[1];return v.useEffect(function(){if(l){var c=MM();return++XC,function(){--XC===0&&(c[xp]=null)}}},[]),u.jsx(EM.Provider,Object.assign({value:a},{children:n}),void 0)});function LH(e){if("manager"in e){var t={dragDropManager:e.manager};return[t,!1]}var n=$H(e.backend,e.context,e.options,e.debugMode),r=!e.context;return[n,r]}function $H(e){var t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:MM(),n=arguments.length>2?arguments[2]:void 0,r=arguments.length>3?arguments[3]:void 0,s=t;return s[xp]||(s[xp]={dragDropManager:_H(e,t,n,r)}),s[xp]}function MM(){return typeof global<"u"?global:window}function BH(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function zH(e,t){for(var n=0;n, or turn it into a ")+"drag source or a drop target itself.")}}function JH(e){return function(){var t=arguments.length>0&&arguments[0]!==void 0?arguments[0]:null,n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:null;if(!v.isValidElement(t)){var r=t;return e(r,n),r}var s=t;GH(s);var o=n?function(a){return e(a,n)}:e;return QH(s,o)}}function OM(e){var t={};return Object.keys(e).forEach(function(n){var r=e[n];if(n.endsWith("Ref"))t[n]=e[n];else{var s=JH(r);t[n]=function(){return s}}}),t}function n1(e,t){typeof e=="function"?e(t):e.current=t}function QH(e,t){var n=e.ref;return Ve(typeof n!="string","Cannot connect React DnD to an element with an existing string ref. Please convert it to use a callback ref instead, or wrap it into a or
. Read more: https://reactjs.org/docs/refs-and-the-dom.html#callback-refs"),n?v.cloneElement(e,{ref:function(s){n1(n,s),n1(t,s)}}):v.cloneElement(e,{ref:t})}function wp(e){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?wp=function(n){return typeof n}:wp=function(n){return n&&typeof Symbol=="function"&&n.constructor===Symbol&&n!==Symbol.prototype?"symbol":typeof n},wp(e)}function ob(e){return e!==null&&wp(e)==="object"&&Object.prototype.hasOwnProperty.call(e,"current")}function ab(e,t,n,r){var s=void 0;if(s!==void 0)return!!s;if(e===t)return!0;if(typeof e!="object"||!e||typeof t!="object"||!t)return!1;var o=Object.keys(e),a=Object.keys(t);if(o.length!==a.length)return!1;for(var l=Object.prototype.hasOwnProperty.bind(t),c=0;ce.length)&&(t=e.length);for(var n=0,r=new Array(t);ne.length)&&(t=e.length);for(var n=0,r=new Array(t);ne.length)&&(t=e.length);for(var n=0,r=new Array(t);ne.length)&&(t=e.length);for(var n=0,r=new Array(t);ne.length)&&(t=e.length);for(var n=0,r=new Array(t);n0}},{key:"leave",value:function(n){var r=this.entered.length;return this.entered=oK(this.entered.filter(this.isNodeInDocument),n),r>0&&this.entered.length===0}},{key:"reset",value:function(){this.entered=[]}}]),e}(),dK=DM(function(){return/firefox/i.test(navigator.userAgent)}),AM=DM(function(){return!!window.safari});function fK(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function pK(e,t){for(var n=0;nn)d=p-1;else return s[p]}c=Math.max(0,d);var h=n-r[c],g=h*h;return s[c]+o[c]*h+a[c]*g+l[c]*h*g}}]),e}(),gK=1;function FM(e){var t=e.nodeType===gK?e:e.parentElement;if(!t)return null;var n=t.getBoundingClientRect(),r=n.top,s=n.left;return{x:s,y:r}}function Bf(e){return{x:e.clientX,y:e.clientY}}function mK(e){var t;return e.nodeName==="IMG"&&(dK()||!((t=document.documentElement)!==null&&t!==void 0&&t.contains(e)))}function vK(e,t,n,r){var s=e?t.width:n,o=e?t.height:r;return AM()&&e&&(o/=window.devicePixelRatio,s/=window.devicePixelRatio),{dragPreviewWidth:s,dragPreviewHeight:o}}function yK(e,t,n,r,s){var o=mK(t),a=o?e:t,l=FM(a),c={x:n.x-l.x,y:n.y-l.y},i=e.offsetWidth,d=e.offsetHeight,p=r.anchorX,f=r.anchorY,h=vK(o,t,i,d),g=h.dragPreviewWidth,m=h.dragPreviewHeight,x=function(){var k=new u1([0,.5,1],[c.y,c.y/d*m,c.y+m-d]),T=k.interpolate(f);return AM()&&o&&(T+=(window.devicePixelRatio-1)*m),T},b=function(){var k=new u1([0,.5,1],[c.x,c.x/i*g,c.x+g-i]);return k.interpolate(p)},y=s.offsetX,w=s.offsetY,S=y===0||y,E=w===0||w;return{x:S?y:b(),y:E?w:x()}}var LM="__NATIVE_FILE__",$M="__NATIVE_URL__",BM="__NATIVE_TEXT__",zM="__NATIVE_HTML__";const c1=Object.freeze(Object.defineProperty({__proto__:null,FILE:LM,HTML:zM,TEXT:BM,URL:$M},Symbol.toStringTag,{value:"Module"}));function av(e,t,n){var r=t.reduce(function(s,o){return s||e.getData(o)},"");return r??n}var Qi;function zf(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var lb=(Qi={},zf(Qi,LM,{exposeProperties:{files:function(t){return Array.prototype.slice.call(t.files)},items:function(t){return t.items},dataTransfer:function(t){return t}},matchesTypes:["Files"]}),zf(Qi,zM,{exposeProperties:{html:function(t,n){return av(t,n,"")},dataTransfer:function(t){return t}},matchesTypes:["Html","text/html"]}),zf(Qi,$M,{exposeProperties:{urls:function(t,n){return av(t,n,"").split(` +`)},dataTransfer:function(t){return t}},matchesTypes:["Url","text/uri-list"]}),zf(Qi,BM,{exposeProperties:{text:function(t,n){return av(t,n,"")},dataTransfer:function(t){return t}},matchesTypes:["Text","text/plain"]}),Qi);function bK(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function xK(e,t){for(var n=0;n-1})})[0]||null}function EK(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function TK(e,t){for(var n=0;n0&&s.actions.hover(a,{clientOffset:Bf(o)});var l=a.some(function(c){return s.monitor.canDropOnTarget(c)});l&&(o.preventDefault(),o.dataTransfer&&(o.dataTransfer.dropEffect=s.getCurrentDropEffect()))}}),st(this,"handleTopDragOverCapture",function(){s.dragOverTargetIds=[]}),st(this,"handleTopDragOver",function(o){var a=s.dragOverTargetIds;if(s.dragOverTargetIds=[],!s.monitor.isDragging()){o.preventDefault(),o.dataTransfer&&(o.dataTransfer.dropEffect="none");return}s.altKeyPressed=o.altKey,s.lastClientOffset=Bf(o),s.hoverRafId===null&&typeof requestAnimationFrame<"u"&&(s.hoverRafId=requestAnimationFrame(function(){s.monitor.isDragging()&&s.actions.hover(a||[],{clientOffset:s.lastClientOffset}),s.hoverRafId=null}));var l=(a||[]).some(function(c){return s.monitor.canDropOnTarget(c)});l?(o.preventDefault(),o.dataTransfer&&(o.dataTransfer.dropEffect=s.getCurrentDropEffect())):s.isDraggingNativeItem()?o.preventDefault():(o.preventDefault(),o.dataTransfer&&(o.dataTransfer.dropEffect="none"))}),st(this,"handleTopDragLeaveCapture",function(o){s.isDraggingNativeItem()&&o.preventDefault();var a=s.enterLeaveCounter.leave(o.target);a&&s.isDraggingNativeItem()&&setTimeout(function(){return s.endDragNativeItem()},0)}),st(this,"handleTopDropCapture",function(o){if(s.dropTargetIds=[],s.isDraggingNativeItem()){var a;o.preventDefault(),(a=s.currentNativeSource)===null||a===void 0||a.loadDataTransfer(o.dataTransfer)}else iv(o.dataTransfer)&&o.preventDefault();s.enterLeaveCounter.reset()}),st(this,"handleTopDrop",function(o){var a=s.dropTargetIds;s.dropTargetIds=[],s.actions.hover(a,{clientOffset:Bf(o)}),s.actions.drop({dropEffect:s.getCurrentDropEffect()}),s.isDraggingNativeItem()?s.endDragNativeItem():s.monitor.isDragging()&&s.actions.endDrag()}),st(this,"handleSelectStart",function(o){var a=o.target;typeof a.dragDrop=="function"&&(a.tagName==="INPUT"||a.tagName==="SELECT"||a.tagName==="TEXTAREA"||a.isContentEditable||(o.preventDefault(),a.dragDrop()))}),this.options=new _K(n,r),this.actions=t.getActions(),this.monitor=t.getMonitor(),this.registry=t.getRegistry(),this.enterLeaveCounter=new cK(this.isNodeInDocument)}return PK(e,[{key:"profile",value:function(){var n,r;return{sourcePreviewNodes:this.sourcePreviewNodes.size,sourcePreviewNodeOptions:this.sourcePreviewNodeOptions.size,sourceNodeOptions:this.sourceNodeOptions.size,sourceNodes:this.sourceNodes.size,dragStartSourceIds:((n=this.dragStartSourceIds)===null||n===void 0?void 0:n.length)||0,dropTargetIds:this.dropTargetIds.length,dragEnterTargetIds:this.dragEnterTargetIds.length,dragOverTargetIds:((r=this.dragOverTargetIds)===null||r===void 0?void 0:r.length)||0}}},{key:"window",get:function(){return this.options.window}},{key:"document",get:function(){return this.options.document}},{key:"rootElement",get:function(){return this.options.rootElement}},{key:"setup",value:function(){var n=this.rootElement;if(n!==void 0){if(n.__isReactDndBackendSetUp)throw new Error("Cannot have two HTML5 backends at the same time.");n.__isReactDndBackendSetUp=!0,this.addEventListeners(n)}}},{key:"teardown",value:function(){var n=this.rootElement;if(n!==void 0&&(n.__isReactDndBackendSetUp=!1,this.removeEventListeners(this.rootElement),this.clearCurrentDragSourceNode(),this.asyncEndDragFrameId)){var r;(r=this.window)===null||r===void 0||r.cancelAnimationFrame(this.asyncEndDragFrameId)}}},{key:"connectDragPreview",value:function(n,r,s){var o=this;return this.sourcePreviewNodeOptions.set(n,s),this.sourcePreviewNodes.set(n,r),function(){o.sourcePreviewNodes.delete(n),o.sourcePreviewNodeOptions.delete(n)}}},{key:"connectDragSource",value:function(n,r,s){var o=this;this.sourceNodes.set(n,r),this.sourceNodeOptions.set(n,s);var a=function(i){return o.handleDragStart(i,n)},l=function(i){return o.handleSelectStart(i)};return r.setAttribute("draggable","true"),r.addEventListener("dragstart",a),r.addEventListener("selectstart",l),function(){o.sourceNodes.delete(n),o.sourceNodeOptions.delete(n),r.removeEventListener("dragstart",a),r.removeEventListener("selectstart",l),r.setAttribute("draggable","false")}}},{key:"connectDropTarget",value:function(n,r){var s=this,o=function(i){return s.handleDragEnter(i,n)},a=function(i){return s.handleDragOver(i,n)},l=function(i){return s.handleDrop(i,n)};return r.addEventListener("dragenter",o),r.addEventListener("dragover",a),r.addEventListener("drop",l),function(){r.removeEventListener("dragenter",o),r.removeEventListener("dragover",a),r.removeEventListener("drop",l)}}},{key:"addEventListeners",value:function(n){n.addEventListener&&(n.addEventListener("dragstart",this.handleTopDragStart),n.addEventListener("dragstart",this.handleTopDragStartCapture,!0),n.addEventListener("dragend",this.handleTopDragEndCapture,!0),n.addEventListener("dragenter",this.handleTopDragEnter),n.addEventListener("dragenter",this.handleTopDragEnterCapture,!0),n.addEventListener("dragleave",this.handleTopDragLeaveCapture,!0),n.addEventListener("dragover",this.handleTopDragOver),n.addEventListener("dragover",this.handleTopDragOverCapture,!0),n.addEventListener("drop",this.handleTopDrop),n.addEventListener("drop",this.handleTopDropCapture,!0))}},{key:"removeEventListeners",value:function(n){n.removeEventListener&&(n.removeEventListener("dragstart",this.handleTopDragStart),n.removeEventListener("dragstart",this.handleTopDragStartCapture,!0),n.removeEventListener("dragend",this.handleTopDragEndCapture,!0),n.removeEventListener("dragenter",this.handleTopDragEnter),n.removeEventListener("dragenter",this.handleTopDragEnterCapture,!0),n.removeEventListener("dragleave",this.handleTopDragLeaveCapture,!0),n.removeEventListener("dragover",this.handleTopDragOver),n.removeEventListener("dragover",this.handleTopDragOverCapture,!0),n.removeEventListener("drop",this.handleTopDrop),n.removeEventListener("drop",this.handleTopDropCapture,!0))}},{key:"getCurrentSourceNodeOptions",value:function(){var n=this.monitor.getSourceId(),r=this.sourceNodeOptions.get(n);return p1({dropEffect:this.altKeyPressed?"copy":"move"},r||{})}},{key:"getCurrentDropEffect",value:function(){return this.isDraggingNativeItem()?"copy":this.getCurrentSourceNodeOptions().dropEffect}},{key:"getCurrentSourcePreviewNodeOptions",value:function(){var n=this.monitor.getSourceId(),r=this.sourcePreviewNodeOptions.get(n);return p1({anchorX:.5,anchorY:.5,captureDraggingState:!1},r||{})}},{key:"isDraggingNativeItem",value:function(){var n=this.monitor.getItemType();return Object.keys(c1).some(function(r){return c1[r]===n})}},{key:"beginDragNativeItem",value:function(n,r){this.clearCurrentDragSourceNode(),this.currentNativeSource=CK(n,r),this.currentNativeHandle=this.registry.addSource(n,this.currentNativeSource),this.actions.beginDrag([this.currentNativeHandle])}},{key:"setCurrentDragSourceNode",value:function(n){var r=this;this.clearCurrentDragSourceNode(),this.currentDragSourceNode=n;var s=1e3;this.mouseMoveTimeoutTimer=setTimeout(function(){var o;return(o=r.rootElement)===null||o===void 0?void 0:o.addEventListener("mousemove",r.endDragIfSourceWasRemovedFromDOM,!0)},s)}},{key:"clearCurrentDragSourceNode",value:function(){if(this.currentDragSourceNode){if(this.currentDragSourceNode=null,this.rootElement){var n;(n=this.window)===null||n===void 0||n.clearTimeout(this.mouseMoveTimeoutTimer||void 0),this.rootElement.removeEventListener("mousemove",this.endDragIfSourceWasRemovedFromDOM,!0)}return this.mouseMoveTimeoutTimer=null,!0}return!1}},{key:"handleDragStart",value:function(n,r){n.defaultPrevented||(this.dragStartSourceIds||(this.dragStartSourceIds=[]),this.dragStartSourceIds.unshift(r))}},{key:"handleDragEnter",value:function(n,r){this.dragEnterTargetIds.unshift(r)}},{key:"handleDragOver",value:function(n,r){this.dragOverTargetIds===null&&(this.dragOverTargetIds=[]),this.dragOverTargetIds.unshift(r)}},{key:"handleDrop",value:function(n,r){this.dropTargetIds.unshift(r)}}]),e}(),OK=function(t,n,r){return new MK(t,n,r)},NK=Object.create,UM=Object.defineProperty,IK=Object.getOwnPropertyDescriptor,VM=Object.getOwnPropertyNames,DK=Object.getPrototypeOf,AK=Object.prototype.hasOwnProperty,FK=(e,t)=>function(){return t||(0,e[VM(e)[0]])((t={exports:{}}).exports,t),t.exports},LK=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of VM(t))!AK.call(e,s)&&s!==n&&UM(e,s,{get:()=>t[s],enumerable:!(r=IK(t,s))||r.enumerable});return e},HM=(e,t,n)=>(n=e!=null?NK(DK(e)):{},LK(UM(n,"default",{value:e,enumerable:!0}),e)),KM=FK({"node_modules/classnames/index.js"(e,t){(function(){var n={}.hasOwnProperty;function r(){for(var s=[],o=0;o-1}var Wq=qq,Gq=9007199254740991,Jq=/^(?:0|[1-9]\d*)$/;function Qq(e,t){var n=typeof e;return t=t??Gq,!!t&&(n=="number"||n!="symbol"&&Jq.test(e))&&e>-1&&e%1==0&&e-1&&e%1==0&&e<=Xq}var YM=eW;function tW(e){return e!=null&&YM(e.length)&&!QM(e)}var nW=tW,rW=Object.prototype;function sW(e){var t=e&&e.constructor,n=typeof t=="function"&&t.prototype||rW;return e===n}var oW=sW;function aW(e,t){for(var n=-1,r=Array(e);++n-1}var FG=AG;function LG(e,t){var n=this.__data__,r=Ag(n,e);return r<0?(++this.size,n.push([e,t])):n[r][1]=t,this}var $G=LG;function Eu(e){var t=-1,n=e==null?0:e.length;for(this.clear();++tl))return!1;var i=o.get(e),d=o.get(t);if(i&&d)return i==t&&d==e;var p=-1,f=!0,h=n&q9?new oO:void 0;for(o.set(e,t),o.set(t,e);++p":">",'"':""","'":"'"},TJ=s9(EJ),kJ=TJ,uO=/[&<>"']/g,_J=RegExp(uO.source);function jJ(e){return e=sO(e),e&&_J.test(e)?e.replace(uO,kJ):e}var RJ=jJ,cO=/[\\^$.*+?()[\]{}|]/g,PJ=RegExp(cO.source);function MJ(e){return e=sO(e),e&&PJ.test(e)?e.replace(cO,"\\$&"):e}var OJ=MJ;function NJ(e,t){return wJ(e,t)}var IJ=NJ,DJ=1/0,AJ=Pl&&1/Rw(new Pl([,-0]))[1]==DJ?function(e){return new Pl(e)}:Fq,FJ=AJ,LJ=200;function $J(e,t,n){var r=-1,s=Wq,o=e.length,a=!0,l=[],c=l;if(n)a=!1,s=CJ;else if(o>=LJ){var i=t?null:FJ(e);if(i)return Rw(i);a=!1,s=aO,c=new oO}else c=t?[]:l;e:for(;++ru.jsx("button",{className:e.classNames.clearAll,onClick:e.onClick,children:"Clear all"}),HJ=VJ,KJ=(e,t)=>{const n=t.offsetHeight,r=e.offsetHeight,s=e.offsetTop-t.scrollTop;s+r>=n?t.scrollTop+=s-n+r:s<0&&(t.scrollTop+=s)},pb=(e,t,n,r)=>typeof r=="function"?r(e):e.length>=t&&n,qJ=e=>{const t=v.createRef(),{labelField:n,minQueryLength:r,isFocused:s,classNames:o,selectedIndex:a,query:l}=e;v.useEffect(()=>{if(!t.current)return;const p=t.current.querySelector(`.${o.activeSuggestion}`);p&&KJ(p,t.current)},[a]);const c=(p,f)=>{const h=f.trim().replace(/[-\\^$*+?.()|[\]{}]/g,"\\$&"),{[n]:g}=p;return{__html:g.replace(RegExp(h,"gi"),m=>`${RJ(m)}`)}},i=(p,f)=>typeof e.renderSuggestion=="function"?e.renderSuggestion(p,f):u.jsx("span",{dangerouslySetInnerHTML:c(p,f)}),d=e.suggestions.map((p,f)=>u.jsx("li",{onMouseDown:e.handleClick.bind(null,f),onTouchStart:e.handleClick.bind(null,f),onMouseOver:e.handleHover.bind(null,f),className:f===e.selectedIndex?e.classNames.activeSuggestion:"",children:i(p,e.query)},f));return d.length===0||!pb(l,r||2,s,e.shouldRenderSuggestions)?null:u.jsx("div",{ref:t,className:o.suggestions,"data-testid":"suggestions",children:u.jsxs("ul",{children:[" ",d," "]})})},WJ=(e,t)=>{const{query:n,minQueryLength:r=2,isFocused:s,suggestions:o}=t;return!!(e.isFocused===s&&IJ(e.suggestions,o)&&pb(n,r,s,t.shouldRenderSuggestions)===pb(e.query,e.minQueryLength??2,e.isFocused,e.shouldRenderSuggestions)&&e.selectedIndex===t.selectedIndex)},GJ=v.memo(qJ,WJ),JJ=GJ,QJ=HM(KM()),ZJ=HM(KM());function YJ(e){const t=e.map(r=>{const s=r-48*Math.floor(r/48);return String.fromCharCode(96<=r?s:r)}).join(""),n=OJ(t);return new RegExp(`[${n}]+`)}function XJ(e){switch(e){case Rs.ENTER:return[10,13];case Rs.TAB:return 9;case Rs.COMMA:return 188;case Rs.SPACE:return 32;case Rs.SEMICOLON:return 186;default:return 0}}function $1(e){const{moveTag:t,readOnly:n,allowDragDrop:r}=e;return t!==void 0&&!n&&r}function eQ(e){const{readOnly:t,allowDragDrop:n}=e;return!t&&n}var tQ=e=>{const{readOnly:t,removeComponent:n,onRemove:r,className:s,tag:o,index:a}=e,l=i=>{if(Rl.ENTER.includes(i.keyCode)||i.keyCode===Rl.SPACE){i.preventDefault(),i.stopPropagation();return}i.keyCode===Rl.BACKSPACE&&r(i)};if(t)return u.jsx("span",{});const c=`Tag at index ${a} with value ${o.id} focussed. Press backspace to remove`;if(n){const i=n;return u.jsx(i,{"data-testid":"remove",onRemove:r,onKeyDown:l,className:s,"aria-label":c,tag:o,index:a})}return u.jsx("button",{"data-testid":"remove",onClick:r,onKeyDown:l,className:s,type:"button","aria-label":c,children:u.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 512 512",height:"12",width:"12",fill:"#fff",children:u.jsx("path",{d:"M376.6 84.5c11.3-13.6 9.5-33.8-4.1-45.1s-33.8-9.5-45.1 4.1L192 206 56.6 43.5C45.3 29.9 25.1 28.1 11.5 39.4S-3.9 70.9 7.4 84.5L150.3 256 7.4 427.5c-11.3 13.6-9.5 33.8 4.1 45.1s33.8 9.5 45.1-4.1L192 306 327.4 468.5c11.3 13.6 31.5 15.4 45.1 4.1s15.4-31.5 4.1-45.1L233.7 256 376.6 84.5z"})})})},nQ=tQ,B1={TAG:"tag"},rQ=e=>{const t=v.useRef(null),{readOnly:n=!1,tag:r,classNames:s,index:o,moveTag:a,allowDragDrop:l=!0,labelField:c="text",tags:i}=e,[{isDragging:d},p]=U7(()=>({type:B1.TAG,collect:x=>({isDragging:!!x.isDragging()}),item:e,canDrag:()=>$1({moveTag:a,readOnly:n,allowDragDrop:l})}),[i]),[,f]=sK(()=>({accept:B1.TAG,drop:x=>{var w;const b=x.index,y=o;b!==y&&((w=e==null?void 0:e.moveTag)==null||w.call(e,b,y))},canDrop:x=>eQ(x)}),[i]);p(f(t));const h=e.tag[c],{className:g=""}=r,m=d?0:1;return u.jsxs("span",{ref:t,className:(0,ZJ.default)("tag-wrapper",s.tag,g),style:{opacity:m,cursor:$1({moveTag:a,readOnly:n,allowDragDrop:l})?"move":"auto"},"data-testid":"tag",onClick:e.onTagClicked,onTouchStart:e.onTagClicked,children:[h,u.jsx(nQ,{tag:e.tag,className:s.remove,removeComponent:e.removeComponent,onRemove:e.onDelete,readOnly:n,index:o})]})},sQ=e=>{const{autofocus:t,autoFocus:n,readOnly:r,labelField:s,allowDeleteFromEmptyInput:o,allowAdditionFromPaste:a,allowDragDrop:l,minQueryLength:c,shouldRenderSuggestions:i,removeComponent:d,autocomplete:p,inline:f,maxTags:h,allowUnique:g,editable:m,placeholder:x,delimiters:b,separators:y,tags:w,inputFieldPosition:S,inputProps:E,classNames:C,maxLength:k,inputValue:T,clearAll:P}=e,[N,U]=v.useState(e.suggestions),[I,Z]=v.useState(""),[V,Q]=v.useState(!1),[ee,W]=v.useState(-1),[F,A]=v.useState(!1),[Y,de]=v.useState(""),[z,se]=v.useState(-1),[ne,ie]=v.useState(""),oe=v.createRef(),J=v.useRef(null),Ce=v.useRef(null);v.useEffect(()=>{b.length&&console.warn("[Deprecation] The delimiters prop is deprecated and will be removed in v7.x.x, please use separators instead. If you have any concerns regarding this, please share your thoughts in https://github.com/react-tags/react-tags/issues/960")},[]),v.useEffect(()=>{typeof f<"u"&&console.warn("[Deprecation] The inline attribute is deprecated and will be removed in v7.x.x, please use inputFieldPosition instead.")},[f]),v.useEffect(()=>{typeof t<"u"&&console.warn("[Deprecated] autofocus prop will be removed in 7.x so please migrate to autoFocus prop."),(t||n&&t!==!1)&&!r&&Me()},[n,n,r]),v.useEffect(()=>{Wt()},[I,e.suggestions]);const Pe=ue=>{let Ue=e.suggestions.slice();if(g){const _n=w.map(ms=>ms.id.trim().toLowerCase());Ue=Ue.filter(ms=>!_n.includes(ms.id.toLowerCase()))}if(e.handleFilterSuggestions)return e.handleFilterSuggestions(ue,Ue);const St=Ue.filter(_n=>Le(ue,_n)===0),dt=Ue.filter(_n=>Le(ue,_n)>0);return St.concat(dt)},Le=(ue,Ue)=>Ue[s].toLowerCase().indexOf(ue.toLowerCase()),Me=()=>{Z(""),J.current&&(J.current.value="",J.current.focus())},me=(ue,Ue)=>{var dt;Ue.preventDefault(),Ue.stopPropagation();const St=w.slice();St.length!==0&&(ie(""),(dt=e==null?void 0:e.handleDelete)==null||dt.call(e,ue,Ue),rt(ue,St))},rt=(ue,Ue)=>{var _n;if(!(oe!=null&&oe.current))return;const St=oe.current.querySelectorAll(".ReactTags__remove");let dt="";ue===0&&Ue.length>1?(dt=`Tag at index ${ue} with value ${Ue[ue].id} deleted. Tag at index 0 with value ${Ue[1].id} focussed. Press backspace to remove`,St[0].focus()):ue>0?(dt=`Tag at index ${ue} with value ${Ue[ue].id} deleted. Tag at index ${ue-1} with value ${Ue[ue-1].id} focussed. Press backspace to remove`,St[ue-1].focus()):(dt=`Tag at index ${ue} with value ${Ue[ue].id} deleted. Input focussed. Press enter to add a new tag`,(_n=J.current)==null||_n.focus()),de(dt)},It=(ue,Ue,St)=>{var dt,_n;r||(m&&(se(ue),Z(Ue[s]),(dt=Ce.current)==null||dt.focus()),(_n=e.handleTagClick)==null||_n.call(e,ue,St))},Zt=ue=>{e.handleInputChange&&e.handleInputChange(ue.target.value,ue);const Ue=ue.target.value.trim();Z(Ue)},Wt=()=>{const ue=Pe(I);U(ue),W(ee>=ue.length?ue.length-1:ee)},an=ue=>{const Ue=ue.target.value;e.handleInputFocus&&e.handleInputFocus(Ue,ue),Q(!0)},j=ue=>{const Ue=ue.target.value;e.handleInputBlur&&(e.handleInputBlur(Ue,ue),J.current&&(J.current.value="")),Q(!1),se(-1)},D=ue=>{if(ue.key==="Escape"&&(ue.preventDefault(),ue.stopPropagation(),W(-1),A(!1),U([]),se(-1)),(y.indexOf(ue.key)!==-1||b.indexOf(ue.keyCode)!==-1)&&!ue.shiftKey){(ue.keyCode!==Rl.TAB||I!=="")&&ue.preventDefault();const Ue=F&&ee!==-1?N[ee]:{id:I.trim(),[s]:I.trim(),className:""};Object.keys(Ue)&&le(Ue)}ue.key==="Backspace"&&I===""&&(o||S===ec.INLINE)&&me(w.length-1,ue),ue.keyCode===Rl.UP_ARROW&&(ue.preventDefault(),W(ee<=0?N.length-1:ee-1),A(!0)),ue.keyCode===Rl.DOWN_ARROW&&(ue.preventDefault(),A(!0),N.length===0?W(-1):W((ee+1)%N.length))},B=()=>h&&w.length>=h,pe=ue=>{if(!a)return;if(B()){ie(g1.TAG_LIMIT),Me();return}ie(""),ue.preventDefault();const Ue=ue.clipboardData||window.clipboardData,St=Ue.getData("text"),{maxLength:dt=St.length}=e,_n=Math.min(dt,St.length),ms=Ue.getData("text").substr(0,_n);let Ro=b;y.length&&(Ro=[],y.forEach(vs=>{const Du=XJ(vs);Array.isArray(Du)?Ro=[...Ro,...Du]:Ro.push(Du)}));const Iu=YJ(Ro),$i=ms.split(Iu).map(vs=>vs.trim());UJ($i).forEach(vs=>le({id:vs.trim(),[s]:vs.trim(),className:""}))},le=ue=>{var St;if(!ue.id||!ue[s])return;if(z===-1){if(B()){ie(g1.TAG_LIMIT),Me();return}ie("")}const Ue=w.map(dt=>dt.id.toLowerCase());if(!(g&&Ue.indexOf(ue.id.trim().toLowerCase())>=0)){if(p){const dt=Pe(ue[s]);console.warn("[Deprecation] The autocomplete prop will be removed in 7.x to simplify the integration and make it more intutive. If you have any concerns regarding this, please share your thoughts in https://github.com/react-tags/react-tags/issues/949"),(p===1&&dt.length===1||p===!0&&dt.length)&&(ue=dt[0])}z!==-1&&e.onTagUpdate?e.onTagUpdate(z,ue):(St=e==null?void 0:e.handleAddition)==null||St.call(e,ue),Z(""),A(!1),W(-1),se(-1),Me()}},ae=ue=>{le(N[ue])},Ee=()=>{e.onClearAll&&e.onClearAll(),ie(""),Me()},et=ue=>{W(ue),A(!0)},kt=(ue,Ue)=>{var dt;const St=w[ue];(dt=e==null?void 0:e.handleDrag)==null||dt.call(e,St,ue,Ue)},yn=(()=>{const ue={...h1,...e.classNames};return w.map((Ue,St)=>u.jsx(v.Fragment,{children:z===St?u.jsx("div",{className:ue.editTagInput,children:u.jsx("input",{ref:dt=>{Ce.current=dt},onFocus:an,value:I,onChange:Zt,onKeyDown:D,onBlur:j,className:ue.editTagInputField,onPaste:pe,"data-testid":"tag-edit"})}):u.jsx(rQ,{index:St,tag:Ue,tags:w,labelField:s,onDelete:dt=>me(St,dt),moveTag:l?kt:void 0,removeComponent:d,onTagClicked:dt=>It(St,Ue,dt),readOnly:r,classNames:ue,allowDragDrop:l})},St))})(),gn={...h1,...C},{name:jo,id:gs}=e,Aa=f===!1?ec.BOTTOM:S,Fn=r?null:u.jsxs("div",{className:gn.tagInput,children:[u.jsx("input",{...E,ref:ue=>{J.current=ue},className:gn.tagInputField,type:"text",placeholder:x,"aria-label":x,onFocus:an,onBlur:j,onChange:Zt,onKeyDown:D,onPaste:pe,name:jo,id:gs,maxLength:k,value:T,"data-automation":"input","data-testid":"input"}),u.jsx(JJ,{query:I.trim(),suggestions:N,labelField:s,selectedIndex:ee,handleClick:ae,handleHover:et,minQueryLength:c,shouldRenderSuggestions:i,isFocused:V,classNames:gn,renderSuggestion:e.renderSuggestion}),P&&w.length>0&&u.jsx(HJ,{classNames:gn,onClick:Ee}),ne&&u.jsxs("div",{"data-testid":"error",className:"ReactTags__error",children:[u.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 512 512",height:"24",width:"24",fill:"#e03131",children:u.jsx("path",{d:"M256 32c14.2 0 27.3 7.5 34.5 19.8l216 368c7.3 12.4 7.3 27.7 .2 40.1S486.3 480 472 480H40c-14.3 0-27.6-7.7-34.7-20.1s-7-27.8 .2-40.1l216-368C228.7 39.5 241.8 32 256 32zm0 128c-13.3 0-24 10.7-24 24V296c0 13.3 10.7 24 24 24s24-10.7 24-24V184c0-13.3-10.7-24-24-24zm32 224a32 32 0 1 0 -64 0 32 32 0 1 0 64 0z"})}),ne]})]});return u.jsxs("div",{className:(0,QJ.default)(gn.tags,"react-tags-wrapper"),ref:oe,children:[u.jsx("p",{role:"alert",className:"sr-only",style:{position:"absolute",overflow:"hidden",clip:"rect(0 0 0 0)",margin:"-1px",padding:0,width:"1px",height:"1px",border:0},children:Y}),Aa===ec.TOP&&Fn,u.jsxs("div",{className:gn.selected,children:[yn,Aa===ec.INLINE&&Fn]}),Aa===ec.BOTTOM&&Fn]})},oQ=sQ,aQ=e=>{var ne;const{placeholder:t=$K,labelField:n=BK,suggestions:r=[],delimiters:s=[],separators:o=(ne=e.delimiters)!=null&&ne.length?[]:[Rs.ENTER,Rs.TAB],autofocus:a,autoFocus:l=!0,inline:c,inputFieldPosition:i="inline",allowDeleteFromEmptyInput:d=!1,allowAdditionFromPaste:p=!0,autocomplete:f=!1,readOnly:h=!1,allowUnique:g=!0,allowDragDrop:m=!0,tags:x=[],inputProps:b={},editable:y=!1,clearAll:w=!1,handleDelete:S,handleAddition:E,onTagUpdate:C,handleDrag:k,handleFilterSuggestions:T,handleTagClick:P,handleInputChange:N,handleInputFocus:U,handleInputBlur:I,minQueryLength:Z,shouldRenderSuggestions:V,removeComponent:Q,onClearAll:ee,classNames:W,name:F,id:A,maxLength:Y,inputValue:de,maxTags:z,renderSuggestion:se}=e;return u.jsx(oQ,{placeholder:t,labelField:n,suggestions:r,delimiters:s,separators:o,autofocus:a,autoFocus:l,inline:c,inputFieldPosition:i,allowDeleteFromEmptyInput:d,allowAdditionFromPaste:p,autocomplete:f,readOnly:h,allowUnique:g,allowDragDrop:m,tags:x,inputProps:b,editable:y,clearAll:w,handleDelete:S,handleAddition:E,onTagUpdate:C,handleDrag:k,handleFilterSuggestions:T,handleTagClick:P,handleInputChange:N,handleInputFocus:U,handleInputBlur:I,minQueryLength:Z,shouldRenderSuggestions:V,removeComponent:Q,onClearAll:ee,classNames:W,name:F,id:A,maxLength:Y,inputValue:de,maxTags:z,renderSuggestion:se})},iQ=({...e})=>u.jsx(FH,{backend:OK,children:u.jsx(aQ,{...e})});/*! Bundled license information: + +classnames/index.js: + (*! + Copyright (c) 2018 Jed Watson. + Licensed under the MIT License (MIT), see + http://jedwatson.github.io/classnames + *) + +lodash-es/lodash.js: + (** + * @license + * Lodash (Custom Build) + * Build: `lodash modularize exports="es" -o ./` + * Copyright OpenJS Foundation and other contributors + * Released under MIT license + * Based on Underscore.js 1.8.3 + * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + *) +*/var lQ="Label",dO=v.forwardRef((e,t)=>u.jsx(Ne.label,{...e,ref:t,onMouseDown:n=>{var s;n.target.closest("button, input, select, textarea")||((s=e.onMouseDown)==null||s.call(e,n),!n.defaultPrevented&&n.detail>1&&n.preventDefault())}}));dO.displayName=lQ;var fO=dO;const uQ=ig("text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"),pO=v.forwardRef(({className:e,...t},n)=>u.jsx(fO,{ref:n,className:ge(uQ(),e),...t}));pO.displayName=fO.displayName;function hO(e){const t=v.useRef({value:e,previous:e});return v.useMemo(()=>(t.current.value!==e&&(t.current.previous=t.current.value,t.current.value=e),t.current.previous),[e])}var cQ="VisuallyHidden",gO=v.forwardRef((e,t)=>u.jsx(Ne.span,{...e,ref:t,style:{position:"absolute",border:0,width:1,height:1,padding:0,margin:-1,overflow:"hidden",clip:"rect(0, 0, 0, 0)",whiteSpace:"nowrap",wordWrap:"normal",...e.style}}));gO.displayName=cQ;var dQ=[" ","Enter","ArrowUp","ArrowDown"],fQ=[" ","Enter"],ef="Select",[$g,Bg,pQ]=Fx(ef),[_u,Xse]=Vr(ef,[pQ,hg]),zg=hg(),[hQ,Ma]=_u(ef),[gQ,mQ]=_u(ef),mO=e=>{const{__scopeSelect:t,children:n,open:r,defaultOpen:s,onOpenChange:o,value:a,defaultValue:l,onValueChange:c,dir:i,name:d,autoComplete:p,disabled:f,required:h}=e,g=zg(t),[m,x]=v.useState(null),[b,y]=v.useState(null),[w,S]=v.useState(!1),E=Gd(i),[C=!1,k]=pa({prop:r,defaultProp:s,onChange:o}),[T,P]=pa({prop:a,defaultProp:l,onChange:c}),N=v.useRef(null),U=m?!!m.closest("form"):!0,[I,Z]=v.useState(new Set),V=Array.from(I).map(Q=>Q.props.value).join(";");return u.jsx($j,{...g,children:u.jsxs(hQ,{required:h,scope:t,trigger:m,onTriggerChange:x,valueNode:b,onValueNodeChange:y,valueNodeHasChildren:w,onValueNodeHasChildrenChange:S,contentId:os(),value:T,onValueChange:P,open:C,onOpenChange:k,dir:E,triggerPointerDownPosRef:N,disabled:f,children:[u.jsx($g.Provider,{scope:t,children:u.jsx(gQ,{scope:e.__scopeSelect,onNativeOptionAdd:v.useCallback(Q=>{Z(ee=>new Set(ee).add(Q))},[]),onNativeOptionRemove:v.useCallback(Q=>{Z(ee=>{const W=new Set(ee);return W.delete(Q),W})},[]),children:n})}),U?u.jsxs(zO,{"aria-hidden":!0,required:h,tabIndex:-1,name:d,autoComplete:p,value:T,onChange:Q=>P(Q.target.value),disabled:f,children:[T===void 0?u.jsx("option",{value:""}):null,Array.from(I)]},V):null]})})};mO.displayName=ef;var vO="SelectTrigger",yO=v.forwardRef((e,t)=>{const{__scopeSelect:n,disabled:r=!1,...s}=e,o=zg(n),a=Ma(vO,n),l=a.disabled||r,c=it(t,a.onTriggerChange),i=Bg(n),[d,p,f]=UO(g=>{const m=i().filter(y=>!y.disabled),x=m.find(y=>y.value===a.value),b=VO(m,g,x);b!==void 0&&a.onValueChange(b.value)}),h=()=>{l||(a.onOpenChange(!0),f())};return u.jsx(Bj,{asChild:!0,...o,children:u.jsx(Ne.button,{type:"button",role:"combobox","aria-controls":a.contentId,"aria-expanded":a.open,"aria-required":a.required,"aria-autocomplete":"none",dir:a.dir,"data-state":a.open?"open":"closed",disabled:l,"data-disabled":l?"":void 0,"data-placeholder":BO(a.value)?"":void 0,...s,ref:c,onClick:Se(s.onClick,g=>{g.currentTarget.focus()}),onPointerDown:Se(s.onPointerDown,g=>{const m=g.target;m.hasPointerCapture(g.pointerId)&&m.releasePointerCapture(g.pointerId),g.button===0&&g.ctrlKey===!1&&(h(),a.triggerPointerDownPosRef.current={x:Math.round(g.pageX),y:Math.round(g.pageY)},g.preventDefault())}),onKeyDown:Se(s.onKeyDown,g=>{const m=d.current!=="";!(g.ctrlKey||g.altKey||g.metaKey)&&g.key.length===1&&p(g.key),!(m&&g.key===" ")&&dQ.includes(g.key)&&(h(),g.preventDefault())})})})});yO.displayName=vO;var bO="SelectValue",xO=v.forwardRef((e,t)=>{const{__scopeSelect:n,className:r,style:s,children:o,placeholder:a="",...l}=e,c=Ma(bO,n),{onValueNodeHasChildrenChange:i}=c,d=o!==void 0,p=it(t,c.onValueNodeChange);return fn(()=>{i(d)},[i,d]),u.jsx(Ne.span,{...l,ref:p,style:{pointerEvents:"none"},children:BO(c.value)?u.jsx(u.Fragment,{children:a}):o})});xO.displayName=bO;var vQ="SelectIcon",wO=v.forwardRef((e,t)=>{const{__scopeSelect:n,children:r,...s}=e;return u.jsx(Ne.span,{"aria-hidden":!0,...s,ref:t,children:r||"▼"})});wO.displayName=vQ;var yQ="SelectPortal",SO=e=>u.jsx(gg,{asChild:!0,...e});SO.displayName=yQ;var ji="SelectContent",CO=v.forwardRef((e,t)=>{const n=Ma(ji,e.__scopeSelect),[r,s]=v.useState();if(fn(()=>{s(new DocumentFragment)},[]),!n.open){const o=r;return o?ka.createPortal(u.jsx(EO,{scope:e.__scopeSelect,children:u.jsx($g.Slot,{scope:e.__scopeSelect,children:u.jsx("div",{children:e.children})})}),o):null}return u.jsx(TO,{...e,ref:t})});CO.displayName=ji;var Ys=10,[EO,Oa]=_u(ji),bQ="SelectContentImpl",TO=v.forwardRef((e,t)=>{const{__scopeSelect:n,position:r="item-aligned",onCloseAutoFocus:s,onEscapeKeyDown:o,onPointerDownOutside:a,side:l,sideOffset:c,align:i,alignOffset:d,arrowPadding:p,collisionBoundary:f,collisionPadding:h,sticky:g,hideWhenDetached:m,avoidCollisions:x,...b}=e,y=Ma(ji,n),[w,S]=v.useState(null),[E,C]=v.useState(null),k=it(t,J=>S(J)),[T,P]=v.useState(null),[N,U]=v.useState(null),I=Bg(n),[Z,V]=v.useState(!1),Q=v.useRef(!1);v.useEffect(()=>{if(w)return Wx(w)},[w]),Lx();const ee=v.useCallback(J=>{const[Ce,...Pe]=I().map(me=>me.ref.current),[Le]=Pe.slice(-1),Me=document.activeElement;for(const me of J)if(me===Me||(me==null||me.scrollIntoView({block:"nearest"}),me===Ce&&E&&(E.scrollTop=0),me===Le&&E&&(E.scrollTop=E.scrollHeight),me==null||me.focus(),document.activeElement!==Me))return},[I,E]),W=v.useCallback(()=>ee([T,w]),[ee,T,w]);v.useEffect(()=>{Z&&W()},[Z,W]);const{onOpenChange:F,triggerPointerDownPosRef:A}=y;v.useEffect(()=>{if(w){let J={x:0,y:0};const Ce=Le=>{var Me,me;J={x:Math.abs(Math.round(Le.pageX)-(((Me=A.current)==null?void 0:Me.x)??0)),y:Math.abs(Math.round(Le.pageY)-(((me=A.current)==null?void 0:me.y)??0))}},Pe=Le=>{J.x<=10&&J.y<=10?Le.preventDefault():w.contains(Le.target)||F(!1),document.removeEventListener("pointermove",Ce),A.current=null};return A.current!==null&&(document.addEventListener("pointermove",Ce),document.addEventListener("pointerup",Pe,{capture:!0,once:!0})),()=>{document.removeEventListener("pointermove",Ce),document.removeEventListener("pointerup",Pe,{capture:!0})}}},[w,F,A]),v.useEffect(()=>{const J=()=>F(!1);return window.addEventListener("blur",J),window.addEventListener("resize",J),()=>{window.removeEventListener("blur",J),window.removeEventListener("resize",J)}},[F]);const[Y,de]=UO(J=>{const Ce=I().filter(Me=>!Me.disabled),Pe=Ce.find(Me=>Me.ref.current===document.activeElement),Le=VO(Ce,J,Pe);Le&&setTimeout(()=>Le.ref.current.focus())}),z=v.useCallback((J,Ce,Pe)=>{const Le=!Q.current&&!Pe;(y.value!==void 0&&y.value===Ce||Le)&&(P(J),Le&&(Q.current=!0))},[y.value]),se=v.useCallback(()=>w==null?void 0:w.focus(),[w]),ne=v.useCallback((J,Ce,Pe)=>{const Le=!Q.current&&!Pe;(y.value!==void 0&&y.value===Ce||Le)&&U(J)},[y.value]),ie=r==="popper"?hb:kO,oe=ie===hb?{side:l,sideOffset:c,align:i,alignOffset:d,arrowPadding:p,collisionBoundary:f,collisionPadding:h,sticky:g,hideWhenDetached:m,avoidCollisions:x}:{};return u.jsx(EO,{scope:n,content:w,viewport:E,onViewportChange:C,itemRefCallback:z,selectedItem:T,onItemLeave:se,itemTextRefCallback:ne,focusSelectedItem:W,selectedItemText:N,position:r,isPositioned:Z,searchRef:Y,children:u.jsx(bg,{as:mo,allowPinchZoom:!0,children:u.jsx(dg,{asChild:!0,trapped:y.open,onMountAutoFocus:J=>{J.preventDefault()},onUnmountAutoFocus:Se(s,J=>{var Ce;(Ce=y.trigger)==null||Ce.focus({preventScroll:!0}),J.preventDefault()}),children:u.jsx(cg,{asChild:!0,disableOutsidePointerEvents:!0,onEscapeKeyDown:o,onPointerDownOutside:a,onFocusOutside:J=>J.preventDefault(),onDismiss:()=>y.onOpenChange(!1),children:u.jsx(ie,{role:"listbox",id:y.contentId,"data-state":y.open?"open":"closed",dir:y.dir,onContextMenu:J=>J.preventDefault(),...b,...oe,onPlaced:()=>V(!0),ref:k,style:{display:"flex",flexDirection:"column",outline:"none",...b.style},onKeyDown:Se(b.onKeyDown,J=>{const Ce=J.ctrlKey||J.altKey||J.metaKey;if(J.key==="Tab"&&J.preventDefault(),!Ce&&J.key.length===1&&de(J.key),["ArrowUp","ArrowDown","Home","End"].includes(J.key)){let Le=I().filter(Me=>!Me.disabled).map(Me=>Me.ref.current);if(["ArrowUp","End"].includes(J.key)&&(Le=Le.slice().reverse()),["ArrowUp","ArrowDown"].includes(J.key)){const Me=J.target,me=Le.indexOf(Me);Le=Le.slice(me+1)}setTimeout(()=>ee(Le)),J.preventDefault()}})})})})})})});TO.displayName=bQ;var xQ="SelectItemAlignedPosition",kO=v.forwardRef((e,t)=>{const{__scopeSelect:n,onPlaced:r,...s}=e,o=Ma(ji,n),a=Oa(ji,n),[l,c]=v.useState(null),[i,d]=v.useState(null),p=it(t,k=>d(k)),f=Bg(n),h=v.useRef(!1),g=v.useRef(!0),{viewport:m,selectedItem:x,selectedItemText:b,focusSelectedItem:y}=a,w=v.useCallback(()=>{if(o.trigger&&o.valueNode&&l&&i&&m&&x&&b){const k=o.trigger.getBoundingClientRect(),T=i.getBoundingClientRect(),P=o.valueNode.getBoundingClientRect(),N=b.getBoundingClientRect();if(o.dir!=="rtl"){const Me=N.left-T.left,me=P.left-Me,rt=k.left-me,It=k.width+rt,Zt=Math.max(It,T.width),Wt=window.innerWidth-Ys,an=Zy(me,[Ys,Wt-Zt]);l.style.minWidth=It+"px",l.style.left=an+"px"}else{const Me=T.right-N.right,me=window.innerWidth-P.right-Me,rt=window.innerWidth-k.right-me,It=k.width+rt,Zt=Math.max(It,T.width),Wt=window.innerWidth-Ys,an=Zy(me,[Ys,Wt-Zt]);l.style.minWidth=It+"px",l.style.right=an+"px"}const U=f(),I=window.innerHeight-Ys*2,Z=m.scrollHeight,V=window.getComputedStyle(i),Q=parseInt(V.borderTopWidth,10),ee=parseInt(V.paddingTop,10),W=parseInt(V.borderBottomWidth,10),F=parseInt(V.paddingBottom,10),A=Q+ee+Z+F+W,Y=Math.min(x.offsetHeight*5,A),de=window.getComputedStyle(m),z=parseInt(de.paddingTop,10),se=parseInt(de.paddingBottom,10),ne=k.top+k.height/2-Ys,ie=I-ne,oe=x.offsetHeight/2,J=x.offsetTop+oe,Ce=Q+ee+J,Pe=A-Ce;if(Ce<=ne){const Me=x===U[U.length-1].ref.current;l.style.bottom="0px";const me=i.clientHeight-m.offsetTop-m.offsetHeight,rt=Math.max(ie,oe+(Me?se:0)+me+W),It=Ce+rt;l.style.height=It+"px"}else{const Me=x===U[0].ref.current;l.style.top="0px";const rt=Math.max(ne,Q+m.offsetTop+(Me?z:0)+oe)+Pe;l.style.height=rt+"px",m.scrollTop=Ce-ne+m.offsetTop}l.style.margin=`${Ys}px 0`,l.style.minHeight=Y+"px",l.style.maxHeight=I+"px",r==null||r(),requestAnimationFrame(()=>h.current=!0)}},[f,o.trigger,o.valueNode,l,i,m,x,b,o.dir,r]);fn(()=>w(),[w]);const[S,E]=v.useState();fn(()=>{i&&E(window.getComputedStyle(i).zIndex)},[i]);const C=v.useCallback(k=>{k&&g.current===!0&&(w(),y==null||y(),g.current=!1)},[w,y]);return u.jsx(SQ,{scope:n,contentWrapper:l,shouldExpandOnScrollRef:h,onScrollButtonChange:C,children:u.jsx("div",{ref:c,style:{display:"flex",flexDirection:"column",position:"fixed",zIndex:S},children:u.jsx(Ne.div,{...s,ref:p,style:{boxSizing:"border-box",maxHeight:"100%",...s.style}})})})});kO.displayName=xQ;var wQ="SelectPopperPosition",hb=v.forwardRef((e,t)=>{const{__scopeSelect:n,align:r="start",collisionPadding:s=Ys,...o}=e,a=zg(n);return u.jsx(zj,{...a,...o,ref:t,align:r,collisionPadding:s,style:{boxSizing:"border-box",...o.style,"--radix-select-content-transform-origin":"var(--radix-popper-transform-origin)","--radix-select-content-available-width":"var(--radix-popper-available-width)","--radix-select-content-available-height":"var(--radix-popper-available-height)","--radix-select-trigger-width":"var(--radix-popper-anchor-width)","--radix-select-trigger-height":"var(--radix-popper-anchor-height)"}})});hb.displayName=wQ;var[SQ,Pw]=_u(ji,{}),gb="SelectViewport",_O=v.forwardRef((e,t)=>{const{__scopeSelect:n,nonce:r,...s}=e,o=Oa(gb,n),a=Pw(gb,n),l=it(t,o.onViewportChange),c=v.useRef(0);return u.jsxs(u.Fragment,{children:[u.jsx("style",{dangerouslySetInnerHTML:{__html:"[data-radix-select-viewport]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}[data-radix-select-viewport]::-webkit-scrollbar{display:none}"},nonce:r}),u.jsx($g.Slot,{scope:n,children:u.jsx(Ne.div,{"data-radix-select-viewport":"",role:"presentation",...s,ref:l,style:{position:"relative",flex:1,overflow:"auto",...s.style},onScroll:Se(s.onScroll,i=>{const d=i.currentTarget,{contentWrapper:p,shouldExpandOnScrollRef:f}=a;if(f!=null&&f.current&&p){const h=Math.abs(c.current-d.scrollTop);if(h>0){const g=window.innerHeight-Ys*2,m=parseFloat(p.style.minHeight),x=parseFloat(p.style.height),b=Math.max(m,x);if(b0?S:0,p.style.justifyContent="flex-end")}}}c.current=d.scrollTop})})})]})});_O.displayName=gb;var jO="SelectGroup",[CQ,EQ]=_u(jO),TQ=v.forwardRef((e,t)=>{const{__scopeSelect:n,...r}=e,s=os();return u.jsx(CQ,{scope:n,id:s,children:u.jsx(Ne.div,{role:"group","aria-labelledby":s,...r,ref:t})})});TQ.displayName=jO;var RO="SelectLabel",PO=v.forwardRef((e,t)=>{const{__scopeSelect:n,...r}=e,s=EQ(RO,n);return u.jsx(Ne.div,{id:s.id,...r,ref:t})});PO.displayName=RO;var Th="SelectItem",[kQ,MO]=_u(Th),OO=v.forwardRef((e,t)=>{const{__scopeSelect:n,value:r,disabled:s=!1,textValue:o,...a}=e,l=Ma(Th,n),c=Oa(Th,n),i=l.value===r,[d,p]=v.useState(o??""),[f,h]=v.useState(!1),g=it(t,b=>{var y;return(y=c.itemRefCallback)==null?void 0:y.call(c,b,r,s)}),m=os(),x=()=>{s||(l.onValueChange(r),l.onOpenChange(!1))};if(r==="")throw new Error("A must have a value prop that is not an empty string. This is because the Select value can be set to an empty string to clear the selection and show the placeholder.");return u.jsx(kQ,{scope:n,value:r,disabled:s,textId:m,isSelected:i,onItemTextChange:v.useCallback(b=>{p(y=>y||((b==null?void 0:b.textContent)??"").trim())},[]),children:u.jsx($g.ItemSlot,{scope:n,value:r,disabled:s,textValue:d,children:u.jsx(Ne.div,{role:"option","aria-labelledby":m,"data-highlighted":f?"":void 0,"aria-selected":i&&f,"data-state":i?"checked":"unchecked","aria-disabled":s||void 0,"data-disabled":s?"":void 0,tabIndex:s?void 0:-1,...a,ref:g,onFocus:Se(a.onFocus,()=>h(!0)),onBlur:Se(a.onBlur,()=>h(!1)),onPointerUp:Se(a.onPointerUp,x),onPointerMove:Se(a.onPointerMove,b=>{var y;s?(y=c.onItemLeave)==null||y.call(c):b.currentTarget.focus({preventScroll:!0})}),onPointerLeave:Se(a.onPointerLeave,b=>{var y;b.currentTarget===document.activeElement&&((y=c.onItemLeave)==null||y.call(c))}),onKeyDown:Se(a.onKeyDown,b=>{var w;((w=c.searchRef)==null?void 0:w.current)!==""&&b.key===" "||(fQ.includes(b.key)&&x(),b.key===" "&&b.preventDefault())})})})})});OO.displayName=Th;var hc="SelectItemText",NO=v.forwardRef((e,t)=>{const{__scopeSelect:n,className:r,style:s,...o}=e,a=Ma(hc,n),l=Oa(hc,n),c=MO(hc,n),i=mQ(hc,n),[d,p]=v.useState(null),f=it(t,b=>p(b),c.onItemTextChange,b=>{var y;return(y=l.itemTextRefCallback)==null?void 0:y.call(l,b,c.value,c.disabled)}),h=d==null?void 0:d.textContent,g=v.useMemo(()=>u.jsx("option",{value:c.value,disabled:c.disabled,children:h},c.value),[c.disabled,c.value,h]),{onNativeOptionAdd:m,onNativeOptionRemove:x}=i;return fn(()=>(m(g),()=>x(g)),[m,x,g]),u.jsxs(u.Fragment,{children:[u.jsx(Ne.span,{id:c.textId,...o,ref:f}),c.isSelected&&a.valueNode&&!a.valueNodeHasChildren?ka.createPortal(o.children,a.valueNode):null]})});NO.displayName=hc;var IO="SelectItemIndicator",DO=v.forwardRef((e,t)=>{const{__scopeSelect:n,...r}=e;return MO(IO,n).isSelected?u.jsx(Ne.span,{"aria-hidden":!0,...r,ref:t}):null});DO.displayName=IO;var mb="SelectScrollUpButton",AO=v.forwardRef((e,t)=>{const n=Oa(mb,e.__scopeSelect),r=Pw(mb,e.__scopeSelect),[s,o]=v.useState(!1),a=it(t,r.onScrollButtonChange);return fn(()=>{if(n.viewport&&n.isPositioned){let l=function(){const i=c.scrollTop>0;o(i)};const c=n.viewport;return l(),c.addEventListener("scroll",l),()=>c.removeEventListener("scroll",l)}},[n.viewport,n.isPositioned]),s?u.jsx(LO,{...e,ref:a,onAutoScroll:()=>{const{viewport:l,selectedItem:c}=n;l&&c&&(l.scrollTop=l.scrollTop-c.offsetHeight)}}):null});AO.displayName=mb;var vb="SelectScrollDownButton",FO=v.forwardRef((e,t)=>{const n=Oa(vb,e.__scopeSelect),r=Pw(vb,e.__scopeSelect),[s,o]=v.useState(!1),a=it(t,r.onScrollButtonChange);return fn(()=>{if(n.viewport&&n.isPositioned){let l=function(){const i=c.scrollHeight-c.clientHeight,d=Math.ceil(c.scrollTop)c.removeEventListener("scroll",l)}},[n.viewport,n.isPositioned]),s?u.jsx(LO,{...e,ref:a,onAutoScroll:()=>{const{viewport:l,selectedItem:c}=n;l&&c&&(l.scrollTop=l.scrollTop+c.offsetHeight)}}):null});FO.displayName=vb;var LO=v.forwardRef((e,t)=>{const{__scopeSelect:n,onAutoScroll:r,...s}=e,o=Oa("SelectScrollButton",n),a=v.useRef(null),l=Bg(n),c=v.useCallback(()=>{a.current!==null&&(window.clearInterval(a.current),a.current=null)},[]);return v.useEffect(()=>()=>c(),[c]),fn(()=>{var d;const i=l().find(p=>p.ref.current===document.activeElement);(d=i==null?void 0:i.ref.current)==null||d.scrollIntoView({block:"nearest"})},[l]),u.jsx(Ne.div,{"aria-hidden":!0,...s,ref:t,style:{flexShrink:0,...s.style},onPointerDown:Se(s.onPointerDown,()=>{a.current===null&&(a.current=window.setInterval(r,50))}),onPointerMove:Se(s.onPointerMove,()=>{var i;(i=o.onItemLeave)==null||i.call(o),a.current===null&&(a.current=window.setInterval(r,50))}),onPointerLeave:Se(s.onPointerLeave,()=>{c()})})}),_Q="SelectSeparator",$O=v.forwardRef((e,t)=>{const{__scopeSelect:n,...r}=e;return u.jsx(Ne.div,{"aria-hidden":!0,...r,ref:t})});$O.displayName=_Q;var yb="SelectArrow",jQ=v.forwardRef((e,t)=>{const{__scopeSelect:n,...r}=e,s=zg(n),o=Ma(yb,n),a=Oa(yb,n);return o.open&&a.position==="popper"?u.jsx(Uj,{...s,...r,ref:t}):null});jQ.displayName=yb;function BO(e){return e===""||e===void 0}var zO=v.forwardRef((e,t)=>{const{value:n,...r}=e,s=v.useRef(null),o=it(t,s),a=hO(n);return v.useEffect(()=>{const l=s.current,c=window.HTMLSelectElement.prototype,d=Object.getOwnPropertyDescriptor(c,"value").set;if(a!==n&&d){const p=new Event("change",{bubbles:!0});d.call(l,n),l.dispatchEvent(p)}},[a,n]),u.jsx(gO,{asChild:!0,children:u.jsx("select",{...r,ref:o,defaultValue:n})})});zO.displayName="BubbleSelect";function UO(e){const t=nn(e),n=v.useRef(""),r=v.useRef(0),s=v.useCallback(a=>{const l=n.current+a;t(l),function c(i){n.current=i,window.clearTimeout(r.current),i!==""&&(r.current=window.setTimeout(()=>c(""),1e3))}(l)},[t]),o=v.useCallback(()=>{n.current="",window.clearTimeout(r.current)},[]);return v.useEffect(()=>()=>window.clearTimeout(r.current),[]),[n,s,o]}function VO(e,t,n){const s=t.length>1&&Array.from(t).every(i=>i===t[0])?t[0]:t,o=n?e.indexOf(n):-1;let a=RQ(e,Math.max(o,0));s.length===1&&(a=a.filter(i=>i!==n));const c=a.find(i=>i.textValue.toLowerCase().startsWith(s.toLowerCase()));return c!==n?c:void 0}function RQ(e,t){return e.map((n,r)=>e[(t+r)%e.length])}var PQ=mO,HO=yO,MQ=xO,OQ=wO,NQ=SO,KO=CO,IQ=_O,qO=PO,WO=OO,DQ=NO,AQ=DO,GO=AO,JO=FO,QO=$O;const FQ=PQ,LQ=MQ,ZO=v.forwardRef(({className:e,children:t,...n},r)=>u.jsxs(HO,{ref:r,className:ge("flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",e),...n,children:[t,u.jsx(OQ,{asChild:!0,children:u.jsx(lg,{className:"h-4 w-4 opacity-50"})})]}));ZO.displayName=HO.displayName;const YO=v.forwardRef(({className:e,...t},n)=>u.jsx(GO,{ref:n,className:ge("flex cursor-default items-center justify-center py-1",e),...t,children:u.jsx(P3,{className:"h-4 w-4"})}));YO.displayName=GO.displayName;const XO=v.forwardRef(({className:e,...t},n)=>u.jsx(JO,{ref:n,className:ge("flex cursor-default items-center justify-center py-1",e),...t,children:u.jsx(lg,{className:"h-4 w-4"})}));XO.displayName=JO.displayName;const eN=v.forwardRef(({className:e,children:t,position:n="popper",...r},s)=>u.jsx(NQ,{children:u.jsxs(KO,{ref:s,className:ge("relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",n==="popper"&&"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",e),position:n,...r,children:[u.jsx(YO,{}),u.jsx(IQ,{className:ge("p-1",n==="popper"&&"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"),children:t}),u.jsx(XO,{})]})}));eN.displayName=KO.displayName;const $Q=v.forwardRef(({className:e,...t},n)=>u.jsx(qO,{ref:n,className:ge("py-1.5 pl-8 pr-2 text-sm font-semibold",e),...t}));$Q.displayName=qO.displayName;const tN=v.forwardRef(({className:e,children:t,...n},r)=>u.jsxs(WO,{ref:r,className:ge("relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",e),...n,children:[u.jsx("span",{className:"absolute left-2 flex h-3.5 w-3.5 items-center justify-center",children:u.jsx(AQ,{children:u.jsx(cj,{className:"h-4 w-4"})})}),u.jsx(DQ,{children:t})]}));tN.displayName=WO.displayName;const BQ=v.forwardRef(({className:e,...t},n)=>u.jsx(QO,{ref:n,className:ge("-mx-1 my-1 h-px bg-muted",e),...t}));BQ.displayName=QO.displayName;var Mw="Switch",[zQ,eoe]=Vr(Mw),[UQ,VQ]=zQ(Mw),nN=v.forwardRef((e,t)=>{const{__scopeSwitch:n,name:r,checked:s,defaultChecked:o,required:a,disabled:l,value:c="on",onCheckedChange:i,...d}=e,[p,f]=v.useState(null),h=it(t,y=>f(y)),g=v.useRef(!1),m=p?!!p.closest("form"):!0,[x=!1,b]=pa({prop:s,defaultProp:o,onChange:i});return u.jsxs(UQ,{scope:n,checked:x,disabled:l,children:[u.jsx(Ne.button,{type:"button",role:"switch","aria-checked":x,"aria-required":a,"data-state":oN(x),"data-disabled":l?"":void 0,disabled:l,value:c,...d,ref:h,onClick:Se(e.onClick,y=>{b(w=>!w),m&&(g.current=y.isPropagationStopped(),g.current||y.stopPropagation())})}),m&&u.jsx(HQ,{control:p,bubbles:!g.current,name:r,value:c,checked:x,required:a,disabled:l,style:{transform:"translateX(-100%)"}})]})});nN.displayName=Mw;var rN="SwitchThumb",sN=v.forwardRef((e,t)=>{const{__scopeSwitch:n,...r}=e,s=VQ(rN,n);return u.jsx(Ne.span,{"data-state":oN(s.checked),"data-disabled":s.disabled?"":void 0,...r,ref:t})});sN.displayName=rN;var HQ=e=>{const{control:t,checked:n,bubbles:r=!0,...s}=e,o=v.useRef(null),a=hO(n),l=Rj(t);return v.useEffect(()=>{const c=o.current,i=window.HTMLInputElement.prototype,p=Object.getOwnPropertyDescriptor(i,"checked").set;if(a!==n&&p){const f=new Event("click",{bubbles:r});p.call(c,n),c.dispatchEvent(f)}},[a,n,r]),u.jsx("input",{type:"checkbox","aria-hidden":!0,defaultChecked:n,...s,tabIndex:-1,ref:o,style:{...e.style,...l,position:"absolute",pointerEvents:"none",opacity:0,margin:0}})};function oN(e){return e?"checked":"unchecked"}var aN=nN,KQ=sN;const ju=v.forwardRef(({className:e,...t},n)=>u.jsx(aN,{className:ge("peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-slate-400",e),...t,ref:n,children:u.jsx(KQ,{className:ge("pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0")})}));ju.displayName=aN.displayName;const Na=Tr,iN=v.createContext({}),Ia=({...e})=>u.jsx(iN.Provider,{value:{name:e.name},children:u.jsx($V,{...e})}),Ug=()=>{const e=v.useContext(iN),t=v.useContext(lN),{getFieldState:n,formState:r}=Rg(),s=n(e.name,r);if(!e)throw new Error("useFormField should be used within ");const{id:o}=t;return{id:o,name:e.name,formItemId:`${o}-form-item`,formDescriptionId:`${o}-form-item-description`,formMessageId:`${o}-form-item-message`,...s}},lN=v.createContext({}),_o=v.forwardRef(({className:e,...t},n)=>{const r=v.useId();return u.jsx(lN.Provider,{value:{id:r},children:u.jsx("div",{ref:n,className:ge("space-y-2",e),...t})})});_o.displayName="FormItem";const xr=v.forwardRef(({className:e,...t},n)=>{const{error:r,formItemId:s}=Ug();return u.jsx(pO,{ref:n,className:ge(r&&"text-rose-600",e),htmlFor:s,...t})});xr.displayName="FormLabel";const Vs=v.forwardRef(({...e},t)=>{const{error:n,formItemId:r,formDescriptionId:s,formMessageId:o}=Ug();return u.jsx(mo,{ref:t,id:r,"aria-describedby":n?`${s} ${o}`:`${s}`,"aria-invalid":!!n,...e})});Vs.displayName="FormControl";const Vg=v.forwardRef(({className:e,...t},n)=>{const{formDescriptionId:r}=Ug();return u.jsx("p",{ref:n,id:r,className:ge("text-sm text-muted-foreground",e),...t})});Vg.displayName="FormDescription";const tf=v.forwardRef(({className:e,children:t,...n},r)=>{const{error:s,formMessageId:o}=Ug(),a=s?String(s==null?void 0:s.message):t;return a?u.jsx("p",{ref:r,id:o,className:ge("text-sm font-medium text-rose-600",e),...n,children:a}):null});tf.displayName="FormMessage";const G=({name:e,label:t,children:n,required:r,readOnly:s,className:o,...a})=>u.jsx(Ia,{...a,name:e,render:({field:l})=>u.jsxs(_o,{className:o,children:[t&&u.jsxs(xr,{children:[t,r&&u.jsx("span",{className:"ml-2 text-rose-600",children:"*"})]}),u.jsx(Vs,{children:v.isValidElement(n)&&v.cloneElement(n,{...l,value:l.value??"",required:r,readOnly:s,checked:l.value,onCheckedChange:l.onChange})}),u.jsx(tf,{})]})}),ke=({name:e,label:t,required:n,className:r,helper:s,reverse:o,...a})=>u.jsx(Ia,{...a,name:e,render:({field:l})=>u.jsxs(_o,{className:ge("flex items-center gap-3",o&&"flex-row-reverse justify-end",r),children:[u.jsx("div",{className:"flex flex-col gap-2",children:t&&u.jsxs(xr,{children:[u.jsxs("p",{className:"break-all",children:[t,n&&u.jsx("span",{className:"ml-2 text-rose-600",children:"*"})]}),s&&u.jsx(Vg,{className:"mt-2",children:s})]})}),u.jsx(Vs,{children:u.jsx(ju,{checked:l.value,onCheckedChange:l.onChange,required:n})}),u.jsx(tf,{})]})}),Qt=({name:e,label:t,helper:n,required:r,options:s,placeholder:o,...a})=>u.jsx(Ia,{...a,name:e,render:({field:l})=>u.jsxs(_o,{children:[t&&u.jsxs(xr,{children:[t,r&&u.jsx("span",{className:"ml-2 text-rose-600",children:"*"})]}),u.jsx(Vs,{children:u.jsxs(FQ,{onValueChange:l.onChange,defaultValue:l.value,children:[u.jsx(Vs,{children:u.jsx(ZO,{children:u.jsx(LQ,{placeholder:o})})}),u.jsx(eN,{children:s.map(c=>u.jsx(tN,{value:c.value,children:c.label},c.value))})]})}),n&&u.jsx(Vg,{children:n}),u.jsx(tf,{})]})}),Ru=({name:e,label:t,helper:n,required:r,placeholder:s,...o})=>u.jsx(Ia,{...o,name:e,render:({field:a})=>{let l=[];return Array.isArray(a.value)&&(l=a.value),u.jsxs(_o,{children:[t&&u.jsxs(xr,{children:[t,r&&u.jsx("span",{className:"ml-2 text-rose-600",children:"*"})]}),u.jsx(Vs,{children:u.jsx(iQ,{tags:l.map(c=>({id:c,text:c,className:""})),handleDelete:c=>a.onChange(l.filter((i,d)=>d!==c)),handleAddition:c=>a.onChange([...l,c.id]),inputFieldPosition:"bottom",placeholder:s,autoFocus:!1,allowDragDrop:!1,separators:[Rs.ENTER,Rs.TAB,Rs.COMMA],classNames:{tags:"tagsClass",tagInput:"tagInputClass",tagInputField:QP,selected:"my-2 flex flex-wrap gap-2",tag:"flex items-center gap-2 px-2 py-1 bg-primary/30 rounded-md text-xs",remove:"[&>svg]:fill-rose-600 hover:[&>svg]:fill-rose-700",suggestions:"suggestionsClass",activeSuggestion:"activeSuggestionClass",editTagInput:"editTagInputClass",editTagInputField:"editTagInputFieldClass",clearAll:"clearAllClass"}})}),n&&u.jsx(Vg,{children:n}),u.jsx(tf,{})]})}}),pv=_.string().optional().transform(e=>e===""?void 0:e),qQ=_.object({name:_.string(),token:pv,number:pv,businessId:pv,integration:_.enum(["WHATSAPP-BUSINESS","WHATSAPP-BAILEYS","EVOLUTION"])});function WQ({resetTable:e}){const{t}=ze(),{createInstance:n}=_g(),[r,s]=v.useState(!1),o=[{value:"WHATSAPP-BAILEYS",label:t("instance.form.integration.baileys")},{value:"WHATSAPP-BUSINESS",label:t("instance.form.integration.whatsapp")},{value:"EVOLUTION",label:t("instance.form.integration.evolution")}],a=sn({resolver:on(qQ),defaultValues:{name:"",integration:"WHATSAPP-BAILEYS",token:NC().replace("-","").toUpperCase(),number:"",businessId:""}}),l=a.watch("integration"),c=async d=>{var p,f,h;try{const g={instanceName:d.name,integration:d.integration,token:d.token===""?null:d.token,number:d.number===""?null:d.number,businessId:d.businessId===""?null:d.businessId};await n(g),X.success(t("toast.instance.created")),s(!1),i(),e()}catch(g){console.error("Error:",g),X.error(`Error : ${(h=(f=(p=g==null?void 0:g.response)==null?void 0:p.data)==null?void 0:f.response)==null?void 0:h.message}`)}},i=()=>{a.reset({name:"",integration:"WHATSAPP-BAILEYS",token:NC().replace("-","").toLocaleUpperCase(),number:"",businessId:""})};return u.jsxs(Tt,{open:r,onOpenChange:s,children:[u.jsx(Nt,{asChild:!0,children:u.jsxs(q,{variant:"default",size:"sm",children:[t("instance.button.create")," ",u.jsx(Ni,{size:"18"})]})}),u.jsxs(xt,{className:"sm:max-w-[650px]",onCloseAutoFocus:i,children:[u.jsx(wt,{children:u.jsx(Ut,{children:t("instance.modal.title")})}),u.jsx(Tr,{...a,children:u.jsxs("form",{onSubmit:a.handleSubmit(c),className:"grid gap-4 py-4",children:[u.jsx(G,{required:!0,name:"name",label:t("instance.form.name"),children:u.jsx(K,{})}),u.jsx(Qt,{name:"integration",label:t("instance.form.integration.label"),options:o}),u.jsx(G,{required:!0,name:"token",label:t("instance.form.token"),children:u.jsx(K,{})}),u.jsx(G,{name:"number",label:t("instance.form.number"),children:u.jsx(K,{type:"tel"})}),l==="WHATSAPP-BUSINESS"&&u.jsx(G,{required:!0,name:"businessId",label:t("instance.form.businessId"),children:u.jsx(K,{})}),u.jsx(rn,{children:u.jsx(q,{type:"submit",children:t("instance.button.save")})})]})})]})]})}function GQ(){const{t:e}=ze(),[t,n]=v.useState(null),{deleteInstance:r,logout:s}=_g(),{data:o,refetch:a}=_V(),[l,c]=v.useState([]),[i,d]=v.useState("all"),[p,f]=v.useState(""),h=async()=>{await a()},g=async b=>{var y,w,S;n(null),c([...l,b]);try{try{await s(b)}catch(E){console.error("Error logout:",E)}await r(b),await new Promise(E=>setTimeout(E,1e3)),h()}catch(E){console.error("Error instance delete:",E),X.error(`Error : ${(S=(w=(y=E==null?void 0:E.response)==null?void 0:y.data)==null?void 0:w.response)==null?void 0:S.message}`)}finally{c(l.filter(E=>E!==b))}},m=v.useMemo(()=>{let b=o?[...o]:[];return i!=="all"&&(b=b.filter(y=>y.connectionStatus===i)),p!==""&&(b=b.filter(y=>y.name.toLowerCase().includes(p.toLowerCase()))),b},[o,p,i]),x=[{value:"all",label:e("status.all")},{value:"close",label:e("status.closed")},{value:"connecting",label:e("status.connecting")},{value:"open",label:e("status.open")}];return u.jsxs("div",{className:"my-4 px-4",children:[u.jsxs("div",{className:"flex w-full items-center justify-between",children:[u.jsx("h2",{className:"text-lg",children:e("dashboard.title")}),u.jsxs("div",{className:"flex gap-2",children:[u.jsx(q,{variant:"outline",size:"icon",children:u.jsx(fj,{onClick:h,size:"20"})}),u.jsx(WQ,{resetTable:h})]})]}),u.jsxs("div",{className:"my-4 flex items-center justify-between gap-3 px-4",children:[u.jsx("div",{className:"flex-1",children:u.jsx(K,{placeholder:e("dashboard.search"),value:p,onChange:b=>f(b.target.value)})}),u.jsxs(Eo,{children:[u.jsx(To,{asChild:!0,children:u.jsxs(q,{variant:"secondary",children:[e("dashboard.status")," ",u.jsx(M3,{size:"15"})]})}),u.jsx(ps,{children:x.map(b=>u.jsx(GR,{checked:i===b.value,onCheckedChange:y=>{y&&d(b.value)},children:b.label},b.value))})]})]}),u.jsx("main",{className:"grid gap-6 sm:grid-cols-2 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4",children:m.length>0&&Array.isArray(o)&&o.map(b=>{var y,w;return u.jsxs(Ja,{children:[u.jsx(Qa,{children:u.jsxs(nd,{to:`/manager/instance/${b.id}/dashboard`,className:"flex w-full flex-row items-center justify-between gap-4",children:[u.jsx("h3",{className:"text-wrap font-semibold",children:b.name}),u.jsx(q,{variant:"ghost",size:"icon",children:u.jsx(Oi,{className:"card-icon",size:"20"})})]})}),u.jsxs(Za,{className:"flex-1 space-y-6",children:[u.jsx(GP,{token:b.token}),u.jsxs("div",{className:"flex w-full flex-wrap",children:[u.jsx("div",{className:"flex flex-1 gap-2",children:b.profileName&&u.jsxs(u.Fragment,{children:[u.jsx(Sg,{children:u.jsx(Cg,{src:b.profilePicUrl,alt:""})}),u.jsxs("div",{className:"space-y-1",children:[u.jsx("strong",{children:b.profileName}),u.jsx("p",{className:"text-sm text-muted-foreground",children:b.ownerJid&&b.ownerJid.split("@")[0]})]})]})}),u.jsxs("div",{className:"flex items-center justify-end gap-4 text-sm",children:[u.jsxs("div",{className:"flex flex-col items-center justify-center gap-1",children:[u.jsx(dj,{className:"text-muted-foreground",size:"20"}),u.jsx("span",{children:new Intl.NumberFormat("pt-BR").format(((y=b==null?void 0:b._count)==null?void 0:y.Contact)||0)})]}),u.jsxs("div",{className:"flex flex-col items-center justify-center gap-1",children:[u.jsx(ug,{className:"text-muted-foreground",size:"20"}),u.jsx("span",{children:new Intl.NumberFormat("pt-BR").format(((w=b==null?void 0:b._count)==null?void 0:w.Message)||0)})]})]})]})]}),u.jsxs(kg,{className:"justify-between",children:[u.jsx(WP,{status:b.connectionStatus}),u.jsx(q,{variant:"destructive",size:"sm",onClick:()=>n(b.name),disabled:l.includes(b.name),children:l.includes(b.name)?u.jsx("span",{children:e("button.deleting")}):u.jsx("span",{children:e("button.delete")})})]})]},b.id)})}),!!t&&u.jsx(Tt,{onOpenChange:()=>n(null),open:!0,children:u.jsxs(xt,{children:[u.jsx(TP,{}),u.jsx(wt,{children:e("modal.delete.title")}),u.jsx("p",{children:e("modal.delete.message",{instanceName:t})}),u.jsx(rn,{children:u.jsxs("div",{className:"flex items-center gap-4",children:[u.jsx(q,{onClick:()=>n(null),size:"sm",variant:"outline",children:e("button.cancel")}),u.jsx(q,{onClick:()=>g(t),variant:"destructive",children:e("button.delete")})]})})]})})]})}const{createElement:au,createContext:JQ,createRef:toe,forwardRef:uN,useCallback:ir,useContext:cN,useEffect:pi,useImperativeHandle:dN,useLayoutEffect:QQ,useMemo:ZQ,useRef:Yn,useState:Oc}=Nh,z1=Nh.useId,YQ=QQ,Hg=JQ(null);Hg.displayName="PanelGroupContext";const hi=YQ,XQ=typeof z1=="function"?z1:()=>null;let eZ=0;function Ow(e=null){const t=XQ(),n=Yn(e||t||null);return n.current===null&&(n.current=""+eZ++),e??n.current}function fN({children:e,className:t="",collapsedSize:n,collapsible:r,defaultSize:s,forwardedRef:o,id:a,maxSize:l,minSize:c,onCollapse:i,onExpand:d,onResize:p,order:f,style:h,tagName:g="div",...m}){const x=cN(Hg);if(x===null)throw Error("Panel components must be rendered within a PanelGroup container");const{collapsePanel:b,expandPanel:y,getPanelSize:w,getPanelStyle:S,groupId:E,isPanelCollapsed:C,reevaluatePanelConstraints:k,registerPanel:T,resizePanel:P,unregisterPanel:N}=x,U=Ow(a),I=Yn({callbacks:{onCollapse:i,onExpand:d,onResize:p},constraints:{collapsedSize:n,collapsible:r,defaultSize:s,maxSize:l,minSize:c},id:U,idIsFromProps:a!==void 0,order:f});Yn({didLogMissingDefaultSizeWarning:!1}),hi(()=>{const{callbacks:V,constraints:Q}=I.current,ee={...Q};I.current.id=U,I.current.idIsFromProps=a!==void 0,I.current.order=f,V.onCollapse=i,V.onExpand=d,V.onResize=p,Q.collapsedSize=n,Q.collapsible=r,Q.defaultSize=s,Q.maxSize=l,Q.minSize=c,(ee.collapsedSize!==Q.collapsedSize||ee.collapsible!==Q.collapsible||ee.maxSize!==Q.maxSize||ee.minSize!==Q.minSize)&&k(I.current,ee)}),hi(()=>{const V=I.current;return T(V),()=>{N(V)}},[f,U,T,N]),dN(o,()=>({collapse:()=>{b(I.current)},expand:V=>{y(I.current,V)},getId(){return U},getSize(){return w(I.current)},isCollapsed(){return C(I.current)},isExpanded(){return!C(I.current)},resize:V=>{P(I.current,V)}}),[b,y,w,C,U,P]);const Z=S(I.current,s);return au(g,{...m,children:e,className:t,id:a,style:{...Z,...h},"data-panel":"","data-panel-collapsible":r||void 0,"data-panel-group-id":E,"data-panel-id":U,"data-panel-size":parseFloat(""+Z.flexGrow).toFixed(1)})}const pN=uN((e,t)=>au(fN,{...e,forwardedRef:t}));fN.displayName="Panel";pN.displayName="forwardRef(Panel)";let bb=null,Xa=null;function tZ(e,t){if(t){const n=(t&yN)!==0,r=(t&bN)!==0,s=(t&xN)!==0,o=(t&wN)!==0;if(n)return s?"se-resize":o?"ne-resize":"e-resize";if(r)return s?"sw-resize":o?"nw-resize":"w-resize";if(s)return"s-resize";if(o)return"n-resize"}switch(e){case"horizontal":return"ew-resize";case"intersection":return"move";case"vertical":return"ns-resize"}}function nZ(){Xa!==null&&(document.head.removeChild(Xa),bb=null,Xa=null)}function hv(e,t){const n=tZ(e,t);bb!==n&&(bb=n,Xa===null&&(Xa=document.createElement("style"),document.head.appendChild(Xa)),Xa.innerHTML=`*{cursor: ${n}!important;}`)}function hN(e){return e.type==="keydown"}function gN(e){return e.type.startsWith("pointer")}function mN(e){return e.type.startsWith("mouse")}function Kg(e){if(gN(e)){if(e.isPrimary)return{x:e.clientX,y:e.clientY}}else if(mN(e))return{x:e.clientX,y:e.clientY};return{x:1/0,y:1/0}}function rZ(){if(typeof matchMedia=="function")return matchMedia("(pointer:coarse)").matches?"coarse":"fine"}function sZ(e,t,n){return e.xt.x&&e.yt.y}function oZ(e,t){if(e===t)throw new Error("Cannot compare node with itself");const n={a:H1(e),b:H1(t)};let r;for(;n.a.at(-1)===n.b.at(-1);)e=n.a.pop(),t=n.b.pop(),r=e;tt(r,"Stacking order can only be calculated for elements with a common ancestor");const s={a:V1(U1(n.a)),b:V1(U1(n.b))};if(s.a===s.b){const o=r.childNodes,a={a:n.a.at(-1),b:n.b.at(-1)};let l=o.length;for(;l--;){const c=o[l];if(c===a.a)return 1;if(c===a.b)return-1}}return Math.sign(s.a-s.b)}const aZ=/\b(?:position|zIndex|opacity|transform|webkitTransform|mixBlendMode|filter|webkitFilter|isolation)\b/;function iZ(e){var t;const n=getComputedStyle((t=vN(e))!==null&&t!==void 0?t:e).display;return n==="flex"||n==="inline-flex"}function lZ(e){const t=getComputedStyle(e);return!!(t.position==="fixed"||t.zIndex!=="auto"&&(t.position!=="static"||iZ(e))||+t.opacity<1||"transform"in t&&t.transform!=="none"||"webkitTransform"in t&&t.webkitTransform!=="none"||"mixBlendMode"in t&&t.mixBlendMode!=="normal"||"filter"in t&&t.filter!=="none"||"webkitFilter"in t&&t.webkitFilter!=="none"||"isolation"in t&&t.isolation==="isolate"||aZ.test(t.willChange)||t.webkitOverflowScrolling==="touch")}function U1(e){let t=e.length;for(;t--;){const n=e[t];if(tt(n,"Missing node"),lZ(n))return n}return null}function V1(e){return e&&Number(getComputedStyle(e).zIndex)||0}function H1(e){const t=[];for(;e;)t.push(e),e=vN(e);return t}function vN(e){const{parentNode:t}=e;return t&&t instanceof ShadowRoot?t.host:t}const yN=1,bN=2,xN=4,wN=8,uZ=rZ()==="coarse";let is=[],_d=!1,Ho=new Map,qg=new Map;const jd=new Set;function cZ(e,t,n,r,s){var o;const{ownerDocument:a}=t,l={direction:n,element:t,hitAreaMargins:r,setResizeHandlerState:s},c=(o=Ho.get(a))!==null&&o!==void 0?o:0;return Ho.set(a,c+1),jd.add(l),kh(),function(){var d;qg.delete(e),jd.delete(l);const p=(d=Ho.get(a))!==null&&d!==void 0?d:1;if(Ho.set(a,p-1),kh(),p===1&&Ho.delete(a),is.includes(l)){const f=is.indexOf(l);f>=0&&is.splice(f,1),Iw()}}}function K1(e){const{target:t}=e,{x:n,y:r}=Kg(e);_d=!0,Nw({target:t,x:n,y:r}),kh(),is.length>0&&(_h("down",e),e.preventDefault(),e.stopPropagation())}function nc(e){const{x:t,y:n}=Kg(e);if(e.buttons===0&&(_d=!1,_h("up",e)),!_d){const{target:r}=e;Nw({target:r,x:t,y:n})}_h("move",e),Iw(),is.length>0&&e.preventDefault()}function Zi(e){const{target:t}=e,{x:n,y:r}=Kg(e);qg.clear(),_d=!1,is.length>0&&e.preventDefault(),_h("up",e),Nw({target:t,x:n,y:r}),Iw(),kh()}function Nw({target:e,x:t,y:n}){is.splice(0);let r=null;e instanceof HTMLElement&&(r=e),jd.forEach(s=>{const{element:o,hitAreaMargins:a}=s,l=o.getBoundingClientRect(),{bottom:c,left:i,right:d,top:p}=l,f=uZ?a.coarse:a.fine;if(t>=i-f&&t<=d+f&&n>=p-f&&n<=c+f){if(r!==null&&o!==r&&!o.contains(r)&&!r.contains(o)&&oZ(r,o)>0){let g=r,m=!1;for(;g&&!g.contains(o);){if(sZ(g.getBoundingClientRect(),l)){m=!0;break}g=g.parentElement}if(m)return}is.push(s)}})}function gv(e,t){qg.set(e,t)}function Iw(){let e=!1,t=!1;is.forEach(r=>{const{direction:s}=r;s==="horizontal"?e=!0:t=!0});let n=0;qg.forEach(r=>{n|=r}),e&&t?hv("intersection",n):e?hv("horizontal",n):t?hv("vertical",n):nZ()}function kh(){Ho.forEach((e,t)=>{const{body:n}=t;n.removeEventListener("contextmenu",Zi),n.removeEventListener("pointerdown",K1),n.removeEventListener("pointerleave",nc),n.removeEventListener("pointermove",nc)}),window.removeEventListener("pointerup",Zi),window.removeEventListener("pointercancel",Zi),jd.size>0&&(_d?(is.length>0&&Ho.forEach((e,t)=>{const{body:n}=t;e>0&&(n.addEventListener("contextmenu",Zi),n.addEventListener("pointerleave",nc),n.addEventListener("pointermove",nc))}),window.addEventListener("pointerup",Zi),window.addEventListener("pointercancel",Zi)):Ho.forEach((e,t)=>{const{body:n}=t;e>0&&(n.addEventListener("pointerdown",K1,{capture:!0}),n.addEventListener("pointermove",nc))}))}function _h(e,t){jd.forEach(n=>{const{setResizeHandlerState:r}=n,s=is.includes(n);r(e,s,t)})}function tt(e,t){if(!e)throw console.error(t),Error(t)}const Dw=10;function Ri(e,t,n=Dw){return e.toFixed(n)===t.toFixed(n)?0:e>t?1:-1}function no(e,t,n=Dw){return Ri(e,t,n)===0}function dr(e,t,n){return Ri(e,t,n)===0}function dZ(e,t,n){if(e.length!==t.length)return!1;for(let r=0;r0&&(e=e<0?0-b:b)}}}{const p=e<0?l:c,f=n[p];tt(f,`No panel constraints found for index ${p}`);const{collapsedSize:h=0,collapsible:g,minSize:m=0}=f;if(g){const x=t[p];if(tt(x!=null,`Previous layout not found for panel index ${p}`),dr(x,m)){const b=x-h;Ri(b,Math.abs(e))>0&&(e=e<0?0-b:b)}}}}{const p=e<0?1:-1;let f=e<0?c:l,h=0;for(;;){const m=t[f];tt(m!=null,`Previous layout not found for panel index ${f}`);const b=yl({panelConstraints:n,panelIndex:f,size:100})-m;if(h+=b,f+=p,f<0||f>=n.length)break}const g=Math.min(Math.abs(e),Math.abs(h));e=e<0?0-g:g}{let f=e<0?l:c;for(;f>=0&&f=0))break;e<0?f--:f++}}if(dZ(s,a))return s;{const p=e<0?c:l,f=t[p];tt(f!=null,`Previous layout not found for panel index ${p}`);const h=f+i,g=yl({panelConstraints:n,panelIndex:p,size:h});if(a[p]=g,!dr(g,h)){let m=h-g,b=e<0?c:l;for(;b>=0&&b0?b--:b++}}}const d=a.reduce((p,f)=>f+p,0);return dr(d,100)?a:s}function fZ({layout:e,panelsArray:t,pivotIndices:n}){let r=0,s=100,o=0,a=0;const l=n[0];tt(l!=null,"No pivot index found"),t.forEach((p,f)=>{const{constraints:h}=p,{maxSize:g=100,minSize:m=0}=h;f===l?(r=m,s=g):(o+=m,a+=g)});const c=Math.min(s,100-o),i=Math.max(r,100-a),d=e[l];return{valueMax:c,valueMin:i,valueNow:d}}function Rd(e,t=document){return Array.from(t.querySelectorAll(`[data-panel-resize-handle-id][data-panel-group-id="${e}"]`))}function SN(e,t,n=document){const s=Rd(e,n).findIndex(o=>o.getAttribute("data-panel-resize-handle-id")===t);return s??null}function CN(e,t,n){const r=SN(e,t,n);return r!=null?[r,r+1]:[-1,-1]}function EN(e,t=document){var n;if(t instanceof HTMLElement&&(t==null||(n=t.dataset)===null||n===void 0?void 0:n.panelGroupId)==e)return t;const r=t.querySelector(`[data-panel-group][data-panel-group-id="${e}"]`);return r||null}function Wg(e,t=document){const n=t.querySelector(`[data-panel-resize-handle-id="${e}"]`);return n||null}function pZ(e,t,n,r=document){var s,o,a,l;const c=Wg(t,r),i=Rd(e,r),d=c?i.indexOf(c):-1,p=(s=(o=n[d])===null||o===void 0?void 0:o.id)!==null&&s!==void 0?s:null,f=(a=(l=n[d+1])===null||l===void 0?void 0:l.id)!==null&&a!==void 0?a:null;return[p,f]}function hZ({committedValuesRef:e,eagerValuesRef:t,groupId:n,layout:r,panelDataArray:s,panelGroupElement:o,setLayout:a}){Yn({didWarnAboutMissingResizeHandle:!1}),hi(()=>{if(!o)return;const l=Rd(n,o);for(let c=0;c{l.forEach((c,i)=>{c.removeAttribute("aria-controls"),c.removeAttribute("aria-valuemax"),c.removeAttribute("aria-valuemin"),c.removeAttribute("aria-valuenow")})}},[n,r,s,o]),pi(()=>{if(!o)return;const l=t.current;tt(l,"Eager values not found");const{panelDataArray:c}=l,i=EN(n,o);tt(i!=null,`No group found for id "${n}"`);const d=Rd(n,o);tt(d,`No resize handles found for group id "${n}"`);const p=d.map(f=>{const h=f.getAttribute("data-panel-resize-handle-id");tt(h,"Resize handle element has no handle id attribute");const[g,m]=pZ(n,h,c,o);if(g==null||m==null)return()=>{};const x=b=>{if(!b.defaultPrevented)switch(b.key){case"Enter":{b.preventDefault();const y=c.findIndex(w=>w.id===g);if(y>=0){const w=c[y];tt(w,`No panel data found for index ${y}`);const S=r[y],{collapsedSize:E=0,collapsible:C,minSize:k=0}=w.constraints;if(S!=null&&C){const T=gc({delta:dr(S,E)?k-E:E-S,initialLayout:r,panelConstraints:c.map(P=>P.constraints),pivotIndices:CN(n,h,o),prevLayout:r,trigger:"keyboard"});r!==T&&a(T)}}break}}};return f.addEventListener("keydown",x),()=>{f.removeEventListener("keydown",x)}});return()=>{p.forEach(f=>f())}},[o,e,t,n,r,s,a])}function q1(e,t){if(e.length!==t.length)return!1;for(let n=0;no.constraints);let r=0,s=100;for(let o=0;o{const o=e[s];tt(o,`Panel data not found for index ${s}`);const{callbacks:a,constraints:l,id:c}=o,{collapsedSize:i=0,collapsible:d}=l,p=n[c];if(p==null||r!==p){n[c]=r;const{onCollapse:f,onExpand:h,onResize:g}=a;g&&g(r,p),d&&(f||h)&&(h&&(p==null||no(p,i))&&!no(r,i)&&h(),f&&(p==null||!no(p,i))&&no(r,i)&&f())}})}function Vf(e,t){if(e.length!==t.length)return!1;for(let n=0;n{n!==null&&clearTimeout(n),n=setTimeout(()=>{e(...s)},t)}}function W1(e){try{if(typeof localStorage<"u")e.getItem=t=>localStorage.getItem(t),e.setItem=(t,n)=>{localStorage.setItem(t,n)};else throw new Error("localStorage not supported in this environment")}catch(t){console.error(t),e.getItem=()=>null,e.setItem=()=>{}}}function kN(e){return`react-resizable-panels:${e}`}function _N(e){return e.map(t=>{const{constraints:n,id:r,idIsFromProps:s,order:o}=t;return s?r:o?`${o}:${JSON.stringify(n)}`:JSON.stringify(n)}).sort((t,n)=>t.localeCompare(n)).join(",")}function jN(e,t){try{const n=kN(e),r=t.getItem(n);if(r){const s=JSON.parse(r);if(typeof s=="object"&&s!=null)return s}}catch{}return null}function xZ(e,t,n){var r,s;const o=(r=jN(e,n))!==null&&r!==void 0?r:{},a=_N(t);return(s=o[a])!==null&&s!==void 0?s:null}function wZ(e,t,n,r,s){var o;const a=kN(e),l=_N(t),c=(o=jN(e,s))!==null&&o!==void 0?o:{};c[l]={expandToSizes:Object.fromEntries(n.entries()),layout:r};try{s.setItem(a,JSON.stringify(c))}catch(i){console.error(i)}}function G1({layout:e,panelConstraints:t}){const n=[...e],r=n.reduce((o,a)=>o+a,0);if(n.length!==t.length)throw Error(`Invalid ${t.length} panel layout: ${n.map(o=>`${o}%`).join(", ")}`);if(!dr(r,100))for(let o=0;o(W1(mc),mc.getItem(e)),setItem:(e,t)=>{W1(mc),mc.setItem(e,t)}},J1={};function RN({autoSaveId:e=null,children:t,className:n="",direction:r,forwardedRef:s,id:o=null,onLayout:a=null,keyboardResizeBy:l=null,storage:c=mc,style:i,tagName:d="div",...p}){const f=Ow(o),h=Yn(null),[g,m]=Oc(null),[x,b]=Oc([]),y=Yn({}),w=Yn(new Map),S=Yn(0),E=Yn({autoSaveId:e,direction:r,dragState:g,id:f,keyboardResizeBy:l,onLayout:a,storage:c}),C=Yn({layout:x,panelDataArray:[],panelDataArrayChanged:!1});Yn({didLogIdAndOrderWarning:!1,didLogPanelConstraintsWarning:!1,prevPanelIds:[]}),dN(s,()=>({getId:()=>E.current.id,getLayout:()=>{const{layout:z}=C.current;return z},setLayout:z=>{const{onLayout:se}=E.current,{layout:ne,panelDataArray:ie}=C.current,oe=G1({layout:z,panelConstraints:ie.map(J=>J.constraints)});q1(ne,oe)||(b(oe),C.current.layout=oe,se&&se(oe),Yi(ie,oe,y.current))}}),[]),hi(()=>{E.current.autoSaveId=e,E.current.direction=r,E.current.dragState=g,E.current.id=f,E.current.onLayout=a,E.current.storage=c}),hZ({committedValuesRef:E,eagerValuesRef:C,groupId:f,layout:x,panelDataArray:C.current.panelDataArray,setLayout:b,panelGroupElement:h.current}),pi(()=>{const{panelDataArray:z}=C.current;if(e){if(x.length===0||x.length!==z.length)return;let se=J1[e];se==null&&(se=bZ(wZ,SZ),J1[e]=se);const ne=[...z],ie=new Map(w.current);se(e,ne,ie,x,c)}},[e,x,c]),pi(()=>{});const k=ir(z=>{const{onLayout:se}=E.current,{layout:ne,panelDataArray:ie}=C.current;if(z.constraints.collapsible){const oe=ie.map(Le=>Le.constraints),{collapsedSize:J=0,panelSize:Ce,pivotIndices:Pe}=Fa(ie,z,ne);if(tt(Ce!=null,`Panel size not found for panel "${z.id}"`),!no(Ce,J)){w.current.set(z.id,Ce);const Me=nl(ie,z)===ie.length-1?Ce-J:J-Ce,me=gc({delta:Me,initialLayout:ne,panelConstraints:oe,pivotIndices:Pe,prevLayout:ne,trigger:"imperative-api"});Vf(ne,me)||(b(me),C.current.layout=me,se&&se(me),Yi(ie,me,y.current))}}},[]),T=ir((z,se)=>{const{onLayout:ne}=E.current,{layout:ie,panelDataArray:oe}=C.current;if(z.constraints.collapsible){const J=oe.map(rt=>rt.constraints),{collapsedSize:Ce=0,panelSize:Pe=0,minSize:Le=0,pivotIndices:Me}=Fa(oe,z,ie),me=se??Le;if(no(Pe,Ce)){const rt=w.current.get(z.id),It=rt!=null&&rt>=me?rt:me,Wt=nl(oe,z)===oe.length-1?Pe-It:It-Pe,an=gc({delta:Wt,initialLayout:ie,panelConstraints:J,pivotIndices:Me,prevLayout:ie,trigger:"imperative-api"});Vf(ie,an)||(b(an),C.current.layout=an,ne&&ne(an),Yi(oe,an,y.current))}}},[]),P=ir(z=>{const{layout:se,panelDataArray:ne}=C.current,{panelSize:ie}=Fa(ne,z,se);return tt(ie!=null,`Panel size not found for panel "${z.id}"`),ie},[]),N=ir((z,se)=>{const{panelDataArray:ne}=C.current,ie=nl(ne,z);return yZ({defaultSize:se,dragState:g,layout:x,panelData:ne,panelIndex:ie})},[g,x]),U=ir(z=>{const{layout:se,panelDataArray:ne}=C.current,{collapsedSize:ie=0,collapsible:oe,panelSize:J}=Fa(ne,z,se);return tt(J!=null,`Panel size not found for panel "${z.id}"`),oe===!0&&no(J,ie)},[]),I=ir(z=>{const{layout:se,panelDataArray:ne}=C.current,{collapsedSize:ie=0,collapsible:oe,panelSize:J}=Fa(ne,z,se);return tt(J!=null,`Panel size not found for panel "${z.id}"`),!oe||Ri(J,ie)>0},[]),Z=ir(z=>{const{panelDataArray:se}=C.current;se.push(z),se.sort((ne,ie)=>{const oe=ne.order,J=ie.order;return oe==null&&J==null?0:oe==null?-1:J==null?1:oe-J}),C.current.panelDataArrayChanged=!0},[]);hi(()=>{if(C.current.panelDataArrayChanged){C.current.panelDataArrayChanged=!1;const{autoSaveId:z,onLayout:se,storage:ne}=E.current,{layout:ie,panelDataArray:oe}=C.current;let J=null;if(z){const Pe=xZ(z,oe,ne);Pe&&(w.current=new Map(Object.entries(Pe.expandToSizes)),J=Pe.layout)}J==null&&(J=vZ({panelDataArray:oe}));const Ce=G1({layout:J,panelConstraints:oe.map(Pe=>Pe.constraints)});q1(ie,Ce)||(b(Ce),C.current.layout=Ce,se&&se(Ce),Yi(oe,Ce,y.current))}}),hi(()=>{const z=C.current;return()=>{z.layout=[]}},[]);const V=ir(z=>function(ne){ne.preventDefault();const ie=h.current;if(!ie)return()=>null;const{direction:oe,dragState:J,id:Ce,keyboardResizeBy:Pe,onLayout:Le}=E.current,{layout:Me,panelDataArray:me}=C.current,{initialLayout:rt}=J??{},It=CN(Ce,z,ie);let Zt=mZ(ne,z,oe,J,Pe,ie);const Wt=oe==="horizontal";document.dir==="rtl"&&Wt&&(Zt=-Zt);const an=me.map(B=>B.constraints),j=gc({delta:Zt,initialLayout:rt??Me,panelConstraints:an,pivotIndices:It,prevLayout:Me,trigger:hN(ne)?"keyboard":"mouse-or-touch"}),D=!Vf(Me,j);(gN(ne)||mN(ne))&&S.current!=Zt&&(S.current=Zt,D?gv(z,0):Wt?gv(z,Zt<0?yN:bN):gv(z,Zt<0?xN:wN)),D&&(b(j),C.current.layout=j,Le&&Le(j),Yi(me,j,y.current))},[]),Q=ir((z,se)=>{const{onLayout:ne}=E.current,{layout:ie,panelDataArray:oe}=C.current,J=oe.map(rt=>rt.constraints),{panelSize:Ce,pivotIndices:Pe}=Fa(oe,z,ie);tt(Ce!=null,`Panel size not found for panel "${z.id}"`);const Me=nl(oe,z)===oe.length-1?Ce-se:se-Ce,me=gc({delta:Me,initialLayout:ie,panelConstraints:J,pivotIndices:Pe,prevLayout:ie,trigger:"imperative-api"});Vf(ie,me)||(b(me),C.current.layout=me,ne&&ne(me),Yi(oe,me,y.current))},[]),ee=ir((z,se)=>{const{layout:ne,panelDataArray:ie}=C.current,{collapsedSize:oe=0,collapsible:J}=se,{collapsedSize:Ce=0,collapsible:Pe,maxSize:Le=100,minSize:Me=0}=z.constraints,{panelSize:me}=Fa(ie,z,ne);me!=null&&(J&&Pe&&no(me,oe)?no(oe,Ce)||Q(z,Ce):meLe&&Q(z,Le))},[Q]),W=ir((z,se)=>{const{direction:ne}=E.current,{layout:ie}=C.current;if(!h.current)return;const oe=Wg(z,h.current);tt(oe,`Drag handle element not found for id "${z}"`);const J=TN(ne,se);m({dragHandleId:z,dragHandleRect:oe.getBoundingClientRect(),initialCursorPosition:J,initialLayout:ie})},[]),F=ir(()=>{m(null)},[]),A=ir(z=>{const{panelDataArray:se}=C.current,ne=nl(se,z);ne>=0&&(se.splice(ne,1),delete y.current[z.id],C.current.panelDataArrayChanged=!0)},[]),Y=ZQ(()=>({collapsePanel:k,direction:r,dragState:g,expandPanel:T,getPanelSize:P,getPanelStyle:N,groupId:f,isPanelCollapsed:U,isPanelExpanded:I,reevaluatePanelConstraints:ee,registerPanel:Z,registerResizeHandle:V,resizePanel:Q,startDragging:W,stopDragging:F,unregisterPanel:A,panelGroupElement:h.current}),[k,g,r,T,P,N,f,U,I,ee,Z,V,Q,W,F,A]),de={display:"flex",flexDirection:r==="horizontal"?"row":"column",height:"100%",overflow:"hidden",width:"100%"};return au(Hg.Provider,{value:Y},au(d,{...p,children:t,className:n,id:o,ref:h,style:{...de,...i},"data-panel-group":"","data-panel-group-direction":r,"data-panel-group-id":f}))}const PN=uN((e,t)=>au(RN,{...e,forwardedRef:t}));RN.displayName="PanelGroup";PN.displayName="forwardRef(PanelGroup)";function nl(e,t){return e.findIndex(n=>n===t||n.id===t.id)}function Fa(e,t,n){const r=nl(e,t),o=r===e.length-1?[r-1,r]:[r,r+1],a=n[r];return{...t.constraints,panelSize:a,pivotIndices:o}}function CZ({disabled:e,handleId:t,resizeHandler:n,panelGroupElement:r}){pi(()=>{if(e||n==null||r==null)return;const s=Wg(t,r);if(s==null)return;const o=a=>{if(!a.defaultPrevented)switch(a.key){case"ArrowDown":case"ArrowLeft":case"ArrowRight":case"ArrowUp":case"End":case"Home":{a.preventDefault(),n(a);break}case"F6":{a.preventDefault();const l=s.getAttribute("data-panel-group-id");tt(l,`No group element found for id "${l}"`);const c=Rd(l,r),i=SN(l,t,r);tt(i!==null,`No resize element found for id "${t}"`);const d=a.shiftKey?i>0?i-1:c.length-1:i+1{s.removeEventListener("keydown",o)}},[r,e,t,n])}function MN({children:e=null,className:t="",disabled:n=!1,hitAreaMargins:r,id:s,onBlur:o,onDragging:a,onFocus:l,style:c={},tabIndex:i=0,tagName:d="div",...p}){var f,h;const g=Yn(null),m=Yn({onDragging:a});pi(()=>{m.current.onDragging=a});const x=cN(Hg);if(x===null)throw Error("PanelResizeHandle components must be rendered within a PanelGroup container");const{direction:b,groupId:y,registerResizeHandle:w,startDragging:S,stopDragging:E,panelGroupElement:C}=x,k=Ow(s),[T,P]=Oc("inactive"),[N,U]=Oc(!1),[I,Z]=Oc(null),V=Yn({state:T});hi(()=>{V.current.state=T}),pi(()=>{if(n)Z(null);else{const F=w(k);Z(()=>F)}},[n,k,w]);const Q=(f=r==null?void 0:r.coarse)!==null&&f!==void 0?f:15,ee=(h=r==null?void 0:r.fine)!==null&&h!==void 0?h:5;return pi(()=>{if(n||I==null)return;const F=g.current;return tt(F,"Element ref not attached"),cZ(k,F,b,{coarse:Q,fine:ee},(Y,de,z)=>{if(de)switch(Y){case"down":{P("drag"),S(k,z);const{onDragging:se}=m.current;se&&se(!0);break}case"move":{const{state:se}=V.current;se!=="drag"&&P("hover"),I(z);break}case"up":{P("hover"),E();const{onDragging:se}=m.current;se&&se(!1);break}}else P("inactive")})},[Q,b,n,ee,w,k,I,S,E]),CZ({disabled:n,handleId:k,resizeHandler:I,panelGroupElement:C}),au(d,{...p,children:e,className:t,id:s,onBlur:()=>{U(!1),o==null||o()},onFocus:()=>{U(!0),l==null||l()},ref:g,role:"separator",style:{...{touchAction:"none",userSelect:"none"},...c},tabIndex:i,"data-panel-group-direction":b,"data-panel-group-id":y,"data-resize-handle":"","data-resize-handle-active":T==="drag"?"pointer":N?"keyboard":void 0,"data-resize-handle-state":T,"data-panel-resize-handle-enabled":!n,"data-panel-resize-handle-id":k})}MN.displayName="PanelResizeHandle";const Pu=({className:e,...t})=>u.jsx(PN,{className:ge("flex h-full w-full data-[panel-group-direction=vertical]:flex-col",e),...t}),Ur=pN,Mu=({withHandle:e,className:t,...n})=>u.jsx(MN,{className:ge("relative flex w-px items-center justify-center bg-border after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 after:bg-border focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:-translate-y-1/2 data-[panel-group-direction=vertical]:after:translate-x-0 [&[data-panel-group-direction=vertical]>div]:rotate-90",t),...n,children:e&&u.jsx("div",{className:"z-10 flex h-4 w-3 items-center justify-center rounded-sm border bg-border",children:u.jsx($3,{className:"h-2.5 w-2.5"})})});var Aw="Tabs",[EZ,noe]=Vr(Aw,[vg]),ON=vg(),[TZ,Fw]=EZ(Aw),NN=v.forwardRef((e,t)=>{const{__scopeTabs:n,value:r,onValueChange:s,defaultValue:o,orientation:a="horizontal",dir:l,activationMode:c="automatic",...i}=e,d=Gd(l),[p,f]=pa({prop:r,onChange:s,defaultProp:o});return u.jsx(TZ,{scope:n,baseId:os(),value:p,onValueChange:f,orientation:a,dir:d,activationMode:c,children:u.jsx(Ne.div,{dir:d,"data-orientation":a,...i,ref:t})})});NN.displayName=Aw;var IN="TabsList",DN=v.forwardRef((e,t)=>{const{__scopeTabs:n,loop:r=!0,...s}=e,o=Fw(IN,n),a=ON(n);return u.jsx(Gj,{asChild:!0,...a,orientation:o.orientation,dir:o.dir,loop:r,children:u.jsx(Ne.div,{role:"tablist","aria-orientation":o.orientation,...s,ref:t})})});DN.displayName=IN;var AN="TabsTrigger",FN=v.forwardRef((e,t)=>{const{__scopeTabs:n,value:r,disabled:s=!1,...o}=e,a=Fw(AN,n),l=ON(n),c=BN(a.baseId,r),i=zN(a.baseId,r),d=r===a.value;return u.jsx(Jj,{asChild:!0,...l,focusable:!s,active:d,children:u.jsx(Ne.button,{type:"button",role:"tab","aria-selected":d,"aria-controls":i,"data-state":d?"active":"inactive","data-disabled":s?"":void 0,disabled:s,id:c,...o,ref:t,onMouseDown:Se(e.onMouseDown,p=>{!s&&p.button===0&&p.ctrlKey===!1?a.onValueChange(r):p.preventDefault()}),onKeyDown:Se(e.onKeyDown,p=>{[" ","Enter"].includes(p.key)&&a.onValueChange(r)}),onFocus:Se(e.onFocus,()=>{const p=a.activationMode!=="manual";!d&&!s&&p&&a.onValueChange(r)})})})});FN.displayName=AN;var LN="TabsContent",$N=v.forwardRef((e,t)=>{const{__scopeTabs:n,value:r,forceMount:s,children:o,...a}=e,l=Fw(LN,n),c=BN(l.baseId,r),i=zN(l.baseId,r),d=r===l.value,p=v.useRef(d);return v.useEffect(()=>{const f=requestAnimationFrame(()=>p.current=!1);return()=>cancelAnimationFrame(f)},[]),u.jsx(or,{present:s||d,children:({present:f})=>u.jsx(Ne.div,{"data-state":d?"active":"inactive","data-orientation":l.orientation,role:"tabpanel","aria-labelledby":c,hidden:!f,id:i,tabIndex:0,...a,ref:t,style:{...e.style,animationDuration:p.current?"0s":void 0},children:f&&o})})});$N.displayName=LN;function BN(e,t){return`${e}-trigger-${t}`}function zN(e,t){return`${e}-content-${t}`}var kZ=NN,UN=DN,VN=FN,HN=$N;const _Z=kZ,KN=v.forwardRef(({className:e,...t},n)=>u.jsx(UN,{ref:n,className:ge("inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",e),...t}));KN.displayName=UN.displayName;const xb=v.forwardRef(({className:e,...t},n)=>u.jsx(VN,{ref:n,className:ge("inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",e),...t}));xb.displayName=VN.displayName;const wb=v.forwardRef(({className:e,...t},n)=>u.jsx(HN,{ref:n,className:ge("mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",e),...t}));wb.displayName=HN.displayName;const jZ=e=>["chats","findChats",JSON.stringify(e)],RZ=async({instanceName:e})=>(await he.post(`/chat/findChats/${e}`,{where:{}})).data,PZ=e=>{const{instanceName:t,...n}=e;return lt({...n,queryKey:jZ({instanceName:t}),queryFn:()=>RZ({instanceName:t}),enabled:!!t})};function Ou(e){const t=o=>typeof window<"u"?window.matchMedia(o).matches:!1,[n,r]=v.useState(t(e));function s(){r(t(e))}return v.useEffect(()=>{const o=window.matchMedia(e);return s(),o.addListener?o.addListener(s):o.addEventListener("change",s),()=>{o.removeListener?o.removeListener(s):o.removeEventListener("change",s)}},[e]),n}const Ml=v.forwardRef(({className:e,...t},n)=>u.jsx("textarea",{className:ge("flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",e),ref:n,...t}));Ml.displayName="Textarea";const MZ=e=>["chats","findChats",JSON.stringify(e)],OZ=async({instanceName:e,remoteJid:t})=>{const n=await he.post(`/chat/findChats/${e}`,{where:{remoteJid:t}});return Array.isArray(n.data)?n.data[0]:n.data},NZ=e=>{const{instanceName:t,remoteJid:n,...r}=e;return lt({...r,queryKey:MZ({instanceName:t,remoteJid:n}),queryFn:()=>OZ({instanceName:t,remoteJid:n}),enabled:!!t&&!!n})},IZ=e=>["chats","findMessages",JSON.stringify(e)],DZ=async({instanceName:e,remoteJid:t})=>{var r,s;const n=await he.post(`/chat/findMessages/${e}`,{where:{key:{remoteJid:t}}});return(s=(r=n.data)==null?void 0:r.messages)!=null&&s.records?n.data.messages.records:n.data},AZ=e=>{const{instanceName:t,remoteJid:n,...r}=e;return lt({...r,queryKey:IZ({instanceName:t,remoteJid:n}),queryFn:()=>DZ({instanceName:t,remoteJid:n}),enabled:!!t&&!!n})};function FZ({textareaRef:e,handleTextareaChange:t,textareaHeight:n,lastMessageRef:r,scrollToBottom:s}){const{instance:o}=nt(),{remoteJid:a}=So(),{data:l}=NZ({remoteJid:a,instanceName:o==null?void 0:o.name}),{data:c,isSuccess:i}=AZ({remoteJid:a,instanceName:o==null?void 0:o.name});v.useEffect(()=>{i&&c&&s()},[i,c,s]);const d=f=>u.jsx("div",{className:"bubble-right",children:u.jsx("div",{className:"flex items-start gap-4 self-end",children:u.jsx("div",{className:"grid gap-1",children:u.jsx("div",{className:"prose text-muted-foreground",children:u.jsx("div",{className:"bubble",children:JSON.stringify(f.message)})})})})}),p=f=>u.jsx("div",{className:"bubble-left",children:u.jsx("div",{className:"flex items-start gap-4",children:u.jsx("div",{className:"grid gap-1",children:u.jsx("div",{className:"prose text-muted-foreground",children:u.jsx("div",{className:"bubble",children:JSON.stringify(f.message)})})})})});return u.jsxs("div",{className:"flex min-h-screen flex-col",children:[u.jsx("div",{className:"sticky top-0 p-2",children:u.jsxs(nw,{children:[u.jsx(rw,{asChild:!0,children:u.jsxs(q,{variant:"ghost",className:"h-10 gap-1 rounded-xl px-3 text-lg data-[state=open]:bg-muted",children:[(l==null?void 0:l.pushName)||(l==null?void 0:l.remoteJid.split("@")[0]),u.jsx(lg,{className:"h-4 w-4 text-muted-foreground"})]})}),u.jsxs(ps,{align:"start",className:"max-w-[300px]",children:[u.jsxs(ft,{className:"items-start gap-2",children:[u.jsx(W3,{className:"mr-2 h-4 w-4 shrink-0 translate-y-1"}),u.jsxs("div",{children:[u.jsx("div",{className:"font-medium",children:"GPT-4"}),u.jsx("div",{className:"text-muted-foreground/80",children:"With DALL-E, browsing and analysis. Limit 40 messages / 3 hours"})]})]}),u.jsx(Pa,{}),u.jsxs(ft,{className:"items-start gap-2",children:[u.jsx(pj,{className:"mr-2 h-4 w-4 shrink-0 translate-y-1"}),u.jsxs("div",{children:[u.jsx("div",{className:"font-medium",children:"GPT-3"}),u.jsx("div",{className:"text-muted-foreground/80",children:"Great for everyday tasks"})]})]})]})]})}),u.jsxs("div",{className:"message-container mx-auto flex max-w-4xl flex-1 flex-col gap-8 overflow-y-auto px-4",children:[c==null?void 0:c.map(f=>f.key.fromMe?d(f):p(f)),u.jsx("div",{ref:r})]}),u.jsx("div",{className:"sticky bottom-0 mx-auto flex w-full max-w-2xl flex-col gap-1.5 bg-background px-4 py-2",children:u.jsxs("div",{className:"input-message relative",children:[u.jsxs(q,{type:"button",size:"icon",className:"absolute bottom-3 left-3 h-8 w-8 rounded-full bg-transparent text-white hover:bg-transparent",children:[u.jsx(q3,{className:"h-4 w-4 text-white"}),u.jsx("span",{className:"sr-only",children:"Anexar"})]}),u.jsx(Ml,{placeholder:"Enviar mensagem...",name:"message",id:"message",rows:1,ref:e,onChange:t,style:{height:n},className:"max-h-[240px] min-h-[48px] resize-none rounded-3xl border border-none p-4 pl-12 pr-16 shadow-sm"}),u.jsxs(q,{type:"submit",size:"icon",className:"absolute bottom-3 right-3 h-8 w-8 rounded-full",children:[u.jsx(j3,{className:"h-4 w-4"}),u.jsx("span",{className:"sr-only",children:"Enviar"})]})]})})]})}function Q1(){const e=Ou("(min-width: 768px)"),t=v.useRef(null),[n]=v.useState("auto"),r=v.useRef(null),{instance:s}=nt(),{data:o,isSuccess:a}=PZ({instanceName:s==null?void 0:s.name}),{instanceId:l,remoteJid:c}=So(),i=An(),d=v.useCallback(()=>{t.current&&t.current.scrollIntoView({})},[]),p=()=>{if(r.current){r.current.style.height="auto";const h=r.current.scrollHeight,m=parseInt(getComputedStyle(r.current).lineHeight)*10;r.current.style.height=`${Math.min(h,m)}px`}};v.useEffect(()=>{a&&d()},[a,d]);const f=h=>{i(`/manager/instance/${l}/chat/${h}`)};return u.jsxs(Pu,{direction:e?"horizontal":"vertical",children:[u.jsx(Ur,{defaultSize:20,children:u.jsxs("div",{className:"hidden flex-col gap-2 bg-background text-foreground md:flex",children:[u.jsx("div",{className:"sticky top-0 p-2",children:u.jsxs(q,{variant:"ghost",className:"w-full justify-start gap-2 px-2 text-left",children:[u.jsx("div",{className:"flex h-7 w-7 items-center justify-center rounded-full",children:u.jsx(ug,{className:"h-4 w-4"})}),u.jsx("div",{className:"grow overflow-hidden text-ellipsis whitespace-nowrap text-sm",children:"Chat"}),u.jsx(Ni,{className:"h-4 w-4"})]})}),u.jsxs(_Z,{defaultValue:"contacts",children:[u.jsxs(KN,{className:"tabs-chat",children:[u.jsx(xb,{value:"contacts",children:"Contatos"}),u.jsx(xb,{value:"groups",children:"Grupos"})]}),u.jsx(wb,{value:"contacts",children:u.jsx("div",{className:"flex-1 overflow-auto",children:u.jsxs("div",{className:"grid gap-1 p-2 text-foreground",children:[u.jsx("div",{className:"px-2 text-xs font-medium text-muted-foreground",children:"Contatos"}),o==null?void 0:o.map(h=>h.remoteJid.includes("@s.whatsapp.net")&&u.jsxs(nd,{to:"#",onClick:()=>f(h.remoteJid),className:`chat-item flex items-center overflow-hidden truncate whitespace-nowrap rounded-md border-b border-gray-600/50 p-2 text-sm transition-colors hover:bg-muted/50 ${c===h.remoteJid?"active":""}`,children:[u.jsx("span",{className:"chat-avatar mr-2",children:u.jsx("img",{src:h.profilePicUrl||"https://via.placeholder.com/150",alt:"Avatar",className:"h-8 w-8 rounded-full"})}),u.jsxs("div",{className:"min-w-0 flex-1",children:[u.jsx("span",{className:"chat-title block font-medium",children:h.pushName}),u.jsx("span",{className:"chat-description block text-xs text-gray-500",children:h.remoteJid.split("@")[0]})]})]},h.id))]})})}),u.jsx(wb,{value:"groups",children:u.jsx("div",{className:"flex-1 overflow-auto",children:u.jsx("div",{className:"grid gap-1 p-2 text-foreground",children:o==null?void 0:o.map(h=>h.remoteJid.includes("@g.us")&&u.jsxs(nd,{to:"#",onClick:()=>f(h.remoteJid),className:`chat-item flex items-center overflow-hidden truncate whitespace-nowrap rounded-md border-b border-gray-600/50 p-2 text-sm transition-colors hover:bg-muted/50 ${c===h.remoteJid?"active":""}`,children:[u.jsx("span",{className:"chat-avatar mr-2",children:u.jsx("img",{src:h.profilePicUrl||"https://via.placeholder.com/150",alt:"Avatar",className:"h-8 w-8 rounded-full"})}),u.jsxs("div",{className:"min-w-0 flex-1",children:[u.jsx("span",{className:"chat-title block font-medium",children:h.pushName}),u.jsx("span",{className:"chat-description block text-xs text-gray-500",children:h.remoteJid})]})]},h.id))})})})]})]})}),u.jsx(Mu,{withHandle:!0,className:"border border-black"}),u.jsx(Ur,{children:c&&u.jsx(FZ,{textareaRef:r,handleTextareaChange:p,textareaHeight:n,lastMessageRef:t,scrollToBottom:d})})]})}const LZ=e=>["chatwoot","fetchChatwoot",JSON.stringify(e)],$Z=async({instanceName:e,token:t})=>(await he.get(`/chatwoot/find/${e}`,{headers:{apiKey:t}})).data,BZ=e=>{const{instanceName:t,token:n,...r}=e;return lt({...r,queryKey:LZ({instanceName:t,token:n}),queryFn:()=>$Z({instanceName:t,token:n}),enabled:!!t})},zZ=async({instanceName:e,token:t,data:n})=>(await he.post(`/chatwoot/set/${e}`,n,{headers:{apikey:t}})).data;function UZ(){return{createChatwoot:Ye(zZ,{invalidateKeys:[["chatwoot","fetchChatwoot"]]})}}const Hf=_.string().optional().transform(e=>e===""?void 0:e),VZ=_.object({enabled:_.boolean(),accountId:_.string(),token:_.string(),url:_.string(),signMsg:_.boolean().optional(),signDelimiter:Hf,nameInbox:Hf,organization:Hf,logo:Hf,reopenConversation:_.boolean().optional(),conversationPending:_.boolean().optional(),mergeBrazilContacts:_.boolean().optional(),importContacts:_.boolean().optional(),importMessages:_.boolean().optional(),daysLimitImportMessages:_.coerce.number().optional(),autoCreate:_.boolean(),ignoreJids:_.array(_.string()).default([])});function HZ(){const{t:e}=ze(),{instance:t}=nt(),[,n]=v.useState(!1),{createChatwoot:r}=UZ(),{data:s}=BZ({instanceName:t==null?void 0:t.name,token:t==null?void 0:t.token}),o=sn({resolver:on(VZ),defaultValues:{enabled:!0,accountId:"",token:"",url:"",signMsg:!0,signDelimiter:"\\n",nameInbox:"",organization:"",logo:"",reopenConversation:!0,conversationPending:!1,mergeBrazilContacts:!0,importContacts:!1,importMessages:!1,daysLimitImportMessages:7,autoCreate:!0,ignoreJids:[]}});v.useEffect(()=>{if(s){o.setValue("ignoreJids",s.ignoreJids||[]);const l={enabled:s.enabled,accountId:s.accountId,token:s.token,url:s.url,signMsg:s.signMsg||!1,signDelimiter:s.signDelimiter||"\\n",nameInbox:s.nameInbox||"",organization:s.organization||"",logo:s.logo||"",reopenConversation:s.reopenConversation||!1,conversationPending:s.conversationPending||!1,mergeBrazilContacts:s.mergeBrazilContacts||!1,importContacts:s.importContacts||!1,importMessages:s.importMessages||!1,daysLimitImportMessages:s.daysLimitImportMessages||7,autoCreate:s.autoCreate||!1,ignoreJids:s.ignoreJids};o.reset(l)}},[s,o]);const a=async l=>{if(!t)return;n(!0);const c={enabled:l.enabled,accountId:l.accountId,token:l.token,url:l.url,signMsg:l.signMsg||!1,signDelimiter:l.signDelimiter||"\\n",nameInbox:l.nameInbox||"",organization:l.organization||"",logo:l.logo||"",reopenConversation:l.reopenConversation||!1,conversationPending:l.conversationPending||!1,mergeBrazilContacts:l.mergeBrazilContacts||!1,importContacts:l.importContacts||!1,importMessages:l.importMessages||!1,daysLimitImportMessages:l.daysLimitImportMessages||7,autoCreate:l.autoCreate,ignoreJids:l.ignoreJids};await r({instanceName:t.name,token:t.token,data:c},{onSuccess:()=>{X.success(e("chatwoot.toast.success"))},onError:i=>{var d,p,f;console.error(e("chatwoot.toast.error"),i),A4(i)?X.error(`Error: ${(f=(p=(d=i==null?void 0:i.response)==null?void 0:d.data)==null?void 0:p.response)==null?void 0:f.message}`):X.error(e("chatwoot.toast.error"))},onSettled:()=>{n(!1)}})};return u.jsx(u.Fragment,{children:u.jsx(Na,{...o,children:u.jsxs("form",{onSubmit:o.handleSubmit(a),className:"w-full space-y-6",children:[u.jsxs("div",{children:[u.jsx("h3",{className:"mb-1 text-lg font-medium",children:e("chatwoot.title")}),u.jsx(Ra,{className:"my-4"}),u.jsxs("div",{className:"mx-4 space-y-2 divide-y [&>*]:px-4 [&>*]:py-2",children:[u.jsx(ke,{name:"enabled",label:e("chatwoot.form.enabled.label"),className:"w-full justify-between",helper:e("chatwoot.form.enabled.description")}),u.jsx(G,{name:"url",label:e("chatwoot.form.url.label"),children:u.jsx(K,{})}),u.jsx(G,{name:"accountId",label:e("chatwoot.form.accountId.label"),children:u.jsx(K,{})}),u.jsx(G,{name:"token",label:e("chatwoot.form.token.label"),children:u.jsx(K,{type:"password"})}),u.jsx(ke,{name:"signMsg",label:e("chatwoot.form.signMsg.label"),className:"w-full justify-between",helper:e("chatwoot.form.signMsg.description")}),u.jsx(G,{name:"signDelimiter",label:e("chatwoot.form.signDelimiter.label"),children:u.jsx(K,{})}),u.jsx(G,{name:"nameInbox",label:e("chatwoot.form.nameInbox.label"),children:u.jsx(K,{})}),u.jsx(G,{name:"organization",label:e("chatwoot.form.organization.label"),children:u.jsx(K,{})}),u.jsx(G,{name:"logo",label:e("chatwoot.form.logo.label"),children:u.jsx(K,{})}),u.jsx(ke,{name:"conversationPending",label:e("chatwoot.form.conversationPending.label"),className:"w-full justify-between",helper:e("chatwoot.form.conversationPending.description")}),u.jsx(ke,{name:"reopenConversation",label:e("chatwoot.form.reopenConversation.label"),className:"w-full justify-between",helper:e("chatwoot.form.reopenConversation.description")}),u.jsx(ke,{name:"importContacts",label:e("chatwoot.form.importContacts.label"),className:"w-full justify-between",helper:e("chatwoot.form.importContacts.description")}),u.jsx(ke,{name:"importMessages",label:e("chatwoot.form.importMessages.label"),className:"w-full justify-between",helper:e("chatwoot.form.importMessages.description")}),u.jsx(G,{name:"daysLimitImportMessages",label:e("chatwoot.form.daysLimitImportMessages.label"),children:u.jsx(K,{type:"number"})}),u.jsx(Ru,{name:"ignoreJids",label:e("chatwoot.form.ignoreJids.label"),placeholder:e("chatwoot.form.ignoreJids.placeholder")}),u.jsx(ke,{name:"autoCreate",label:e("chatwoot.form.autoCreate.label"),className:"w-full justify-between",helper:e("chatwoot.form.autoCreate.description")})]})]}),u.jsx("div",{className:"mx-4 flex justify-end",children:u.jsx(q,{type:"submit",children:e("chatwoot.button.save")})})]})})})}var Gg={},qN={exports:{}},KZ="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED",qZ=KZ,WZ=qZ;function WN(){}function GN(){}GN.resetWarningCache=WN;var GZ=function(){function e(r,s,o,a,l,c){if(c!==WZ){var i=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw i.name="Invariant Violation",i}}e.isRequired=e;function t(){return e}var n={array:e,bigint:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:GN,resetWarningCache:WN};return n.PropTypes=n,n};qN.exports=GZ();var JN=qN.exports,QN={L:1,M:0,Q:3,H:2},ZN={MODE_NUMBER:1,MODE_ALPHA_NUM:2,MODE_8BIT_BYTE:4,MODE_KANJI:8},JZ=ZN;function YN(e){this.mode=JZ.MODE_8BIT_BYTE,this.data=e}YN.prototype={getLength:function(e){return this.data.length},write:function(e){for(var t=0;t>>7-e%8&1)==1},put:function(e,t){for(var n=0;n>>t-n-1&1)==1)},getLengthInBits:function(){return this.length},putBit:function(e){var t=Math.floor(this.length/8);this.buffer.length<=t&&this.buffer.push(0),e&&(this.buffer[t]|=128>>>this.length%8),this.length++}};var YZ=XN,Xr={glog:function(e){if(e<1)throw new Error("glog("+e+")");return Xr.LOG_TABLE[e]},gexp:function(e){for(;e<0;)e+=255;for(;e>=256;)e-=255;return Xr.EXP_TABLE[e]},EXP_TABLE:new Array(256),LOG_TABLE:new Array(256)};for(var Cn=0;Cn<8;Cn++)Xr.EXP_TABLE[Cn]=1<=0;)t^=wn.G15<=0;)t^=wn.G18<>>=1;return t},getPatternPosition:function(e){return wn.PATTERN_POSITION_TABLE[e-1]},getMask:function(e,t,n){switch(e){case Do.PATTERN000:return(t+n)%2==0;case Do.PATTERN001:return t%2==0;case Do.PATTERN010:return n%3==0;case Do.PATTERN011:return(t+n)%3==0;case Do.PATTERN100:return(Math.floor(t/2)+Math.floor(n/3))%2==0;case Do.PATTERN101:return t*n%2+t*n%3==0;case Do.PATTERN110:return(t*n%2+t*n%3)%2==0;case Do.PATTERN111:return(t*n%3+(t+n)%2)%2==0;default:throw new Error("bad maskPattern:"+e)}},getErrorCorrectPolynomial:function(e){for(var t=new Z1([1],0),n=0;n5&&(n+=3+o-5)}for(var r=0;r=7&&this.setupTypeNumber(e),this.dataCache==null&&(this.dataCache=Ns.createData(this.typeNumber,this.errorCorrectLevel,this.dataList)),this.mapData(this.dataCache,t)};kr.setupPositionProbePattern=function(e,t){for(var n=-1;n<=7;n++)if(!(e+n<=-1||this.moduleCount<=e+n))for(var r=-1;r<=7;r++)t+r<=-1||this.moduleCount<=t+r||(0<=n&&n<=6&&(r==0||r==6)||0<=r&&r<=6&&(n==0||n==6)||2<=n&&n<=4&&2<=r&&r<=4?this.modules[e+n][t+r]=!0:this.modules[e+n][t+r]=!1)};kr.getBestMaskPattern=function(){for(var e=0,t=0,n=0;n<8;n++){this.makeImpl(!0,n);var r=Da.getLostPoint(this);(n==0||e>r)&&(e=r,t=n)}return t};kr.createMovieClip=function(e,t,n){var r=e.createEmptyMovieClip(t,n),s=1;this.make();for(var o=0;o>n&1)==1;this.modules[Math.floor(n/3)][n%3+this.moduleCount-8-3]=r}for(var n=0;n<18;n++){var r=!e&&(t>>n&1)==1;this.modules[n%3+this.moduleCount-8-3][Math.floor(n/3)]=r}};kr.setupTypeInfo=function(e,t){for(var n=this.errorCorrectLevel<<3|t,r=Da.getBCHTypeInfo(n),s=0;s<15;s++){var o=!e&&(r>>s&1)==1;s<6?this.modules[s][8]=o:s<8?this.modules[s+1][8]=o:this.modules[this.moduleCount-15+s][8]=o}for(var s=0;s<15;s++){var o=!e&&(r>>s&1)==1;s<8?this.modules[8][this.moduleCount-s-1]=o:s<9?this.modules[8][15-s-1+1]=o:this.modules[8][15-s-1]=o}this.modules[this.moduleCount-8][8]=!e};kr.mapData=function(e,t){for(var n=-1,r=this.moduleCount-1,s=7,o=0,a=this.moduleCount-1;a>0;a-=2)for(a==6&&a--;;){for(var l=0;l<2;l++)if(this.modules[r][a-l]==null){var c=!1;o>>s&1)==1);var i=Da.getMask(t,r,a-l);i&&(c=!c),this.modules[r][a-l]=c,s--,s==-1&&(o++,s=7)}if(r+=n,r<0||this.moduleCount<=r){r-=n,n=-n;break}}};Ns.PAD0=236;Ns.PAD1=17;Ns.createData=function(e,t,n){for(var r=nI.getRSBlocks(e,t),s=new rI,o=0;ol*8)throw new Error("code length overflow. ("+s.getLengthInBits()+">"+l*8+")");for(s.getLengthInBits()+4<=l*8&&s.put(0,4);s.getLengthInBits()%8!=0;)s.putBit(!1);for(;!(s.getLengthInBits()>=l*8||(s.put(Ns.PAD0,8),s.getLengthInBits()>=l*8));)s.put(Ns.PAD1,8);return Ns.createBytes(s,r)};Ns.createBytes=function(e,t){for(var n=0,r=0,s=0,o=new Array(t.length),a=new Array(t.length),l=0;l=0?h.get(g):0}}for(var m=0,d=0;d=0||Object.prototype.hasOwnProperty.call(e,r)&&(n[r]=e[r]);return n}var iY={bgColor:Pr.default.oneOfType([Pr.default.object,Pr.default.string]).isRequired,bgD:Pr.default.string.isRequired,fgColor:Pr.default.oneOfType([Pr.default.object,Pr.default.string]).isRequired,fgD:Pr.default.string.isRequired,size:Pr.default.number.isRequired,title:Pr.default.string,viewBoxSize:Pr.default.number.isRequired,xmlns:Pr.default.string},$w=(0,sI.forwardRef)(function(e,t){var n=e.bgColor,r=e.bgD,s=e.fgD,o=e.fgColor,a=e.size,l=e.title,c=e.viewBoxSize,i=e.xmlns,d=i===void 0?"http://www.w3.org/2000/svg":i,p=aY(e,["bgColor","bgD","fgD","fgColor","size","title","viewBoxSize","xmlns"]);return qf.default.createElement("svg",sY({},p,{height:a,ref:t,viewBox:"0 0 "+c+" "+c,width:a,xmlns:d}),l?qf.default.createElement("title",null,l):null,qf.default.createElement("path",{d:r,fill:n}),qf.default.createElement("path",{d:s,fill:o}))});$w.displayName="QRCodeSvg";$w.propTypes=iY;Lw.default=$w;Object.defineProperty(Gg,"__esModule",{value:!0});Gg.QRCode=void 0;var lY=Object.assign||function(e){for(var t=1;t=0||Object.prototype.hasOwnProperty.call(e,r)&&(n[r]=e[r]);return n}var yY={bgColor:Gs.default.oneOfType([Gs.default.object,Gs.default.string]),fgColor:Gs.default.oneOfType([Gs.default.object,Gs.default.string]),level:Gs.default.string,size:Gs.default.number,value:Gs.default.string.isRequired},Jg=(0,aI.forwardRef)(function(e,t){var n=e.bgColor,r=n===void 0?"#FFFFFF":n,s=e.fgColor,o=s===void 0?"#000000":s,a=e.level,l=a===void 0?"L":a,c=e.size,i=c===void 0?256:c,d=e.value,p=vY(e,["bgColor","fgColor","level","size","value"]),f=new pY.default(-1,dY.default[l]);f.addData(d),f.make();var h=f.modules;return hY.default.createElement(mY.default,lY({},p,{bgColor:r,bgD:h.map(function(g,m){return g.map(function(x,b){return x?"":"M "+b+" "+m+" l 1 0 0 1 -1 0 Z"}).join(" ")}).join(" "),fgColor:o,fgD:h.map(function(g,m){return g.map(function(x,b){return x?"M "+b+" "+m+" l 1 0 0 1 -1 0 Z":""}).join(" ")}).join(" "),ref:t,size:i,viewBoxSize:h.length}))});Gg.QRCode=Jg;Jg.displayName="QRCode";Jg.propTypes=yY;var bY=Gg.default=Jg;const xY=ig("relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7 space-y-1 [&_strong]:text-foreground",{variants:{variant:{default:"border-zinc-500/20 bg-zinc-50/50 dark:border-zinc-500/30 dark:bg-zinc-500/10 text-zinc-900 dark:text-zinc-300 [&>svg]:text-zinc-400 dark:[&>svg]:text-zinc-300",destructive:"border-red-500/20 bg-red-50/50 dark:border-red-500/30 dark:bg-red-500/10 text-red-900 dark:text-red-200 [&>svg]:text-red-600 dark:[&>svg]:text-red-400/80",warning:"border-amber-500/20 bg-amber-50/50 dark:border-amber-500/30 dark:bg-amber-500/10 text-amber-900 dark:text-amber-200 [&>svg]:text-amber-500",info:"border-sky-500/20 bg-sky-50/50 dark:border-sky-500/30 dark:bg-sky-500/10 text-sky-900 dark:text-sky-200 [&>svg]:text-sky-500",success:"border-emerald-500/20 bg-emerald-50/50 dark:border-emerald-500/30 dark:bg-emerald-500/10 text-emerald-900 dark:text-emerald-200 [&>svg]:text-emerald-600 dark:[&>svg]:text-emerald-400/80"}},defaultVariants:{variant:"default"}}),iI=v.forwardRef(({className:e,variant:t,...n},r)=>u.jsx("div",{ref:r,role:"alert",className:ge(xY({variant:t}),e),...n}));iI.displayName="Alert";const lI=v.forwardRef(({className:e,...t},n)=>u.jsx("h5",{ref:n,className:ge("font-medium leading-none tracking-tight",e),...t}));lI.displayName="AlertTitle";const wY=v.forwardRef(({className:e,...t},n)=>u.jsx("div",{ref:n,className:ge("text-sm [&_p]:leading-relaxed",e),...t}));wY.displayName="AlertDescription";const wr=({size:e=45,className:t,...n})=>u.jsx("div",{style:{display:"flex",justifyContent:"center",alignItems:"center",height:"100vh"},children:u.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",width:e,height:e,...n,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:ge("animate-spin",t),children:u.jsx("path",{d:"M21 12a9 9 0 1 1-6.219-8.56"})})});function SY(){const{t:e,i18n:t}=ze(),n=new Intl.NumberFormat(t.language),[r,s]=v.useState(null),[o,a]=v.useState(""),l=Fs(rs.TOKEN),{theme:c}=R_(),{connect:i,logout:d,restart:p}=_g(),{instance:f,reloadInstance:h}=nt(),g=async()=>{await h()},m=async E=>{try{await p(E),await h()}catch(C){console.error("Error:",C)}},x=async E=>{try{await d(E),await h()}catch(C){console.error("Error:",C)}},b=async(E,C)=>{try{if(s(null),!l){console.error("Token not found.");return}if(C){const k=await i({instanceName:E,token:l,number:f==null?void 0:f.number});a(k.pairingCode)}else{const k=await i({instanceName:E,token:l});s(k.code)}}catch(k){console.error("Error:",k)}},y=async()=>{s(null),a(""),await h()},w=v.useMemo(()=>{var E,C,k;return f?{contacts:((E=f._count)==null?void 0:E.Contact)||0,chats:((C=f._count)==null?void 0:C.Chat)||0,messages:((k=f._count)==null?void 0:k.Message)||0}:{contacts:0,chats:0,messages:0}},[f]),S=v.useMemo(()=>c==="dark"?"#fff":c==="light"?"#000":"#189d68",[c]);return f?u.jsxs("main",{className:"flex flex-col gap-8",children:[u.jsx("section",{children:u.jsxs(Ja,{children:[u.jsx(Qa,{children:u.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-4",children:[u.jsx("h2",{className:"break-all text-lg font-semibold",children:f.name}),u.jsx(WP,{status:f.connectionStatus})]})}),u.jsxs(Za,{className:"flex flex-col items-start space-y-6",children:[u.jsx("div",{className:"flex w-full flex-1",children:u.jsx(GP,{token:f.token})}),f.profileName&&u.jsxs("div",{className:"flex flex-1 gap-2",children:[u.jsx(Sg,{children:u.jsx(Cg,{src:f.profilePicUrl,alt:""})}),u.jsxs("div",{className:"space-y-1",children:[u.jsx("strong",{children:f.profileName}),u.jsx("p",{className:"break-all text-sm text-muted-foreground",children:f.ownerJid})]})]}),f.connectionStatus!=="open"&&u.jsxs(iI,{variant:"warning",className:"flex flex-wrap items-center justify-between gap-3",children:[u.jsx(lI,{className:"text-lg font-bold tracking-wide",children:e("instance.dashboard.alert")}),u.jsxs(Tt,{children:[u.jsx(Nt,{onClick:()=>b(f.name,!1),asChild:!0,children:u.jsx(q,{variant:"warning",children:e("instance.dashboard.button.qrcode.label")})}),u.jsxs(xt,{onCloseAutoFocus:y,children:[u.jsx(wt,{children:e("instance.dashboard.button.qrcode.title")}),u.jsx("div",{className:"flex items-center justify-center",children:r&&u.jsx(bY,{value:r,size:256,bgColor:"transparent",fgColor:S,className:"rounded-sm"})})]})]}),f.number&&u.jsxs(Tt,{children:[u.jsx(Nt,{className:"connect-code-button",onClick:()=>b(f.name,!0),children:e("instance.dashboard.button.pairingCode.label")}),u.jsx(xt,{onCloseAutoFocus:y,children:u.jsx(wt,{children:u.jsx(Fi,{children:o?u.jsxs("div",{className:"py-3",children:[u.jsx("p",{className:"text-center",children:u.jsx("strong",{children:e("instance.dashboard.button.pairingCode.title")})}),u.jsxs("p",{className:"pairing-code text-center",children:[o.substring(0,4),"-",o.substring(4,8)]})]}):u.jsx(wr,{})})})})]})]})]}),u.jsxs(kg,{className:"flex flex-wrap items-center justify-end gap-3",children:[u.jsx(q,{variant:"outline",className:"refresh-button",size:"icon",onClick:g,children:u.jsx(fj,{size:"20"})}),u.jsx(q,{className:"action-button",variant:"secondary",onClick:()=>m(f.name),children:e("instance.dashboard.button.restart").toUpperCase()}),u.jsx(q,{variant:"destructive",onClick:()=>x(f.name),disabled:f.connectionStatus==="close",children:e("instance.dashboard.button.disconnect").toUpperCase()})]})]})}),u.jsxs("section",{className:"grid grid-cols-[repeat(auto-fit,_minmax(15rem,_1fr))] gap-6",children:[u.jsxs(Ja,{className:"instance-card",children:[u.jsx(Qa,{children:u.jsxs(jc,{className:"flex items-center gap-2",children:[u.jsx(dj,{size:"20"}),e("instance.dashboard.contacts")]})}),u.jsx(Za,{children:n.format(w.contacts)})]}),u.jsxs(Ja,{className:"instance-card",children:[u.jsx(Qa,{children:u.jsxs(jc,{className:"flex items-center gap-2",children:[u.jsx(J3,{size:"20"}),e("instance.dashboard.chats")]})}),u.jsx(Za,{children:n.format(w.chats)})]}),u.jsxs(Ja,{className:"instance-card",children:[u.jsx(Qa,{children:u.jsxs(jc,{className:"flex items-center gap-2",children:[u.jsx(ug,{size:"20"}),e("instance.dashboard.messages")]})}),u.jsx(Za,{children:n.format(w.messages)})]})]})]}):u.jsx(wr,{})}var CY="Separator",Y1="horizontal",EY=["horizontal","vertical"],uI=v.forwardRef((e,t)=>{const{decorative:n,orientation:r=Y1,...s}=e,o=TY(r)?r:Y1,l=n?{role:"none"}:{"aria-orientation":o==="vertical"?o:void 0,role:"separator"};return u.jsx(Ne.div,{"data-orientation":o,...l,...s,ref:t})});uI.displayName=CY;function TY(e){return EY.includes(e)}var cI=uI;const $t=v.forwardRef(({className:e,orientation:t="horizontal",decorative:n=!0,...r},s)=>u.jsx(cI,{ref:s,decorative:n,orientation:t,className:ge("shrink-0 bg-border",t==="horizontal"?"h-[1px] w-full":"h-full w-[1px]",e),...r}));$t.displayName=cI.displayName;const kY=e=>["dify","fetchDify",JSON.stringify(e)],_Y=async({instanceName:e,token:t})=>(await he.get(`/dify/find/${e}`,{headers:{apikey:t}})).data,dI=e=>{const{instanceName:t,token:n,...r}=e;return lt({...r,queryKey:kY({instanceName:t,token:n}),queryFn:()=>_Y({instanceName:t,token:n}),enabled:!!t&&(e.enabled??!0)})},jY=async({instanceName:e,token:t,data:n})=>(await he.post(`/dify/create/${e}`,n,{headers:{apikey:t}})).data,RY=async({instanceName:e,difyId:t,data:n})=>(await he.put(`/dify/update/${t}/${e}`,n)).data,PY=async({instanceName:e,difyId:t})=>(await he.delete(`/dify/delete/${t}/${e}`)).data,MY=async({instanceName:e,token:t,data:n})=>(await he.post(`/dify/settings/${e}`,n,{headers:{apikey:t}})).data,OY=async({instanceName:e,token:t,remoteJid:n,status:r})=>(await he.post(`/dify/changeStatus/${e}`,{remoteJid:n,status:r},{headers:{apikey:t}})).data;function Qg(){const e=Ye(MY,{invalidateKeys:[["dify","fetchDefaultSettings"]]}),t=Ye(OY,{invalidateKeys:[["dify","getDify"],["dify","fetchSessions"]]}),n=Ye(PY,{invalidateKeys:[["dify","getDify"],["dify","fetchDify"],["dify","fetchSessions"]]}),r=Ye(RY,{invalidateKeys:[["dify","getDify"],["dify","fetchDify"],["dify","fetchSessions"]]}),s=Ye(jY,{invalidateKeys:[["dify","fetchDify"]]});return{setDefaultSettingsDify:e,changeStatusDify:t,deleteDify:n,updateDify:r,createDify:s}}const NY=e=>["dify","fetchDefaultSettings",JSON.stringify(e)],IY=async({instanceName:e,token:t})=>(await he.get(`/dify/fetchSettings/${e}`,{headers:{apikey:t}})).data,DY=e=>{const{instanceName:t,token:n,...r}=e;return lt({...r,queryKey:NY({instanceName:t,token:n}),queryFn:()=>IY({instanceName:t,token:n}),enabled:!!t})},AY=_.object({expire:_.string(),keywordFinish:_.string(),delayMessage:_.string(),unknownMessage:_.string(),listeningFromMe:_.boolean(),stopBotFromMe:_.boolean(),keepOpen:_.boolean(),debounceTime:_.string(),ignoreJids:_.array(_.string()).default([]),difyIdFallback:_.union([_.null(),_.string()]).optional(),splitMessages:_.boolean(),timePerChar:_.string()});function FY(){const{t:e}=ze(),{instance:t}=nt(),{setDefaultSettingsDify:n}=Qg(),[r,s]=v.useState(!1),{data:o,refetch:a}=dI({instanceName:t==null?void 0:t.name,token:t==null?void 0:t.token,enabled:r}),{data:l,refetch:c}=DY({instanceName:t==null?void 0:t.name,token:t==null?void 0:t.token}),i=sn({resolver:on(AY),defaultValues:{expire:"0",keywordFinish:e("dify.form.examples.keywordFinish"),delayMessage:"1000",unknownMessage:e("dify.form.examples.unknownMessage"),listeningFromMe:!1,stopBotFromMe:!1,keepOpen:!1,debounceTime:"0",ignoreJids:[],difyIdFallback:void 0,splitMessages:!1,timePerChar:"0"}});v.useEffect(()=>{l&&i.reset({expire:l!=null&&l.expire?l.expire.toString():"0",keywordFinish:l.keywordFinish,delayMessage:l.delayMessage?l.delayMessage.toString():"0",unknownMessage:l.unknownMessage,listeningFromMe:l.listeningFromMe,stopBotFromMe:l.stopBotFromMe,keepOpen:l.keepOpen,debounceTime:l.debounceTime?l.debounceTime.toString():"0",ignoreJids:l.ignoreJids,difyIdFallback:l.difyIdFallback,splitMessages:l.splitMessages,timePerChar:l.timePerChar?l.timePerChar.toString():"0"})},[l]);const d=async f=>{var h,g,m;try{if(!t||!t.name)throw new Error("instance not found.");const x={expire:parseInt(f.expire),keywordFinish:f.keywordFinish,delayMessage:parseInt(f.delayMessage),unknownMessage:f.unknownMessage,listeningFromMe:f.listeningFromMe,stopBotFromMe:f.stopBotFromMe,keepOpen:f.keepOpen,debounceTime:parseInt(f.debounceTime),difyIdFallback:f.difyIdFallback||void 0,ignoreJids:f.ignoreJids,splitMessages:f.splitMessages,timePerChar:parseInt(f.timePerChar)};await n({instanceName:t.name,token:t.token,data:x}),X.success(e("dify.toast.defaultSettings.success"))}catch(x){console.error("Error:",x),X.error(`Error: ${(m=(g=(h=x==null?void 0:x.response)==null?void 0:h.data)==null?void 0:g.response)==null?void 0:m.message}`)}};function p(){c(),a()}return u.jsxs(Tt,{open:r,onOpenChange:s,children:[u.jsx(Nt,{asChild:!0,children:u.jsxs(q,{variant:"secondary",size:"sm",children:[u.jsx(Oi,{size:16,className:"mr-1"}),u.jsx("span",{className:"hidden sm:inline",children:e("dify.defaultSettings")})]})}),u.jsxs(xt,{className:"overflow-y-auto sm:max-h-[600px] sm:max-w-[740px]",onCloseAutoFocus:p,children:[u.jsx(wt,{children:u.jsx(Ut,{children:e("dify.defaultSettings")})}),u.jsx(Tr,{...i,children:u.jsxs("form",{className:"w-full space-y-6",onSubmit:i.handleSubmit(d),children:[u.jsx("div",{children:u.jsxs("div",{className:"space-y-4",children:[u.jsx(Qt,{name:"difyIdFallback",label:e("dify.form.difyIdFallback.label"),options:(o==null?void 0:o.filter(f=>!!f.id).map(f=>({label:f.description,value:f.id})))??[]}),u.jsx(G,{name:"expire",label:e("dify.form.expire.label"),children:u.jsx(K,{type:"number"})}),u.jsx(G,{name:"keywordFinish",label:e("dify.form.keywordFinish.label"),children:u.jsx(K,{})}),u.jsx(G,{name:"delayMessage",label:e("dify.form.delayMessage.label"),children:u.jsx(K,{type:"number"})}),u.jsx(G,{name:"unknownMessage",label:e("dify.form.unknownMessage.label"),children:u.jsx(K,{})}),u.jsx(ke,{name:"listeningFromMe",label:e("dify.form.listeningFromMe.label"),reverse:!0}),u.jsx(ke,{name:"stopBotFromMe",label:e("dify.form.stopBotFromMe.label"),reverse:!0}),u.jsx(ke,{name:"keepOpen",label:e("dify.form.keepOpen.label"),reverse:!0}),u.jsx(G,{name:"debounceTime",label:e("dify.form.debounceTime.label"),children:u.jsx(K,{type:"number"})}),u.jsx(ke,{name:"splitMessages",label:e("dify.form.splitMessages.label"),reverse:!0}),u.jsx(G,{name:"timePerChar",label:e("dify.form.timePerChar.label"),children:u.jsx(K,{type:"number"})}),u.jsx(Ru,{name:"ignoreJids",label:e("dify.form.ignoreJids.label"),placeholder:e("dify.form.ignoreJids.placeholder")})]})}),u.jsx(rn,{children:u.jsx(q,{type:"submit",children:e("dify.button.save")})})]})})]})]})}/** + * table-core + * + * Copyright (c) TanStack + * + * This source code is licensed under the MIT license found in the + * LICENSE.md file in the root directory of this source tree. + * + * @license MIT + */function na(e,t){return typeof e=="function"?e(t):e}function Sr(e,t){return n=>{t.setState(r=>({...r,[e]:na(n,r[e])}))}}function Zg(e){return e instanceof Function}function LY(e){return Array.isArray(e)&&e.every(t=>typeof t=="number")}function fI(e,t){const n=[],r=s=>{s.forEach(o=>{n.push(o);const a=t(o);a!=null&&a.length&&r(a)})};return r(e),n}function De(e,t,n){let r=[],s;return o=>{let a;n.key&&n.debug&&(a=Date.now());const l=e(o);if(!(l.length!==r.length||l.some((d,p)=>r[p]!==d)))return s;r=l;let i;if(n.key&&n.debug&&(i=Date.now()),s=t(...l),n==null||n.onChange==null||n.onChange(s),n.key&&n.debug&&n!=null&&n.debug()){const d=Math.round((Date.now()-a)*100)/100,p=Math.round((Date.now()-i)*100)/100,f=p/16,h=(g,m)=>{for(g=String(g);g.length{var s;return(s=e==null?void 0:e.debugAll)!=null?s:e[t]},key:!1,onChange:r}}function $Y(e,t,n,r){const s=()=>{var a;return(a=o.getValue())!=null?a:e.options.renderFallbackValue},o={id:`${t.id}_${n.id}`,row:t,column:n,getValue:()=>t.getValue(r),renderValue:s,getContext:De(()=>[e,n,t,o],(a,l,c,i)=>({table:a,column:l,row:c,cell:i,getValue:i.getValue,renderValue:i.renderValue}),Ae(e.options,"debugCells"))};return e._features.forEach(a=>{a.createCell==null||a.createCell(o,n,t,e)},{}),o}function BY(e,t,n,r){var s,o;const l={...e._getDefaultColumnDef(),...t},c=l.accessorKey;let i=(s=(o=l.id)!=null?o:c?typeof String.prototype.replaceAll=="function"?c.replaceAll(".","_"):c.replace(/\./g,"_"):void 0)!=null?s:typeof l.header=="string"?l.header:void 0,d;if(l.accessorFn?d=l.accessorFn:c&&(c.includes(".")?d=f=>{let h=f;for(const m of c.split(".")){var g;h=(g=h)==null?void 0:g[m]}return h}:d=f=>f[l.accessorKey]),!i)throw new Error;let p={id:`${String(i)}`,accessorFn:d,parent:r,depth:n,columnDef:l,columns:[],getFlatColumns:De(()=>[!0],()=>{var f;return[p,...(f=p.columns)==null?void 0:f.flatMap(h=>h.getFlatColumns())]},Ae(e.options,"debugColumns")),getLeafColumns:De(()=>[e._getOrderColumnsFn()],f=>{var h;if((h=p.columns)!=null&&h.length){let g=p.columns.flatMap(m=>m.getLeafColumns());return f(g)}return[p]},Ae(e.options,"debugColumns"))};for(const f of e._features)f.createColumn==null||f.createColumn(p,e);return p}const Mn="debugHeaders";function X1(e,t,n){var r;let o={id:(r=n.id)!=null?r:t.id,column:t,index:n.index,isPlaceholder:!!n.isPlaceholder,placeholderId:n.placeholderId,depth:n.depth,subHeaders:[],colSpan:0,rowSpan:0,headerGroup:null,getLeafHeaders:()=>{const a=[],l=c=>{c.subHeaders&&c.subHeaders.length&&c.subHeaders.map(l),a.push(c)};return l(o),a},getContext:()=>({table:e,header:o,column:t})};return e._features.forEach(a=>{a.createHeader==null||a.createHeader(o,e)}),o}const zY={createTable:e=>{e.getHeaderGroups=De(()=>[e.getAllColumns(),e.getVisibleLeafColumns(),e.getState().columnPinning.left,e.getState().columnPinning.right],(t,n,r,s)=>{var o,a;const l=(o=r==null?void 0:r.map(p=>n.find(f=>f.id===p)).filter(Boolean))!=null?o:[],c=(a=s==null?void 0:s.map(p=>n.find(f=>f.id===p)).filter(Boolean))!=null?a:[],i=n.filter(p=>!(r!=null&&r.includes(p.id))&&!(s!=null&&s.includes(p.id)));return Wf(t,[...l,...i,...c],e)},Ae(e.options,Mn)),e.getCenterHeaderGroups=De(()=>[e.getAllColumns(),e.getVisibleLeafColumns(),e.getState().columnPinning.left,e.getState().columnPinning.right],(t,n,r,s)=>(n=n.filter(o=>!(r!=null&&r.includes(o.id))&&!(s!=null&&s.includes(o.id))),Wf(t,n,e,"center")),Ae(e.options,Mn)),e.getLeftHeaderGroups=De(()=>[e.getAllColumns(),e.getVisibleLeafColumns(),e.getState().columnPinning.left],(t,n,r)=>{var s;const o=(s=r==null?void 0:r.map(a=>n.find(l=>l.id===a)).filter(Boolean))!=null?s:[];return Wf(t,o,e,"left")},Ae(e.options,Mn)),e.getRightHeaderGroups=De(()=>[e.getAllColumns(),e.getVisibleLeafColumns(),e.getState().columnPinning.right],(t,n,r)=>{var s;const o=(s=r==null?void 0:r.map(a=>n.find(l=>l.id===a)).filter(Boolean))!=null?s:[];return Wf(t,o,e,"right")},Ae(e.options,Mn)),e.getFooterGroups=De(()=>[e.getHeaderGroups()],t=>[...t].reverse(),Ae(e.options,Mn)),e.getLeftFooterGroups=De(()=>[e.getLeftHeaderGroups()],t=>[...t].reverse(),Ae(e.options,Mn)),e.getCenterFooterGroups=De(()=>[e.getCenterHeaderGroups()],t=>[...t].reverse(),Ae(e.options,Mn)),e.getRightFooterGroups=De(()=>[e.getRightHeaderGroups()],t=>[...t].reverse(),Ae(e.options,Mn)),e.getFlatHeaders=De(()=>[e.getHeaderGroups()],t=>t.map(n=>n.headers).flat(),Ae(e.options,Mn)),e.getLeftFlatHeaders=De(()=>[e.getLeftHeaderGroups()],t=>t.map(n=>n.headers).flat(),Ae(e.options,Mn)),e.getCenterFlatHeaders=De(()=>[e.getCenterHeaderGroups()],t=>t.map(n=>n.headers).flat(),Ae(e.options,Mn)),e.getRightFlatHeaders=De(()=>[e.getRightHeaderGroups()],t=>t.map(n=>n.headers).flat(),Ae(e.options,Mn)),e.getCenterLeafHeaders=De(()=>[e.getCenterFlatHeaders()],t=>t.filter(n=>{var r;return!((r=n.subHeaders)!=null&&r.length)}),Ae(e.options,Mn)),e.getLeftLeafHeaders=De(()=>[e.getLeftFlatHeaders()],t=>t.filter(n=>{var r;return!((r=n.subHeaders)!=null&&r.length)}),Ae(e.options,Mn)),e.getRightLeafHeaders=De(()=>[e.getRightFlatHeaders()],t=>t.filter(n=>{var r;return!((r=n.subHeaders)!=null&&r.length)}),Ae(e.options,Mn)),e.getLeafHeaders=De(()=>[e.getLeftHeaderGroups(),e.getCenterHeaderGroups(),e.getRightHeaderGroups()],(t,n,r)=>{var s,o,a,l,c,i;return[...(s=(o=t[0])==null?void 0:o.headers)!=null?s:[],...(a=(l=n[0])==null?void 0:l.headers)!=null?a:[],...(c=(i=r[0])==null?void 0:i.headers)!=null?c:[]].map(d=>d.getLeafHeaders()).flat()},Ae(e.options,Mn))}};function Wf(e,t,n,r){var s,o;let a=0;const l=function(f,h){h===void 0&&(h=1),a=Math.max(a,h),f.filter(g=>g.getIsVisible()).forEach(g=>{var m;(m=g.columns)!=null&&m.length&&l(g.columns,h+1)},0)};l(e);let c=[];const i=(f,h)=>{const g={depth:h,id:[r,`${h}`].filter(Boolean).join("_"),headers:[]},m=[];f.forEach(x=>{const b=[...m].reverse()[0],y=x.column.depth===g.depth;let w,S=!1;if(y&&x.column.parent?w=x.column.parent:(w=x.column,S=!0),b&&(b==null?void 0:b.column)===w)b.subHeaders.push(x);else{const E=X1(n,w,{id:[r,h,w.id,x==null?void 0:x.id].filter(Boolean).join("_"),isPlaceholder:S,placeholderId:S?`${m.filter(C=>C.column===w).length}`:void 0,depth:h,index:m.length});E.subHeaders.push(x),m.push(E)}g.headers.push(x),x.headerGroup=g}),c.push(g),h>0&&i(m,h-1)},d=t.map((f,h)=>X1(n,f,{depth:a,index:h}));i(d,a-1),c.reverse();const p=f=>f.filter(g=>g.column.getIsVisible()).map(g=>{let m=0,x=0,b=[0];g.subHeaders&&g.subHeaders.length?(b=[],p(g.subHeaders).forEach(w=>{let{colSpan:S,rowSpan:E}=w;m+=S,b.push(E)})):m=1;const y=Math.min(...b);return x=x+y,g.colSpan=m,g.rowSpan=x,{colSpan:m,rowSpan:x}});return p((s=(o=c[0])==null?void 0:o.headers)!=null?s:[]),c}const Yg=(e,t,n,r,s,o,a)=>{let l={id:t,index:r,original:n,depth:s,parentId:a,_valuesCache:{},_uniqueValuesCache:{},getValue:c=>{if(l._valuesCache.hasOwnProperty(c))return l._valuesCache[c];const i=e.getColumn(c);if(i!=null&&i.accessorFn)return l._valuesCache[c]=i.accessorFn(l.original,r),l._valuesCache[c]},getUniqueValues:c=>{if(l._uniqueValuesCache.hasOwnProperty(c))return l._uniqueValuesCache[c];const i=e.getColumn(c);if(i!=null&&i.accessorFn)return i.columnDef.getUniqueValues?(l._uniqueValuesCache[c]=i.columnDef.getUniqueValues(l.original,r),l._uniqueValuesCache[c]):(l._uniqueValuesCache[c]=[l.getValue(c)],l._uniqueValuesCache[c])},renderValue:c=>{var i;return(i=l.getValue(c))!=null?i:e.options.renderFallbackValue},subRows:[],getLeafRows:()=>fI(l.subRows,c=>c.subRows),getParentRow:()=>l.parentId?e.getRow(l.parentId,!0):void 0,getParentRows:()=>{let c=[],i=l;for(;;){const d=i.getParentRow();if(!d)break;c.push(d),i=d}return c.reverse()},getAllCells:De(()=>[e.getAllLeafColumns()],c=>c.map(i=>$Y(e,l,i,i.id)),Ae(e.options,"debugRows")),_getAllCellsByColumnId:De(()=>[l.getAllCells()],c=>c.reduce((i,d)=>(i[d.column.id]=d,i),{}),Ae(e.options,"debugRows"))};for(let c=0;c{e._getFacetedRowModel=t.options.getFacetedRowModel&&t.options.getFacetedRowModel(t,e.id),e.getFacetedRowModel=()=>e._getFacetedRowModel?e._getFacetedRowModel():t.getPreFilteredRowModel(),e._getFacetedUniqueValues=t.options.getFacetedUniqueValues&&t.options.getFacetedUniqueValues(t,e.id),e.getFacetedUniqueValues=()=>e._getFacetedUniqueValues?e._getFacetedUniqueValues():new Map,e._getFacetedMinMaxValues=t.options.getFacetedMinMaxValues&&t.options.getFacetedMinMaxValues(t,e.id),e.getFacetedMinMaxValues=()=>{if(e._getFacetedMinMaxValues)return e._getFacetedMinMaxValues()}}},pI=(e,t,n)=>{var r;const s=n.toLowerCase();return!!(!((r=e.getValue(t))==null||(r=r.toString())==null||(r=r.toLowerCase())==null)&&r.includes(s))};pI.autoRemove=e=>ls(e);const hI=(e,t,n)=>{var r;return!!(!((r=e.getValue(t))==null||(r=r.toString())==null)&&r.includes(n))};hI.autoRemove=e=>ls(e);const gI=(e,t,n)=>{var r;return((r=e.getValue(t))==null||(r=r.toString())==null?void 0:r.toLowerCase())===(n==null?void 0:n.toLowerCase())};gI.autoRemove=e=>ls(e);const mI=(e,t,n)=>{var r;return(r=e.getValue(t))==null?void 0:r.includes(n)};mI.autoRemove=e=>ls(e)||!(e!=null&&e.length);const vI=(e,t,n)=>!n.some(r=>{var s;return!((s=e.getValue(t))!=null&&s.includes(r))});vI.autoRemove=e=>ls(e)||!(e!=null&&e.length);const yI=(e,t,n)=>n.some(r=>{var s;return(s=e.getValue(t))==null?void 0:s.includes(r)});yI.autoRemove=e=>ls(e)||!(e!=null&&e.length);const bI=(e,t,n)=>e.getValue(t)===n;bI.autoRemove=e=>ls(e);const xI=(e,t,n)=>e.getValue(t)==n;xI.autoRemove=e=>ls(e);const Bw=(e,t,n)=>{let[r,s]=n;const o=e.getValue(t);return o>=r&&o<=s};Bw.resolveFilterValue=e=>{let[t,n]=e,r=typeof t!="number"?parseFloat(t):t,s=typeof n!="number"?parseFloat(n):n,o=t===null||Number.isNaN(r)?-1/0:r,a=n===null||Number.isNaN(s)?1/0:s;if(o>a){const l=o;o=a,a=l}return[o,a]};Bw.autoRemove=e=>ls(e)||ls(e[0])&&ls(e[1]);const Xs={includesString:pI,includesStringSensitive:hI,equalsString:gI,arrIncludes:mI,arrIncludesAll:vI,arrIncludesSome:yI,equals:bI,weakEquals:xI,inNumberRange:Bw};function ls(e){return e==null||e===""}const VY={getDefaultColumnDef:()=>({filterFn:"auto"}),getInitialState:e=>({columnFilters:[],...e}),getDefaultOptions:e=>({onColumnFiltersChange:Sr("columnFilters",e),filterFromLeafRows:!1,maxLeafRowFilterDepth:100}),createColumn:(e,t)=>{e.getAutoFilterFn=()=>{const n=t.getCoreRowModel().flatRows[0],r=n==null?void 0:n.getValue(e.id);return typeof r=="string"?Xs.includesString:typeof r=="number"?Xs.inNumberRange:typeof r=="boolean"||r!==null&&typeof r=="object"?Xs.equals:Array.isArray(r)?Xs.arrIncludes:Xs.weakEquals},e.getFilterFn=()=>{var n,r;return Zg(e.columnDef.filterFn)?e.columnDef.filterFn:e.columnDef.filterFn==="auto"?e.getAutoFilterFn():(n=(r=t.options.filterFns)==null?void 0:r[e.columnDef.filterFn])!=null?n:Xs[e.columnDef.filterFn]},e.getCanFilter=()=>{var n,r,s;return((n=e.columnDef.enableColumnFilter)!=null?n:!0)&&((r=t.options.enableColumnFilters)!=null?r:!0)&&((s=t.options.enableFilters)!=null?s:!0)&&!!e.accessorFn},e.getIsFiltered=()=>e.getFilterIndex()>-1,e.getFilterValue=()=>{var n;return(n=t.getState().columnFilters)==null||(n=n.find(r=>r.id===e.id))==null?void 0:n.value},e.getFilterIndex=()=>{var n,r;return(n=(r=t.getState().columnFilters)==null?void 0:r.findIndex(s=>s.id===e.id))!=null?n:-1},e.setFilterValue=n=>{t.setColumnFilters(r=>{const s=e.getFilterFn(),o=r==null?void 0:r.find(d=>d.id===e.id),a=na(n,o?o.value:void 0);if(eE(s,a,e)){var l;return(l=r==null?void 0:r.filter(d=>d.id!==e.id))!=null?l:[]}const c={id:e.id,value:a};if(o){var i;return(i=r==null?void 0:r.map(d=>d.id===e.id?c:d))!=null?i:[]}return r!=null&&r.length?[...r,c]:[c]})}},createRow:(e,t)=>{e.columnFilters={},e.columnFiltersMeta={}},createTable:e=>{e.setColumnFilters=t=>{const n=e.getAllLeafColumns(),r=s=>{var o;return(o=na(t,s))==null?void 0:o.filter(a=>{const l=n.find(c=>c.id===a.id);if(l){const c=l.getFilterFn();if(eE(c,a.value,l))return!1}return!0})};e.options.onColumnFiltersChange==null||e.options.onColumnFiltersChange(r)},e.resetColumnFilters=t=>{var n,r;e.setColumnFilters(t?[]:(n=(r=e.initialState)==null?void 0:r.columnFilters)!=null?n:[])},e.getPreFilteredRowModel=()=>e.getCoreRowModel(),e.getFilteredRowModel=()=>(!e._getFilteredRowModel&&e.options.getFilteredRowModel&&(e._getFilteredRowModel=e.options.getFilteredRowModel(e)),e.options.manualFiltering||!e._getFilteredRowModel?e.getPreFilteredRowModel():e._getFilteredRowModel())}};function eE(e,t,n){return(e&&e.autoRemove?e.autoRemove(t,n):!1)||typeof t>"u"||typeof t=="string"&&!t}const HY=(e,t,n)=>n.reduce((r,s)=>{const o=s.getValue(e);return r+(typeof o=="number"?o:0)},0),KY=(e,t,n)=>{let r;return n.forEach(s=>{const o=s.getValue(e);o!=null&&(r>o||r===void 0&&o>=o)&&(r=o)}),r},qY=(e,t,n)=>{let r;return n.forEach(s=>{const o=s.getValue(e);o!=null&&(r=o)&&(r=o)}),r},WY=(e,t,n)=>{let r,s;return n.forEach(o=>{const a=o.getValue(e);a!=null&&(r===void 0?a>=a&&(r=s=a):(r>a&&(r=a),s{let n=0,r=0;if(t.forEach(s=>{let o=s.getValue(e);o!=null&&(o=+o)>=o&&(++n,r+=o)}),n)return r/n},JY=(e,t)=>{if(!t.length)return;const n=t.map(o=>o.getValue(e));if(!LY(n))return;if(n.length===1)return n[0];const r=Math.floor(n.length/2),s=n.sort((o,a)=>o-a);return n.length%2!==0?s[r]:(s[r-1]+s[r])/2},QY=(e,t)=>Array.from(new Set(t.map(n=>n.getValue(e))).values()),ZY=(e,t)=>new Set(t.map(n=>n.getValue(e))).size,YY=(e,t)=>t.length,mv={sum:HY,min:KY,max:qY,extent:WY,mean:GY,median:JY,unique:QY,uniqueCount:ZY,count:YY},XY={getDefaultColumnDef:()=>({aggregatedCell:e=>{var t,n;return(t=(n=e.getValue())==null||n.toString==null?void 0:n.toString())!=null?t:null},aggregationFn:"auto"}),getInitialState:e=>({grouping:[],...e}),getDefaultOptions:e=>({onGroupingChange:Sr("grouping",e),groupedColumnMode:"reorder"}),createColumn:(e,t)=>{e.toggleGrouping=()=>{t.setGrouping(n=>n!=null&&n.includes(e.id)?n.filter(r=>r!==e.id):[...n??[],e.id])},e.getCanGroup=()=>{var n,r;return((n=e.columnDef.enableGrouping)!=null?n:!0)&&((r=t.options.enableGrouping)!=null?r:!0)&&(!!e.accessorFn||!!e.columnDef.getGroupingValue)},e.getIsGrouped=()=>{var n;return(n=t.getState().grouping)==null?void 0:n.includes(e.id)},e.getGroupedIndex=()=>{var n;return(n=t.getState().grouping)==null?void 0:n.indexOf(e.id)},e.getToggleGroupingHandler=()=>{const n=e.getCanGroup();return()=>{n&&e.toggleGrouping()}},e.getAutoAggregationFn=()=>{const n=t.getCoreRowModel().flatRows[0],r=n==null?void 0:n.getValue(e.id);if(typeof r=="number")return mv.sum;if(Object.prototype.toString.call(r)==="[object Date]")return mv.extent},e.getAggregationFn=()=>{var n,r;if(!e)throw new Error;return Zg(e.columnDef.aggregationFn)?e.columnDef.aggregationFn:e.columnDef.aggregationFn==="auto"?e.getAutoAggregationFn():(n=(r=t.options.aggregationFns)==null?void 0:r[e.columnDef.aggregationFn])!=null?n:mv[e.columnDef.aggregationFn]}},createTable:e=>{e.setGrouping=t=>e.options.onGroupingChange==null?void 0:e.options.onGroupingChange(t),e.resetGrouping=t=>{var n,r;e.setGrouping(t?[]:(n=(r=e.initialState)==null?void 0:r.grouping)!=null?n:[])},e.getPreGroupedRowModel=()=>e.getFilteredRowModel(),e.getGroupedRowModel=()=>(!e._getGroupedRowModel&&e.options.getGroupedRowModel&&(e._getGroupedRowModel=e.options.getGroupedRowModel(e)),e.options.manualGrouping||!e._getGroupedRowModel?e.getPreGroupedRowModel():e._getGroupedRowModel())},createRow:(e,t)=>{e.getIsGrouped=()=>!!e.groupingColumnId,e.getGroupingValue=n=>{if(e._groupingValuesCache.hasOwnProperty(n))return e._groupingValuesCache[n];const r=t.getColumn(n);return r!=null&&r.columnDef.getGroupingValue?(e._groupingValuesCache[n]=r.columnDef.getGroupingValue(e.original),e._groupingValuesCache[n]):e.getValue(n)},e._groupingValuesCache={}},createCell:(e,t,n,r)=>{e.getIsGrouped=()=>t.getIsGrouped()&&t.id===n.groupingColumnId,e.getIsPlaceholder=()=>!e.getIsGrouped()&&t.getIsGrouped(),e.getIsAggregated=()=>{var s;return!e.getIsGrouped()&&!e.getIsPlaceholder()&&!!((s=n.subRows)!=null&&s.length)}}};function eX(e,t,n){if(!(t!=null&&t.length)||!n)return e;const r=e.filter(o=>!t.includes(o.id));return n==="remove"?r:[...t.map(o=>e.find(a=>a.id===o)).filter(Boolean),...r]}const tX={getInitialState:e=>({columnOrder:[],...e}),getDefaultOptions:e=>({onColumnOrderChange:Sr("columnOrder",e)}),createColumn:(e,t)=>{e.getIndex=De(n=>[Nc(t,n)],n=>n.findIndex(r=>r.id===e.id),Ae(t.options,"debugColumns")),e.getIsFirstColumn=n=>{var r;return((r=Nc(t,n)[0])==null?void 0:r.id)===e.id},e.getIsLastColumn=n=>{var r;const s=Nc(t,n);return((r=s[s.length-1])==null?void 0:r.id)===e.id}},createTable:e=>{e.setColumnOrder=t=>e.options.onColumnOrderChange==null?void 0:e.options.onColumnOrderChange(t),e.resetColumnOrder=t=>{var n;e.setColumnOrder(t?[]:(n=e.initialState.columnOrder)!=null?n:[])},e._getOrderColumnsFn=De(()=>[e.getState().columnOrder,e.getState().grouping,e.options.groupedColumnMode],(t,n,r)=>s=>{let o=[];if(!(t!=null&&t.length))o=s;else{const a=[...t],l=[...s];for(;l.length&&a.length;){const c=a.shift(),i=l.findIndex(d=>d.id===c);i>-1&&o.push(l.splice(i,1)[0])}o=[...o,...l]}return eX(o,n,r)},Ae(e.options,"debugTable"))}},vv=()=>({left:[],right:[]}),nX={getInitialState:e=>({columnPinning:vv(),...e}),getDefaultOptions:e=>({onColumnPinningChange:Sr("columnPinning",e)}),createColumn:(e,t)=>{e.pin=n=>{const r=e.getLeafColumns().map(s=>s.id).filter(Boolean);t.setColumnPinning(s=>{var o,a;if(n==="right"){var l,c;return{left:((l=s==null?void 0:s.left)!=null?l:[]).filter(p=>!(r!=null&&r.includes(p))),right:[...((c=s==null?void 0:s.right)!=null?c:[]).filter(p=>!(r!=null&&r.includes(p))),...r]}}if(n==="left"){var i,d;return{left:[...((i=s==null?void 0:s.left)!=null?i:[]).filter(p=>!(r!=null&&r.includes(p))),...r],right:((d=s==null?void 0:s.right)!=null?d:[]).filter(p=>!(r!=null&&r.includes(p)))}}return{left:((o=s==null?void 0:s.left)!=null?o:[]).filter(p=>!(r!=null&&r.includes(p))),right:((a=s==null?void 0:s.right)!=null?a:[]).filter(p=>!(r!=null&&r.includes(p)))}})},e.getCanPin=()=>e.getLeafColumns().some(r=>{var s,o,a;return((s=r.columnDef.enablePinning)!=null?s:!0)&&((o=(a=t.options.enableColumnPinning)!=null?a:t.options.enablePinning)!=null?o:!0)}),e.getIsPinned=()=>{const n=e.getLeafColumns().map(l=>l.id),{left:r,right:s}=t.getState().columnPinning,o=n.some(l=>r==null?void 0:r.includes(l)),a=n.some(l=>s==null?void 0:s.includes(l));return o?"left":a?"right":!1},e.getPinnedIndex=()=>{var n,r;const s=e.getIsPinned();return s?(n=(r=t.getState().columnPinning)==null||(r=r[s])==null?void 0:r.indexOf(e.id))!=null?n:-1:0}},createRow:(e,t)=>{e.getCenterVisibleCells=De(()=>[e._getAllVisibleCells(),t.getState().columnPinning.left,t.getState().columnPinning.right],(n,r,s)=>{const o=[...r??[],...s??[]];return n.filter(a=>!o.includes(a.column.id))},Ae(t.options,"debugRows")),e.getLeftVisibleCells=De(()=>[e._getAllVisibleCells(),t.getState().columnPinning.left],(n,r)=>(r??[]).map(o=>n.find(a=>a.column.id===o)).filter(Boolean).map(o=>({...o,position:"left"})),Ae(t.options,"debugRows")),e.getRightVisibleCells=De(()=>[e._getAllVisibleCells(),t.getState().columnPinning.right],(n,r)=>(r??[]).map(o=>n.find(a=>a.column.id===o)).filter(Boolean).map(o=>({...o,position:"right"})),Ae(t.options,"debugRows"))},createTable:e=>{e.setColumnPinning=t=>e.options.onColumnPinningChange==null?void 0:e.options.onColumnPinningChange(t),e.resetColumnPinning=t=>{var n,r;return e.setColumnPinning(t?vv():(n=(r=e.initialState)==null?void 0:r.columnPinning)!=null?n:vv())},e.getIsSomeColumnsPinned=t=>{var n;const r=e.getState().columnPinning;if(!t){var s,o;return!!((s=r.left)!=null&&s.length||(o=r.right)!=null&&o.length)}return!!((n=r[t])!=null&&n.length)},e.getLeftLeafColumns=De(()=>[e.getAllLeafColumns(),e.getState().columnPinning.left],(t,n)=>(n??[]).map(r=>t.find(s=>s.id===r)).filter(Boolean),Ae(e.options,"debugColumns")),e.getRightLeafColumns=De(()=>[e.getAllLeafColumns(),e.getState().columnPinning.right],(t,n)=>(n??[]).map(r=>t.find(s=>s.id===r)).filter(Boolean),Ae(e.options,"debugColumns")),e.getCenterLeafColumns=De(()=>[e.getAllLeafColumns(),e.getState().columnPinning.left,e.getState().columnPinning.right],(t,n,r)=>{const s=[...n??[],...r??[]];return t.filter(o=>!s.includes(o.id))},Ae(e.options,"debugColumns"))}},Gf={size:150,minSize:20,maxSize:Number.MAX_SAFE_INTEGER},yv=()=>({startOffset:null,startSize:null,deltaOffset:null,deltaPercentage:null,isResizingColumn:!1,columnSizingStart:[]}),rX={getDefaultColumnDef:()=>Gf,getInitialState:e=>({columnSizing:{},columnSizingInfo:yv(),...e}),getDefaultOptions:e=>({columnResizeMode:"onEnd",columnResizeDirection:"ltr",onColumnSizingChange:Sr("columnSizing",e),onColumnSizingInfoChange:Sr("columnSizingInfo",e)}),createColumn:(e,t)=>{e.getSize=()=>{var n,r,s;const o=t.getState().columnSizing[e.id];return Math.min(Math.max((n=e.columnDef.minSize)!=null?n:Gf.minSize,(r=o??e.columnDef.size)!=null?r:Gf.size),(s=e.columnDef.maxSize)!=null?s:Gf.maxSize)},e.getStart=De(n=>[n,Nc(t,n),t.getState().columnSizing],(n,r)=>r.slice(0,e.getIndex(n)).reduce((s,o)=>s+o.getSize(),0),Ae(t.options,"debugColumns")),e.getAfter=De(n=>[n,Nc(t,n),t.getState().columnSizing],(n,r)=>r.slice(e.getIndex(n)+1).reduce((s,o)=>s+o.getSize(),0),Ae(t.options,"debugColumns")),e.resetSize=()=>{t.setColumnSizing(n=>{let{[e.id]:r,...s}=n;return s})},e.getCanResize=()=>{var n,r;return((n=e.columnDef.enableResizing)!=null?n:!0)&&((r=t.options.enableColumnResizing)!=null?r:!0)},e.getIsResizing=()=>t.getState().columnSizingInfo.isResizingColumn===e.id},createHeader:(e,t)=>{e.getSize=()=>{let n=0;const r=s=>{if(s.subHeaders.length)s.subHeaders.forEach(r);else{var o;n+=(o=s.column.getSize())!=null?o:0}};return r(e),n},e.getStart=()=>{if(e.index>0){const n=e.headerGroup.headers[e.index-1];return n.getStart()+n.getSize()}return 0},e.getResizeHandler=n=>{const r=t.getColumn(e.column.id),s=r==null?void 0:r.getCanResize();return o=>{if(!r||!s||(o.persist==null||o.persist(),bv(o)&&o.touches&&o.touches.length>1))return;const a=e.getSize(),l=e?e.getLeafHeaders().map(b=>[b.column.id,b.column.getSize()]):[[r.id,r.getSize()]],c=bv(o)?Math.round(o.touches[0].clientX):o.clientX,i={},d=(b,y)=>{typeof y=="number"&&(t.setColumnSizingInfo(w=>{var S,E;const C=t.options.columnResizeDirection==="rtl"?-1:1,k=(y-((S=w==null?void 0:w.startOffset)!=null?S:0))*C,T=Math.max(k/((E=w==null?void 0:w.startSize)!=null?E:0),-.999999);return w.columnSizingStart.forEach(P=>{let[N,U]=P;i[N]=Math.round(Math.max(U+U*T,0)*100)/100}),{...w,deltaOffset:k,deltaPercentage:T}}),(t.options.columnResizeMode==="onChange"||b==="end")&&t.setColumnSizing(w=>({...w,...i})))},p=b=>d("move",b),f=b=>{d("end",b),t.setColumnSizingInfo(y=>({...y,isResizingColumn:!1,startOffset:null,startSize:null,deltaOffset:null,deltaPercentage:null,columnSizingStart:[]}))},h=n||typeof document<"u"?document:null,g={moveHandler:b=>p(b.clientX),upHandler:b=>{h==null||h.removeEventListener("mousemove",g.moveHandler),h==null||h.removeEventListener("mouseup",g.upHandler),f(b.clientX)}},m={moveHandler:b=>(b.cancelable&&(b.preventDefault(),b.stopPropagation()),p(b.touches[0].clientX),!1),upHandler:b=>{var y;h==null||h.removeEventListener("touchmove",m.moveHandler),h==null||h.removeEventListener("touchend",m.upHandler),b.cancelable&&(b.preventDefault(),b.stopPropagation()),f((y=b.touches[0])==null?void 0:y.clientX)}},x=sX()?{passive:!1}:!1;bv(o)?(h==null||h.addEventListener("touchmove",m.moveHandler,x),h==null||h.addEventListener("touchend",m.upHandler,x)):(h==null||h.addEventListener("mousemove",g.moveHandler,x),h==null||h.addEventListener("mouseup",g.upHandler,x)),t.setColumnSizingInfo(b=>({...b,startOffset:c,startSize:a,deltaOffset:0,deltaPercentage:0,columnSizingStart:l,isResizingColumn:r.id}))}}},createTable:e=>{e.setColumnSizing=t=>e.options.onColumnSizingChange==null?void 0:e.options.onColumnSizingChange(t),e.setColumnSizingInfo=t=>e.options.onColumnSizingInfoChange==null?void 0:e.options.onColumnSizingInfoChange(t),e.resetColumnSizing=t=>{var n;e.setColumnSizing(t?{}:(n=e.initialState.columnSizing)!=null?n:{})},e.resetHeaderSizeInfo=t=>{var n;e.setColumnSizingInfo(t?yv():(n=e.initialState.columnSizingInfo)!=null?n:yv())},e.getTotalSize=()=>{var t,n;return(t=(n=e.getHeaderGroups()[0])==null?void 0:n.headers.reduce((r,s)=>r+s.getSize(),0))!=null?t:0},e.getLeftTotalSize=()=>{var t,n;return(t=(n=e.getLeftHeaderGroups()[0])==null?void 0:n.headers.reduce((r,s)=>r+s.getSize(),0))!=null?t:0},e.getCenterTotalSize=()=>{var t,n;return(t=(n=e.getCenterHeaderGroups()[0])==null?void 0:n.headers.reduce((r,s)=>r+s.getSize(),0))!=null?t:0},e.getRightTotalSize=()=>{var t,n;return(t=(n=e.getRightHeaderGroups()[0])==null?void 0:n.headers.reduce((r,s)=>r+s.getSize(),0))!=null?t:0}}};let Jf=null;function sX(){if(typeof Jf=="boolean")return Jf;let e=!1;try{const t={get passive(){return e=!0,!1}},n=()=>{};window.addEventListener("test",n,t),window.removeEventListener("test",n)}catch{e=!1}return Jf=e,Jf}function bv(e){return e.type==="touchstart"}const oX={getInitialState:e=>({columnVisibility:{},...e}),getDefaultOptions:e=>({onColumnVisibilityChange:Sr("columnVisibility",e)}),createColumn:(e,t)=>{e.toggleVisibility=n=>{e.getCanHide()&&t.setColumnVisibility(r=>({...r,[e.id]:n??!e.getIsVisible()}))},e.getIsVisible=()=>{var n,r;const s=e.columns;return(n=s.length?s.some(o=>o.getIsVisible()):(r=t.getState().columnVisibility)==null?void 0:r[e.id])!=null?n:!0},e.getCanHide=()=>{var n,r;return((n=e.columnDef.enableHiding)!=null?n:!0)&&((r=t.options.enableHiding)!=null?r:!0)},e.getToggleVisibilityHandler=()=>n=>{e.toggleVisibility==null||e.toggleVisibility(n.target.checked)}},createRow:(e,t)=>{e._getAllVisibleCells=De(()=>[e.getAllCells(),t.getState().columnVisibility],n=>n.filter(r=>r.column.getIsVisible()),Ae(t.options,"debugRows")),e.getVisibleCells=De(()=>[e.getLeftVisibleCells(),e.getCenterVisibleCells(),e.getRightVisibleCells()],(n,r,s)=>[...n,...r,...s],Ae(t.options,"debugRows"))},createTable:e=>{const t=(n,r)=>De(()=>[r(),r().filter(s=>s.getIsVisible()).map(s=>s.id).join("_")],s=>s.filter(o=>o.getIsVisible==null?void 0:o.getIsVisible()),Ae(e.options,"debugColumns"));e.getVisibleFlatColumns=t("getVisibleFlatColumns",()=>e.getAllFlatColumns()),e.getVisibleLeafColumns=t("getVisibleLeafColumns",()=>e.getAllLeafColumns()),e.getLeftVisibleLeafColumns=t("getLeftVisibleLeafColumns",()=>e.getLeftLeafColumns()),e.getRightVisibleLeafColumns=t("getRightVisibleLeafColumns",()=>e.getRightLeafColumns()),e.getCenterVisibleLeafColumns=t("getCenterVisibleLeafColumns",()=>e.getCenterLeafColumns()),e.setColumnVisibility=n=>e.options.onColumnVisibilityChange==null?void 0:e.options.onColumnVisibilityChange(n),e.resetColumnVisibility=n=>{var r;e.setColumnVisibility(n?{}:(r=e.initialState.columnVisibility)!=null?r:{})},e.toggleAllColumnsVisible=n=>{var r;n=(r=n)!=null?r:!e.getIsAllColumnsVisible(),e.setColumnVisibility(e.getAllLeafColumns().reduce((s,o)=>({...s,[o.id]:n||!(o.getCanHide!=null&&o.getCanHide())}),{}))},e.getIsAllColumnsVisible=()=>!e.getAllLeafColumns().some(n=>!(n.getIsVisible!=null&&n.getIsVisible())),e.getIsSomeColumnsVisible=()=>e.getAllLeafColumns().some(n=>n.getIsVisible==null?void 0:n.getIsVisible()),e.getToggleAllColumnsVisibilityHandler=()=>n=>{var r;e.toggleAllColumnsVisible((r=n.target)==null?void 0:r.checked)}}};function Nc(e,t){return t?t==="center"?e.getCenterVisibleLeafColumns():t==="left"?e.getLeftVisibleLeafColumns():e.getRightVisibleLeafColumns():e.getVisibleLeafColumns()}const aX={createTable:e=>{e._getGlobalFacetedRowModel=e.options.getFacetedRowModel&&e.options.getFacetedRowModel(e,"__global__"),e.getGlobalFacetedRowModel=()=>e.options.manualFiltering||!e._getGlobalFacetedRowModel?e.getPreFilteredRowModel():e._getGlobalFacetedRowModel(),e._getGlobalFacetedUniqueValues=e.options.getFacetedUniqueValues&&e.options.getFacetedUniqueValues(e,"__global__"),e.getGlobalFacetedUniqueValues=()=>e._getGlobalFacetedUniqueValues?e._getGlobalFacetedUniqueValues():new Map,e._getGlobalFacetedMinMaxValues=e.options.getFacetedMinMaxValues&&e.options.getFacetedMinMaxValues(e,"__global__"),e.getGlobalFacetedMinMaxValues=()=>{if(e._getGlobalFacetedMinMaxValues)return e._getGlobalFacetedMinMaxValues()}}},iX={getInitialState:e=>({globalFilter:void 0,...e}),getDefaultOptions:e=>({onGlobalFilterChange:Sr("globalFilter",e),globalFilterFn:"auto",getColumnCanGlobalFilter:t=>{var n;const r=(n=e.getCoreRowModel().flatRows[0])==null||(n=n._getAllCellsByColumnId()[t.id])==null?void 0:n.getValue();return typeof r=="string"||typeof r=="number"}}),createColumn:(e,t)=>{e.getCanGlobalFilter=()=>{var n,r,s,o;return((n=e.columnDef.enableGlobalFilter)!=null?n:!0)&&((r=t.options.enableGlobalFilter)!=null?r:!0)&&((s=t.options.enableFilters)!=null?s:!0)&&((o=t.options.getColumnCanGlobalFilter==null?void 0:t.options.getColumnCanGlobalFilter(e))!=null?o:!0)&&!!e.accessorFn}},createTable:e=>{e.getGlobalAutoFilterFn=()=>Xs.includesString,e.getGlobalFilterFn=()=>{var t,n;const{globalFilterFn:r}=e.options;return Zg(r)?r:r==="auto"?e.getGlobalAutoFilterFn():(t=(n=e.options.filterFns)==null?void 0:n[r])!=null?t:Xs[r]},e.setGlobalFilter=t=>{e.options.onGlobalFilterChange==null||e.options.onGlobalFilterChange(t)},e.resetGlobalFilter=t=>{e.setGlobalFilter(t?void 0:e.initialState.globalFilter)}}},lX={getInitialState:e=>({expanded:{},...e}),getDefaultOptions:e=>({onExpandedChange:Sr("expanded",e),paginateExpandedRows:!0}),createTable:e=>{let t=!1,n=!1;e._autoResetExpanded=()=>{var r,s;if(!t){e._queue(()=>{t=!0});return}if((r=(s=e.options.autoResetAll)!=null?s:e.options.autoResetExpanded)!=null?r:!e.options.manualExpanding){if(n)return;n=!0,e._queue(()=>{e.resetExpanded(),n=!1})}},e.setExpanded=r=>e.options.onExpandedChange==null?void 0:e.options.onExpandedChange(r),e.toggleAllRowsExpanded=r=>{r??!e.getIsAllRowsExpanded()?e.setExpanded(!0):e.setExpanded({})},e.resetExpanded=r=>{var s,o;e.setExpanded(r?{}:(s=(o=e.initialState)==null?void 0:o.expanded)!=null?s:{})},e.getCanSomeRowsExpand=()=>e.getPrePaginationRowModel().flatRows.some(r=>r.getCanExpand()),e.getToggleAllRowsExpandedHandler=()=>r=>{r.persist==null||r.persist(),e.toggleAllRowsExpanded()},e.getIsSomeRowsExpanded=()=>{const r=e.getState().expanded;return r===!0||Object.values(r).some(Boolean)},e.getIsAllRowsExpanded=()=>{const r=e.getState().expanded;return typeof r=="boolean"?r===!0:!(!Object.keys(r).length||e.getRowModel().flatRows.some(s=>!s.getIsExpanded()))},e.getExpandedDepth=()=>{let r=0;return(e.getState().expanded===!0?Object.keys(e.getRowModel().rowsById):Object.keys(e.getState().expanded)).forEach(o=>{const a=o.split(".");r=Math.max(r,a.length)}),r},e.getPreExpandedRowModel=()=>e.getSortedRowModel(),e.getExpandedRowModel=()=>(!e._getExpandedRowModel&&e.options.getExpandedRowModel&&(e._getExpandedRowModel=e.options.getExpandedRowModel(e)),e.options.manualExpanding||!e._getExpandedRowModel?e.getPreExpandedRowModel():e._getExpandedRowModel())},createRow:(e,t)=>{e.toggleExpanded=n=>{t.setExpanded(r=>{var s;const o=r===!0?!0:!!(r!=null&&r[e.id]);let a={};if(r===!0?Object.keys(t.getRowModel().rowsById).forEach(l=>{a[l]=!0}):a=r,n=(s=n)!=null?s:!o,!o&&n)return{...a,[e.id]:!0};if(o&&!n){const{[e.id]:l,...c}=a;return c}return r})},e.getIsExpanded=()=>{var n;const r=t.getState().expanded;return!!((n=t.options.getIsRowExpanded==null?void 0:t.options.getIsRowExpanded(e))!=null?n:r===!0||r!=null&&r[e.id])},e.getCanExpand=()=>{var n,r,s;return(n=t.options.getRowCanExpand==null?void 0:t.options.getRowCanExpand(e))!=null?n:((r=t.options.enableExpanding)!=null?r:!0)&&!!((s=e.subRows)!=null&&s.length)},e.getIsAllParentsExpanded=()=>{let n=!0,r=e;for(;n&&r.parentId;)r=t.getRow(r.parentId,!0),n=r.getIsExpanded();return n},e.getToggleExpandedHandler=()=>{const n=e.getCanExpand();return()=>{n&&e.toggleExpanded()}}}},Sb=0,Cb=10,xv=()=>({pageIndex:Sb,pageSize:Cb}),uX={getInitialState:e=>({...e,pagination:{...xv(),...e==null?void 0:e.pagination}}),getDefaultOptions:e=>({onPaginationChange:Sr("pagination",e)}),createTable:e=>{let t=!1,n=!1;e._autoResetPageIndex=()=>{var r,s;if(!t){e._queue(()=>{t=!0});return}if((r=(s=e.options.autoResetAll)!=null?s:e.options.autoResetPageIndex)!=null?r:!e.options.manualPagination){if(n)return;n=!0,e._queue(()=>{e.resetPageIndex(),n=!1})}},e.setPagination=r=>{const s=o=>na(r,o);return e.options.onPaginationChange==null?void 0:e.options.onPaginationChange(s)},e.resetPagination=r=>{var s;e.setPagination(r?xv():(s=e.initialState.pagination)!=null?s:xv())},e.setPageIndex=r=>{e.setPagination(s=>{let o=na(r,s.pageIndex);const a=typeof e.options.pageCount>"u"||e.options.pageCount===-1?Number.MAX_SAFE_INTEGER:e.options.pageCount-1;return o=Math.max(0,Math.min(o,a)),{...s,pageIndex:o}})},e.resetPageIndex=r=>{var s,o;e.setPageIndex(r?Sb:(s=(o=e.initialState)==null||(o=o.pagination)==null?void 0:o.pageIndex)!=null?s:Sb)},e.resetPageSize=r=>{var s,o;e.setPageSize(r?Cb:(s=(o=e.initialState)==null||(o=o.pagination)==null?void 0:o.pageSize)!=null?s:Cb)},e.setPageSize=r=>{e.setPagination(s=>{const o=Math.max(1,na(r,s.pageSize)),a=s.pageSize*s.pageIndex,l=Math.floor(a/o);return{...s,pageIndex:l,pageSize:o}})},e.setPageCount=r=>e.setPagination(s=>{var o;let a=na(r,(o=e.options.pageCount)!=null?o:-1);return typeof a=="number"&&(a=Math.max(-1,a)),{...s,pageCount:a}}),e.getPageOptions=De(()=>[e.getPageCount()],r=>{let s=[];return r&&r>0&&(s=[...new Array(r)].fill(null).map((o,a)=>a)),s},Ae(e.options,"debugTable")),e.getCanPreviousPage=()=>e.getState().pagination.pageIndex>0,e.getCanNextPage=()=>{const{pageIndex:r}=e.getState().pagination,s=e.getPageCount();return s===-1?!0:s===0?!1:re.setPageIndex(r=>r-1),e.nextPage=()=>e.setPageIndex(r=>r+1),e.firstPage=()=>e.setPageIndex(0),e.lastPage=()=>e.setPageIndex(e.getPageCount()-1),e.getPrePaginationRowModel=()=>e.getExpandedRowModel(),e.getPaginationRowModel=()=>(!e._getPaginationRowModel&&e.options.getPaginationRowModel&&(e._getPaginationRowModel=e.options.getPaginationRowModel(e)),e.options.manualPagination||!e._getPaginationRowModel?e.getPrePaginationRowModel():e._getPaginationRowModel()),e.getPageCount=()=>{var r;return(r=e.options.pageCount)!=null?r:Math.ceil(e.getRowCount()/e.getState().pagination.pageSize)},e.getRowCount=()=>{var r;return(r=e.options.rowCount)!=null?r:e.getPrePaginationRowModel().rows.length}}},wv=()=>({top:[],bottom:[]}),cX={getInitialState:e=>({rowPinning:wv(),...e}),getDefaultOptions:e=>({onRowPinningChange:Sr("rowPinning",e)}),createRow:(e,t)=>{e.pin=(n,r,s)=>{const o=r?e.getLeafRows().map(c=>{let{id:i}=c;return i}):[],a=s?e.getParentRows().map(c=>{let{id:i}=c;return i}):[],l=new Set([...a,e.id,...o]);t.setRowPinning(c=>{var i,d;if(n==="bottom"){var p,f;return{top:((p=c==null?void 0:c.top)!=null?p:[]).filter(m=>!(l!=null&&l.has(m))),bottom:[...((f=c==null?void 0:c.bottom)!=null?f:[]).filter(m=>!(l!=null&&l.has(m))),...Array.from(l)]}}if(n==="top"){var h,g;return{top:[...((h=c==null?void 0:c.top)!=null?h:[]).filter(m=>!(l!=null&&l.has(m))),...Array.from(l)],bottom:((g=c==null?void 0:c.bottom)!=null?g:[]).filter(m=>!(l!=null&&l.has(m)))}}return{top:((i=c==null?void 0:c.top)!=null?i:[]).filter(m=>!(l!=null&&l.has(m))),bottom:((d=c==null?void 0:c.bottom)!=null?d:[]).filter(m=>!(l!=null&&l.has(m)))}})},e.getCanPin=()=>{var n;const{enableRowPinning:r,enablePinning:s}=t.options;return typeof r=="function"?r(e):(n=r??s)!=null?n:!0},e.getIsPinned=()=>{const n=[e.id],{top:r,bottom:s}=t.getState().rowPinning,o=n.some(l=>r==null?void 0:r.includes(l)),a=n.some(l=>s==null?void 0:s.includes(l));return o?"top":a?"bottom":!1},e.getPinnedIndex=()=>{var n,r;const s=e.getIsPinned();if(!s)return-1;const o=(n=s==="top"?t.getTopRows():t.getBottomRows())==null?void 0:n.map(a=>{let{id:l}=a;return l});return(r=o==null?void 0:o.indexOf(e.id))!=null?r:-1}},createTable:e=>{e.setRowPinning=t=>e.options.onRowPinningChange==null?void 0:e.options.onRowPinningChange(t),e.resetRowPinning=t=>{var n,r;return e.setRowPinning(t?wv():(n=(r=e.initialState)==null?void 0:r.rowPinning)!=null?n:wv())},e.getIsSomeRowsPinned=t=>{var n;const r=e.getState().rowPinning;if(!t){var s,o;return!!((s=r.top)!=null&&s.length||(o=r.bottom)!=null&&o.length)}return!!((n=r[t])!=null&&n.length)},e._getPinnedRows=(t,n,r)=>{var s;return((s=e.options.keepPinnedRows)==null||s?(n??[]).map(a=>{const l=e.getRow(a,!0);return l.getIsAllParentsExpanded()?l:null}):(n??[]).map(a=>t.find(l=>l.id===a))).filter(Boolean).map(a=>({...a,position:r}))},e.getTopRows=De(()=>[e.getRowModel().rows,e.getState().rowPinning.top],(t,n)=>e._getPinnedRows(t,n,"top"),Ae(e.options,"debugRows")),e.getBottomRows=De(()=>[e.getRowModel().rows,e.getState().rowPinning.bottom],(t,n)=>e._getPinnedRows(t,n,"bottom"),Ae(e.options,"debugRows")),e.getCenterRows=De(()=>[e.getRowModel().rows,e.getState().rowPinning.top,e.getState().rowPinning.bottom],(t,n,r)=>{const s=new Set([...n??[],...r??[]]);return t.filter(o=>!s.has(o.id))},Ae(e.options,"debugRows"))}},dX={getInitialState:e=>({rowSelection:{},...e}),getDefaultOptions:e=>({onRowSelectionChange:Sr("rowSelection",e),enableRowSelection:!0,enableMultiRowSelection:!0,enableSubRowSelection:!0}),createTable:e=>{e.setRowSelection=t=>e.options.onRowSelectionChange==null?void 0:e.options.onRowSelectionChange(t),e.resetRowSelection=t=>{var n;return e.setRowSelection(t?{}:(n=e.initialState.rowSelection)!=null?n:{})},e.toggleAllRowsSelected=t=>{e.setRowSelection(n=>{t=typeof t<"u"?t:!e.getIsAllRowsSelected();const r={...n},s=e.getPreGroupedRowModel().flatRows;return t?s.forEach(o=>{o.getCanSelect()&&(r[o.id]=!0)}):s.forEach(o=>{delete r[o.id]}),r})},e.toggleAllPageRowsSelected=t=>e.setRowSelection(n=>{const r=typeof t<"u"?t:!e.getIsAllPageRowsSelected(),s={...n};return e.getRowModel().rows.forEach(o=>{Eb(s,o.id,r,!0,e)}),s}),e.getPreSelectedRowModel=()=>e.getCoreRowModel(),e.getSelectedRowModel=De(()=>[e.getState().rowSelection,e.getCoreRowModel()],(t,n)=>Object.keys(t).length?Sv(e,n):{rows:[],flatRows:[],rowsById:{}},Ae(e.options,"debugTable")),e.getFilteredSelectedRowModel=De(()=>[e.getState().rowSelection,e.getFilteredRowModel()],(t,n)=>Object.keys(t).length?Sv(e,n):{rows:[],flatRows:[],rowsById:{}},Ae(e.options,"debugTable")),e.getGroupedSelectedRowModel=De(()=>[e.getState().rowSelection,e.getSortedRowModel()],(t,n)=>Object.keys(t).length?Sv(e,n):{rows:[],flatRows:[],rowsById:{}},Ae(e.options,"debugTable")),e.getIsAllRowsSelected=()=>{const t=e.getFilteredRowModel().flatRows,{rowSelection:n}=e.getState();let r=!!(t.length&&Object.keys(n).length);return r&&t.some(s=>s.getCanSelect()&&!n[s.id])&&(r=!1),r},e.getIsAllPageRowsSelected=()=>{const t=e.getPaginationRowModel().flatRows.filter(s=>s.getCanSelect()),{rowSelection:n}=e.getState();let r=!!t.length;return r&&t.some(s=>!n[s.id])&&(r=!1),r},e.getIsSomeRowsSelected=()=>{var t;const n=Object.keys((t=e.getState().rowSelection)!=null?t:{}).length;return n>0&&n{const t=e.getPaginationRowModel().flatRows;return e.getIsAllPageRowsSelected()?!1:t.filter(n=>n.getCanSelect()).some(n=>n.getIsSelected()||n.getIsSomeSelected())},e.getToggleAllRowsSelectedHandler=()=>t=>{e.toggleAllRowsSelected(t.target.checked)},e.getToggleAllPageRowsSelectedHandler=()=>t=>{e.toggleAllPageRowsSelected(t.target.checked)}},createRow:(e,t)=>{e.toggleSelected=(n,r)=>{const s=e.getIsSelected();t.setRowSelection(o=>{var a;if(n=typeof n<"u"?n:!s,e.getCanSelect()&&s===n)return o;const l={...o};return Eb(l,e.id,n,(a=r==null?void 0:r.selectChildren)!=null?a:!0,t),l})},e.getIsSelected=()=>{const{rowSelection:n}=t.getState();return zw(e,n)},e.getIsSomeSelected=()=>{const{rowSelection:n}=t.getState();return Tb(e,n)==="some"},e.getIsAllSubRowsSelected=()=>{const{rowSelection:n}=t.getState();return Tb(e,n)==="all"},e.getCanSelect=()=>{var n;return typeof t.options.enableRowSelection=="function"?t.options.enableRowSelection(e):(n=t.options.enableRowSelection)!=null?n:!0},e.getCanSelectSubRows=()=>{var n;return typeof t.options.enableSubRowSelection=="function"?t.options.enableSubRowSelection(e):(n=t.options.enableSubRowSelection)!=null?n:!0},e.getCanMultiSelect=()=>{var n;return typeof t.options.enableMultiRowSelection=="function"?t.options.enableMultiRowSelection(e):(n=t.options.enableMultiRowSelection)!=null?n:!0},e.getToggleSelectedHandler=()=>{const n=e.getCanSelect();return r=>{var s;n&&e.toggleSelected((s=r.target)==null?void 0:s.checked)}}}},Eb=(e,t,n,r,s)=>{var o;const a=s.getRow(t,!0);n?(a.getCanMultiSelect()||Object.keys(e).forEach(l=>delete e[l]),a.getCanSelect()&&(e[t]=!0)):delete e[t],r&&(o=a.subRows)!=null&&o.length&&a.getCanSelectSubRows()&&a.subRows.forEach(l=>Eb(e,l.id,n,r,s))};function Sv(e,t){const n=e.getState().rowSelection,r=[],s={},o=function(a,l){return a.map(c=>{var i;const d=zw(c,n);if(d&&(r.push(c),s[c.id]=c),(i=c.subRows)!=null&&i.length&&(c={...c,subRows:o(c.subRows)}),d)return c}).filter(Boolean)};return{rows:o(t.rows),flatRows:r,rowsById:s}}function zw(e,t){var n;return(n=t[e.id])!=null?n:!1}function Tb(e,t,n){var r;if(!((r=e.subRows)!=null&&r.length))return!1;let s=!0,o=!1;return e.subRows.forEach(a=>{if(!(o&&!s)&&(a.getCanSelect()&&(zw(a,t)?o=!0:s=!1),a.subRows&&a.subRows.length)){const l=Tb(a,t);l==="all"?o=!0:(l==="some"&&(o=!0),s=!1)}}),s?"all":o?"some":!1}const kb=/([0-9]+)/gm,fX=(e,t,n)=>wI(Sa(e.getValue(n)).toLowerCase(),Sa(t.getValue(n)).toLowerCase()),pX=(e,t,n)=>wI(Sa(e.getValue(n)),Sa(t.getValue(n))),hX=(e,t,n)=>Uw(Sa(e.getValue(n)).toLowerCase(),Sa(t.getValue(n)).toLowerCase()),gX=(e,t,n)=>Uw(Sa(e.getValue(n)),Sa(t.getValue(n))),mX=(e,t,n)=>{const r=e.getValue(n),s=t.getValue(n);return r>s?1:rUw(e.getValue(n),t.getValue(n));function Uw(e,t){return e===t?0:e>t?1:-1}function Sa(e){return typeof e=="number"?isNaN(e)||e===1/0||e===-1/0?"":String(e):typeof e=="string"?e:""}function wI(e,t){const n=e.split(kb).filter(Boolean),r=t.split(kb).filter(Boolean);for(;n.length&&r.length;){const s=n.shift(),o=r.shift(),a=parseInt(s,10),l=parseInt(o,10),c=[a,l].sort();if(isNaN(c[0])){if(s>o)return 1;if(o>s)return-1;continue}if(isNaN(c[1]))return isNaN(a)?-1:1;if(a>l)return 1;if(l>a)return-1}return n.length-r.length}const rc={alphanumeric:fX,alphanumericCaseSensitive:pX,text:hX,textCaseSensitive:gX,datetime:mX,basic:vX},yX={getInitialState:e=>({sorting:[],...e}),getDefaultColumnDef:()=>({sortingFn:"auto",sortUndefined:1}),getDefaultOptions:e=>({onSortingChange:Sr("sorting",e),isMultiSortEvent:t=>t.shiftKey}),createColumn:(e,t)=>{e.getAutoSortingFn=()=>{const n=t.getFilteredRowModel().flatRows.slice(10);let r=!1;for(const s of n){const o=s==null?void 0:s.getValue(e.id);if(Object.prototype.toString.call(o)==="[object Date]")return rc.datetime;if(typeof o=="string"&&(r=!0,o.split(kb).length>1))return rc.alphanumeric}return r?rc.text:rc.basic},e.getAutoSortDir=()=>{const n=t.getFilteredRowModel().flatRows[0];return typeof(n==null?void 0:n.getValue(e.id))=="string"?"asc":"desc"},e.getSortingFn=()=>{var n,r;if(!e)throw new Error;return Zg(e.columnDef.sortingFn)?e.columnDef.sortingFn:e.columnDef.sortingFn==="auto"?e.getAutoSortingFn():(n=(r=t.options.sortingFns)==null?void 0:r[e.columnDef.sortingFn])!=null?n:rc[e.columnDef.sortingFn]},e.toggleSorting=(n,r)=>{const s=e.getNextSortingOrder(),o=typeof n<"u"&&n!==null;t.setSorting(a=>{const l=a==null?void 0:a.find(h=>h.id===e.id),c=a==null?void 0:a.findIndex(h=>h.id===e.id);let i=[],d,p=o?n:s==="desc";if(a!=null&&a.length&&e.getCanMultiSort()&&r?l?d="toggle":d="add":a!=null&&a.length&&c!==a.length-1?d="replace":l?d="toggle":d="replace",d==="toggle"&&(o||s||(d="remove")),d==="add"){var f;i=[...a,{id:e.id,desc:p}],i.splice(0,i.length-((f=t.options.maxMultiSortColCount)!=null?f:Number.MAX_SAFE_INTEGER))}else d==="toggle"?i=a.map(h=>h.id===e.id?{...h,desc:p}:h):d==="remove"?i=a.filter(h=>h.id!==e.id):i=[{id:e.id,desc:p}];return i})},e.getFirstSortDir=()=>{var n,r;return((n=(r=e.columnDef.sortDescFirst)!=null?r:t.options.sortDescFirst)!=null?n:e.getAutoSortDir()==="desc")?"desc":"asc"},e.getNextSortingOrder=n=>{var r,s;const o=e.getFirstSortDir(),a=e.getIsSorted();return a?a!==o&&((r=t.options.enableSortingRemoval)==null||r)&&(!(n&&(s=t.options.enableMultiRemove)!=null)||s)?!1:a==="desc"?"asc":"desc":o},e.getCanSort=()=>{var n,r;return((n=e.columnDef.enableSorting)!=null?n:!0)&&((r=t.options.enableSorting)!=null?r:!0)&&!!e.accessorFn},e.getCanMultiSort=()=>{var n,r;return(n=(r=e.columnDef.enableMultiSort)!=null?r:t.options.enableMultiSort)!=null?n:!!e.accessorFn},e.getIsSorted=()=>{var n;const r=(n=t.getState().sorting)==null?void 0:n.find(s=>s.id===e.id);return r?r.desc?"desc":"asc":!1},e.getSortIndex=()=>{var n,r;return(n=(r=t.getState().sorting)==null?void 0:r.findIndex(s=>s.id===e.id))!=null?n:-1},e.clearSorting=()=>{t.setSorting(n=>n!=null&&n.length?n.filter(r=>r.id!==e.id):[])},e.getToggleSortingHandler=()=>{const n=e.getCanSort();return r=>{n&&(r.persist==null||r.persist(),e.toggleSorting==null||e.toggleSorting(void 0,e.getCanMultiSort()?t.options.isMultiSortEvent==null?void 0:t.options.isMultiSortEvent(r):!1))}}},createTable:e=>{e.setSorting=t=>e.options.onSortingChange==null?void 0:e.options.onSortingChange(t),e.resetSorting=t=>{var n,r;e.setSorting(t?[]:(n=(r=e.initialState)==null?void 0:r.sorting)!=null?n:[])},e.getPreSortedRowModel=()=>e.getGroupedRowModel(),e.getSortedRowModel=()=>(!e._getSortedRowModel&&e.options.getSortedRowModel&&(e._getSortedRowModel=e.options.getSortedRowModel(e)),e.options.manualSorting||!e._getSortedRowModel?e.getPreSortedRowModel():e._getSortedRowModel())}},bX=[zY,oX,tX,nX,UY,VY,aX,iX,yX,XY,lX,uX,cX,dX,rX];function xX(e){var t,n;const r=[...bX,...(t=e._features)!=null?t:[]];let s={_features:r};const o=s._features.reduce((f,h)=>Object.assign(f,h.getDefaultOptions==null?void 0:h.getDefaultOptions(s)),{}),a=f=>s.options.mergeOptions?s.options.mergeOptions(o,f):{...o,...f};let c={...{},...(n=e.initialState)!=null?n:{}};s._features.forEach(f=>{var h;c=(h=f.getInitialState==null?void 0:f.getInitialState(c))!=null?h:c});const i=[];let d=!1;const p={_features:r,options:{...o,...e},initialState:c,_queue:f=>{i.push(f),d||(d=!0,Promise.resolve().then(()=>{for(;i.length;)i.shift()();d=!1}).catch(h=>setTimeout(()=>{throw h})))},reset:()=>{s.setState(s.initialState)},setOptions:f=>{const h=na(f,s.options);s.options=a(h)},getState:()=>s.options.state,setState:f=>{s.options.onStateChange==null||s.options.onStateChange(f)},_getRowId:(f,h,g)=>{var m;return(m=s.options.getRowId==null?void 0:s.options.getRowId(f,h,g))!=null?m:`${g?[g.id,h].join("."):h}`},getCoreRowModel:()=>(s._getCoreRowModel||(s._getCoreRowModel=s.options.getCoreRowModel(s)),s._getCoreRowModel()),getRowModel:()=>s.getPaginationRowModel(),getRow:(f,h)=>{let g=(h?s.getPrePaginationRowModel():s.getRowModel()).rowsById[f];if(!g&&(g=s.getCoreRowModel().rowsById[f],!g))throw new Error;return g},_getDefaultColumnDef:De(()=>[s.options.defaultColumn],f=>{var h;return f=(h=f)!=null?h:{},{header:g=>{const m=g.header.column.columnDef;return m.accessorKey?m.accessorKey:m.accessorFn?m.id:null},cell:g=>{var m,x;return(m=(x=g.renderValue())==null||x.toString==null?void 0:x.toString())!=null?m:null},...s._features.reduce((g,m)=>Object.assign(g,m.getDefaultColumnDef==null?void 0:m.getDefaultColumnDef()),{}),...f}},Ae(e,"debugColumns")),_getColumnDefs:()=>s.options.columns,getAllColumns:De(()=>[s._getColumnDefs()],f=>{const h=function(g,m,x){return x===void 0&&(x=0),g.map(b=>{const y=BY(s,b,x,m),w=b;return y.columns=w.columns?h(w.columns,y,x+1):[],y})};return h(f)},Ae(e,"debugColumns")),getAllFlatColumns:De(()=>[s.getAllColumns()],f=>f.flatMap(h=>h.getFlatColumns()),Ae(e,"debugColumns")),_getAllFlatColumnsById:De(()=>[s.getAllFlatColumns()],f=>f.reduce((h,g)=>(h[g.id]=g,h),{}),Ae(e,"debugColumns")),getAllLeafColumns:De(()=>[s.getAllColumns(),s._getOrderColumnsFn()],(f,h)=>{let g=f.flatMap(m=>m.getLeafColumns());return h(g)},Ae(e,"debugColumns")),getColumn:f=>s._getAllFlatColumnsById()[f]};Object.assign(s,p);for(let f=0;fDe(()=>[e.options.data],t=>{const n={rows:[],flatRows:[],rowsById:{}},r=function(s,o,a){o===void 0&&(o=0);const l=[];for(let i=0;ie._autoResetPageIndex()))}function SX(e,t,n){return n.options.filterFromLeafRows?CX(e,t,n):EX(e,t,n)}function CX(e,t,n){var r;const s=[],o={},a=(r=n.options.maxLeafRowFilterDepth)!=null?r:100,l=function(c,i){i===void 0&&(i=0);const d=[];for(let f=0;fDe(()=>[e.getPreFilteredRowModel(),e.getState().columnFilters,e.getState().globalFilter],(t,n,r)=>{if(!t.rows.length||!(n!=null&&n.length)&&!r){for(let f=0;f{var h;const g=e.getColumn(f.id);if(!g)return;const m=g.getFilterFn();m&&s.push({id:f.id,filterFn:m,resolvedValue:(h=m.resolveFilterValue==null?void 0:m.resolveFilterValue(f.value))!=null?h:f.value})});const a=(n??[]).map(f=>f.id),l=e.getGlobalFilterFn(),c=e.getAllLeafColumns().filter(f=>f.getCanGlobalFilter());r&&l&&c.length&&(a.push("__global__"),c.forEach(f=>{var h;o.push({id:f.id,filterFn:l,resolvedValue:(h=l.resolveFilterValue==null?void 0:l.resolveFilterValue(r))!=null?h:r})}));let i,d;for(let f=0;f{h.columnFiltersMeta[m]=x})}if(o.length){for(let g=0;g{h.columnFiltersMeta[m]=x})){h.columnFilters.__global__=!0;break}}h.columnFilters.__global__!==!0&&(h.columnFilters.__global__=!1)}}const p=f=>{for(let h=0;he._autoResetPageIndex()))}function kX(){return e=>De(()=>[e.getState().grouping,e.getPreGroupedRowModel()],(t,n)=>{if(!n.rows.length||!t.length)return n.rows.forEach(c=>{c.depth=0,c.parentId=void 0}),n;const r=t.filter(c=>e.getColumn(c)),s=[],o={},a=function(c,i,d){if(i===void 0&&(i=0),i>=r.length)return c.map(g=>(g.depth=i,s.push(g),o[g.id]=g,g.subRows&&(g.subRows=a(g.subRows,i+1,g.id)),g));const p=r[i],f=_X(c,p);return Array.from(f.entries()).map((g,m)=>{let[x,b]=g,y=`${p}:${x}`;y=d?`${d}>${y}`:y;const w=a(b,i+1,y);w.forEach(C=>{C.parentId=y});const S=i?fI(b,C=>C.subRows):b,E=Yg(e,y,S[0].original,m,i,void 0,d);return Object.assign(E,{groupingColumnId:p,groupingValue:x,subRows:w,leafRows:S,getValue:C=>{if(r.includes(C)){if(E._valuesCache.hasOwnProperty(C))return E._valuesCache[C];if(b[0]){var k;E._valuesCache[C]=(k=b[0].getValue(C))!=null?k:void 0}return E._valuesCache[C]}if(E._groupingValuesCache.hasOwnProperty(C))return E._groupingValuesCache[C];const T=e.getColumn(C),P=T==null?void 0:T.getAggregationFn();if(P)return E._groupingValuesCache[C]=P(C,S,b),E._groupingValuesCache[C]}}),w.forEach(C=>{s.push(C),o[C.id]=C}),E})},l=a(n.rows,0);return l.forEach(c=>{s.push(c),o[c.id]=c}),{rows:l,flatRows:s,rowsById:o}},Ae(e.options,"debugTable","getGroupedRowModel",()=>{e._queue(()=>{e._autoResetExpanded(),e._autoResetPageIndex()})}))}function _X(e,t){const n=new Map;return e.reduce((r,s)=>{const o=`${s.getGroupingValue(t)}`,a=r.get(o);return a?a.push(s):r.set(o,[s]),r},n)}function jX(){return e=>De(()=>[e.getState().sorting,e.getPreSortedRowModel()],(t,n)=>{if(!n.rows.length||!(t!=null&&t.length))return n;const r=e.getState().sorting,s=[],o=r.filter(c=>{var i;return(i=e.getColumn(c.id))==null?void 0:i.getCanSort()}),a={};o.forEach(c=>{const i=e.getColumn(c.id);i&&(a[c.id]={sortUndefined:i.columnDef.sortUndefined,invertSorting:i.columnDef.invertSorting,sortingFn:i.getSortingFn()})});const l=c=>{const i=c.map(d=>({...d}));return i.sort((d,p)=>{for(let h=0;h{var p;s.push(d),(p=d.subRows)!=null&&p.length&&(d.subRows=l(d.subRows))}),i};return{rows:l(n.rows),flatRows:s,rowsById:n.rowsById}},Ae(e.options,"debugTable","getSortedRowModel",()=>e._autoResetPageIndex()))}/** + * react-table + * + * Copyright (c) TanStack + * + * This source code is licensed under the MIT license found in the + * LICENSE.md file in the root directory of this source tree. + * + * @license MIT + */function tE(e,t){return e?RX(e)?v.createElement(e,t):e:null}function RX(e){return PX(e)||typeof e=="function"||MX(e)}function PX(e){return typeof e=="function"&&(()=>{const t=Object.getPrototypeOf(e);return t.prototype&&t.prototype.isReactComponent})()}function MX(e){return typeof e=="object"&&typeof e.$$typeof=="symbol"&&["react.memo","react.forward_ref"].includes(e.$$typeof.description)}function OX(e){const t={state:{},onStateChange:()=>{},renderFallbackValue:null,...e},[n]=v.useState(()=>({current:xX(t)})),[r,s]=v.useState(()=>n.current.initialState);return n.current.setOptions(o=>({...o,...e,state:{...r,...e.state},onStateChange:a=>{s(a),e.onStateChange==null||e.onStateChange(a)}})),n.current}const SI=v.forwardRef(({className:e,...t},n)=>u.jsx("div",{className:"relative w-full overflow-auto",children:u.jsx("table",{ref:n,className:ge("w-full caption-bottom text-sm",e),...t})}));SI.displayName="Table";const CI=v.forwardRef(({className:e,...t},n)=>u.jsx("thead",{ref:n,className:ge("[&_tr]:border-b",e),...t}));CI.displayName="TableHeader";const EI=v.forwardRef(({className:e,...t},n)=>u.jsx("tbody",{ref:n,className:ge("[&_tr:last-child]:border-0",e),...t}));EI.displayName="TableBody";const NX=v.forwardRef(({className:e,...t},n)=>u.jsx("tfoot",{ref:n,className:ge("border-t bg-muted/50 font-medium [&>tr]:last:border-b-0",e),...t}));NX.displayName="TableFooter";const vc=v.forwardRef(({className:e,...t},n)=>u.jsx("tr",{ref:n,className:ge("border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",e),...t}));vc.displayName="TableRow";const TI=v.forwardRef(({className:e,...t},n)=>u.jsx("th",{ref:n,className:ge("h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0",e),...t}));TI.displayName="TableHead";const Ep=v.forwardRef(({className:e,...t},n)=>u.jsx("td",{ref:n,className:ge("p-4 align-middle [&:has([role=checkbox])]:pr-0",e),...t}));Ep.displayName="TableCell";const IX=v.forwardRef(({className:e,...t},n)=>u.jsx("caption",{ref:n,className:ge("mt-4 text-sm text-muted-foreground",e),...t}));IX.displayName="TableCaption";function Nu({columns:e,data:t,isLoading:n,loadingMessage:r,noResultsMessage:s,enableHeaders:o=!0,className:a,highlightedRows:l,...c}){var d;const i=OX({...c,data:t,columns:e,getCoreRowModel:wX(),getFilteredRowModel:TX(),getGroupedRowModel:kX(),getSortedRowModel:jX()});return u.jsx("div",{className:ge("rounded-md border",a),children:u.jsxs(SI,{children:[o&&u.jsx(CI,{children:i.getHeaderGroups().map(p=>u.jsx(vc,{children:p.headers.map(f=>u.jsx(TI,{children:f.isPlaceholder?null:tE(f.column.columnDef.header,f.getContext())},f.id))},p.id))}),u.jsx(EI,{children:n?u.jsx(vc,{children:u.jsx(Ep,{colSpan:e.length,className:"h-24 text-center text-muted-foreground",children:r??"Carregando..."})}):u.jsx(u.Fragment,{children:(d=i.getRowModel().rows)!=null&&d.length?i.getRowModel().rows.map(p=>u.jsx(vc,{"data-state":p.getIsSelected()?"selected":l!=null&&l.includes(p.id)?"highlighted":"",children:p.getVisibleCells().map(f=>u.jsx(Ep,{children:tE(f.column.columnDef.cell,f.getContext())},f.id))},p.id)):u.jsx(vc,{children:u.jsx(Ep,{colSpan:e.length,className:"h-24 text-center",children:s??"Nenhum resultado encontrado!"})})})})]})})}const DX=e=>["dify","fetchSessions",JSON.stringify(e)],AX=async({difyId:e,instanceName:t})=>(await he.get(`/dify/fetchSessions/${e}/${t}`)).data,FX=e=>{const{difyId:t,instanceName:n,...r}=e;return lt({...r,queryKey:DX({difyId:t,instanceName:n}),queryFn:()=>AX({difyId:t,instanceName:n}),enabled:!!n&&!!t&&(e.enabled??!0),staleTime:1e3*10})};function kI({difyId:e}){const{t}=ze(),{instance:n}=nt(),{changeStatusDify:r}=Qg(),[s,o]=v.useState([]),{data:a,refetch:l}=FX({difyId:e,instanceName:n==null?void 0:n.name}),[c,i]=v.useState(!1),[d,p]=v.useState("");function f(){l()}const h=async(m,x)=>{var b,y,w;try{if(!n)return;await r({instanceName:n.name,token:n.token,remoteJid:m,status:x}),X.success(t("dify.toast.success.status")),f()}catch(S){console.error("Error:",S),X.error(`Error : ${(w=(y=(b=S==null?void 0:S.response)==null?void 0:b.data)==null?void 0:y.response)==null?void 0:w.message}`)}},g=[{accessorKey:"remoteJid",header:()=>u.jsx("div",{className:"text-center",children:t("dify.sessions.table.remoteJid")}),cell:({row:m})=>u.jsx("div",{children:m.getValue("remoteJid")})},{accessorKey:"pushName",header:()=>u.jsx("div",{className:"text-center",children:t("dify.sessions.table.pushName")}),cell:({row:m})=>u.jsx("div",{children:m.getValue("pushName")})},{accessorKey:"sessionId",header:()=>u.jsx("div",{className:"text-center",children:t("dify.sessions.table.sessionId")}),cell:({row:m})=>u.jsx("div",{children:m.getValue("sessionId")})},{accessorKey:"status",header:()=>u.jsx("div",{className:"text-center",children:t("dify.sessions.table.status")}),cell:({row:m})=>u.jsx("div",{children:m.getValue("status")})},{id:"actions",enableHiding:!1,cell:({row:m})=>{const x=m.original;return u.jsxs(Eo,{children:[u.jsx(To,{asChild:!0,children:u.jsxs(q,{variant:"ghost",className:"h-8 w-8 p-0",children:[u.jsx("span",{className:"sr-only",children:t("dify.sessions.table.actions.title")}),u.jsx(vu,{className:"h-4 w-4"})]})}),u.jsxs(ps,{align:"end",children:[u.jsx(Ai,{children:t("dify.sessions.table.actions.title")}),u.jsx(Pa,{}),x.status!=="opened"&&u.jsxs(ft,{onClick:()=>h(x.remoteJid,"opened"),children:[u.jsx(qd,{className:"mr-2 h-4 w-4"}),t("dify.sessions.table.actions.open")]}),x.status!=="paused"&&x.status!=="closed"&&u.jsxs(ft,{onClick:()=>h(x.remoteJid,"paused"),children:[u.jsx(Kd,{className:"mr-2 h-4 w-4"}),t("dify.sessions.table.actions.pause")]}),x.status!=="closed"&&u.jsxs(ft,{onClick:()=>h(x.remoteJid,"closed"),children:[u.jsx(Ud,{className:"mr-2 h-4 w-4"}),t("dify.sessions.table.actions.close")]}),u.jsxs(ft,{onClick:()=>h(x.remoteJid,"delete"),children:[u.jsx(Vd,{className:"mr-2 h-4 w-4"}),t("dify.sessions.table.actions.delete")]})]})]})}}];return u.jsxs(Tt,{open:c,onOpenChange:i,children:[u.jsx(Nt,{asChild:!0,children:u.jsxs(q,{variant:"secondary",size:"sm",children:[u.jsx(Hd,{size:16,className:"mr-1"}),u.jsx("span",{className:"hidden sm:inline",children:t("dify.sessions.label")})]})}),u.jsxs(xt,{className:"overflow-y-auto sm:max-w-[950px]",onCloseAutoFocus:f,children:[u.jsx(wt,{children:u.jsx(Ut,{children:t("dify.sessions.label")})}),u.jsxs("div",{children:[u.jsxs("div",{className:"flex items-center justify-between gap-6 p-5",children:[u.jsx(K,{placeholder:t("dify.sessions.search"),value:d,onChange:m=>p(m.target.value)}),u.jsx(q,{variant:"outline",onClick:f,size:"icon",children:u.jsx(Wd,{})})]}),u.jsx(Nu,{columns:g,data:a??[],onSortingChange:o,state:{sorting:s,globalFilter:d},onGlobalFilterChange:p,enableGlobalFilter:!0,noResultsMessage:t("dify.sessions.table.none")})]})]})]})}const LX=_.object({enabled:_.boolean(),description:_.string(),botType:_.string(),apiUrl:_.string(),apiKey:_.string(),triggerType:_.string(),triggerOperator:_.string().optional(),triggerValue:_.string().optional(),expire:_.coerce.number().optional(),keywordFinish:_.string().optional(),delayMessage:_.coerce.number().optional(),unknownMessage:_.string().optional(),listeningFromMe:_.boolean().optional(),stopBotFromMe:_.boolean().optional(),keepOpen:_.boolean().optional(),debounceTime:_.coerce.number().optional(),splitMessages:_.boolean().optional(),timePerChar:_.coerce.number().optional()});function _I({initialData:e,onSubmit:t,handleDelete:n,difyId:r,isModal:s=!1,isLoading:o=!1,openDeletionDialog:a=!1,setOpenDeletionDialog:l=()=>{}}){const{t:c}=ze(),i=sn({resolver:on(LX),defaultValues:e||{enabled:!0,description:"",botType:"chatBot",apiUrl:"",apiKey:"",triggerType:"keyword",triggerOperator:"contains",triggerValue:"",expire:0,keywordFinish:"",delayMessage:0,unknownMessage:"",listeningFromMe:!1,stopBotFromMe:!1,keepOpen:!1,debounceTime:0,splitMessages:!1,timePerChar:0}}),d=i.watch("triggerType");return u.jsx(Tr,{...i,children:u.jsxs("form",{onSubmit:i.handleSubmit(t),className:"w-full space-y-6",children:[u.jsxs("div",{className:"space-y-4",children:[u.jsx(ke,{name:"enabled",label:c("dify.form.enabled.label"),reverse:!0}),u.jsx(G,{name:"description",label:c("dify.form.description.label"),required:!0,children:u.jsx(K,{})}),u.jsxs("div",{className:"flex flex-col",children:[u.jsx("h3",{className:"my-4 text-lg font-medium",children:c("dify.form.difySettings.label")}),u.jsx($t,{})]}),u.jsx(Qt,{name:"botType",label:c("dify.form.botType.label"),options:[{label:c("dify.form.botType.chatBot"),value:"chatBot"},{label:c("dify.form.botType.textGenerator"),value:"textGenerator"},{label:c("dify.form.botType.agent"),value:"agent"},{label:c("dify.form.botType.workflow"),value:"workflow"}]}),u.jsx(G,{name:"apiUrl",label:c("dify.form.apiUrl.label"),required:!0,children:u.jsx(K,{})}),u.jsx(G,{name:"apiKey",label:c("dify.form.apiKey.label"),required:!0,children:u.jsx(K,{type:"password"})}),u.jsxs("div",{className:"flex flex-col",children:[u.jsx("h3",{className:"my-4 text-lg font-medium",children:c("dify.form.triggerSettings.label")}),u.jsx($t,{})]}),u.jsx(Qt,{name:"triggerType",label:c("dify.form.triggerType.label"),options:[{label:c("dify.form.triggerType.keyword"),value:"keyword"},{label:c("dify.form.triggerType.all"),value:"all"},{label:c("dify.form.triggerType.advanced"),value:"advanced"},{label:c("dify.form.triggerType.none"),value:"none"}]}),d==="keyword"&&u.jsxs(u.Fragment,{children:[u.jsx(Qt,{name:"triggerOperator",label:c("dify.form.triggerOperator.label"),options:[{label:c("dify.form.triggerOperator.contains"),value:"contains"},{label:c("dify.form.triggerOperator.equals"),value:"equals"},{label:c("dify.form.triggerOperator.startsWith"),value:"startsWith"},{label:c("dify.form.triggerOperator.endsWith"),value:"endsWith"},{label:c("dify.form.triggerOperator.regex"),value:"regex"}]}),u.jsx(G,{name:"triggerValue",label:c("dify.form.triggerValue.label"),children:u.jsx(K,{})})]}),d==="advanced"&&u.jsx(G,{name:"triggerValue",label:c("dify.form.triggerConditions.label"),children:u.jsx(K,{})}),u.jsxs("div",{className:"flex flex-col",children:[u.jsx("h3",{className:"my-4 text-lg font-medium",children:c("dify.form.generalSettings.label")}),u.jsx($t,{})]}),u.jsx(G,{name:"expire",label:c("dify.form.expire.label"),children:u.jsx(K,{type:"number"})}),u.jsx(G,{name:"keywordFinish",label:c("dify.form.keywordFinish.label"),children:u.jsx(K,{})}),u.jsx(G,{name:"delayMessage",label:c("dify.form.delayMessage.label"),children:u.jsx(K,{type:"number"})}),u.jsx(G,{name:"unknownMessage",label:c("dify.form.unknownMessage.label"),children:u.jsx(K,{})}),u.jsx(ke,{name:"listeningFromMe",label:c("dify.form.listeningFromMe.label"),reverse:!0}),u.jsx(ke,{name:"stopBotFromMe",label:c("dify.form.stopBotFromMe.label"),reverse:!0}),u.jsx(ke,{name:"keepOpen",label:c("dify.form.keepOpen.label"),reverse:!0}),u.jsx(G,{name:"debounceTime",label:c("dify.form.debounceTime.label"),children:u.jsx(K,{type:"number"})}),u.jsx(ke,{name:"splitMessages",label:c("dify.form.splitMessages.label"),reverse:!0}),i.watch("splitMessages")&&u.jsx(G,{name:"timePerChar",label:c("dify.form.timePerChar.label"),children:u.jsx(K,{type:"number"})})]}),s&&u.jsx(rn,{children:u.jsx(q,{disabled:o,type:"submit",children:c(o?"dify.button.saving":"dify.button.save")})}),!s&&u.jsxs("div",{children:[u.jsx(kI,{difyId:r}),u.jsxs("div",{className:"mt-5 flex items-center gap-3",children:[u.jsxs(Tt,{open:a,onOpenChange:l,children:[u.jsx(Nt,{asChild:!0,children:u.jsx(q,{variant:"destructive",size:"sm",children:c("dify.button.delete")})}),u.jsx(xt,{children:u.jsxs(wt,{children:[u.jsx(Ut,{children:c("modal.delete.title")}),u.jsx(Fi,{children:c("modal.delete.messageSingle")}),u.jsxs(rn,{children:[u.jsx(q,{size:"sm",variant:"outline",onClick:()=>l(!1),children:c("button.cancel")}),u.jsx(q,{variant:"destructive",onClick:n,children:c("button.delete")})]})]})})]}),u.jsx(q,{disabled:o,type:"submit",children:c(o?"dify.button.saving":"dify.button.update")})]})]})]})})}function $X({resetTable:e}){const{t}=ze(),{instance:n}=nt(),[r,s]=v.useState(!1),[o,a]=v.useState(!1),{createDify:l}=Qg(),c=async i=>{var d,p,f;try{if(!n||!n.name)throw new Error("instance not found");s(!0);const h={enabled:i.enabled,description:i.description,botType:i.botType,apiUrl:i.apiUrl,apiKey:i.apiKey,triggerType:i.triggerType,triggerOperator:i.triggerOperator||"",triggerValue:i.triggerValue||"",expire:i.expire||0,keywordFinish:i.keywordFinish||"",delayMessage:i.delayMessage||0,unknownMessage:i.unknownMessage||"",listeningFromMe:i.listeningFromMe||!1,stopBotFromMe:i.stopBotFromMe||!1,keepOpen:i.keepOpen||!1,debounceTime:i.debounceTime||0,splitMessages:i.splitMessages||!1,timePerChar:i.timePerChar||0};await l({instanceName:n.name,token:n.token,data:h}),X.success(t("dify.toast.success.create")),a(!1),e()}catch(h){console.error("Error:",h),X.error(`Error: ${(f=(p=(d=h==null?void 0:h.response)==null?void 0:d.data)==null?void 0:p.response)==null?void 0:f.message}`)}finally{s(!1)}};return u.jsxs(Tt,{open:o,onOpenChange:a,children:[u.jsx(Nt,{asChild:!0,children:u.jsxs(q,{size:"sm",children:[u.jsx(Ni,{size:16,className:"mr-1"}),u.jsx("span",{className:"hidden sm:inline",children:t("dify.button.create")})]})}),u.jsxs(xt,{className:"overflow-y-auto sm:max-h-[600px] sm:max-w-[740px]",children:[u.jsx(wt,{children:u.jsx(Ut,{children:t("dify.form.title")})}),u.jsx(_I,{onSubmit:c,isModal:!0,isLoading:r})]})]})}const BX=e=>["dify","getDify",JSON.stringify(e)],zX=async({difyId:e,instanceName:t})=>(await he.get(`/dify/fetch/${e}/${t}`)).data,UX=e=>{const{difyId:t,instanceName:n,...r}=e;return lt({...r,queryKey:BX({difyId:t,instanceName:n}),queryFn:()=>zX({difyId:t,instanceName:n}),enabled:!!n&&!!t&&(e.enabled??!0)})};function VX({difyId:e,resetTable:t}){const{t:n}=ze(),{instance:r}=nt(),s=An(),[o,a]=v.useState(!1),{deleteDify:l,updateDify:c}=Qg(),{data:i,isLoading:d}=UX({difyId:e,instanceName:r==null?void 0:r.name}),p=v.useMemo(()=>({enabled:!!(i!=null&&i.enabled),description:(i==null?void 0:i.description)??"",botType:(i==null?void 0:i.botType)??"",apiUrl:(i==null?void 0:i.apiUrl)??"",apiKey:(i==null?void 0:i.apiKey)??"",triggerType:(i==null?void 0:i.triggerType)??"",triggerOperator:(i==null?void 0:i.triggerOperator)??"",triggerValue:(i==null?void 0:i.triggerValue)??"",expire:(i==null?void 0:i.expire)??0,keywordFinish:(i==null?void 0:i.keywordFinish)??"",delayMessage:(i==null?void 0:i.delayMessage)??0,unknownMessage:(i==null?void 0:i.unknownMessage)??"",listeningFromMe:!!(i!=null&&i.listeningFromMe),stopBotFromMe:!!(i!=null&&i.stopBotFromMe),keepOpen:!!(i!=null&&i.keepOpen),debounceTime:(i==null?void 0:i.debounceTime)??0,splitMessages:(i==null?void 0:i.splitMessages)??!1,timePerChar:(i==null?void 0:i.timePerChar)??0}),[i==null?void 0:i.apiKey,i==null?void 0:i.apiUrl,i==null?void 0:i.botType,i==null?void 0:i.debounceTime,i==null?void 0:i.delayMessage,i==null?void 0:i.description,i==null?void 0:i.enabled,i==null?void 0:i.expire,i==null?void 0:i.keepOpen,i==null?void 0:i.keywordFinish,i==null?void 0:i.listeningFromMe,i==null?void 0:i.stopBotFromMe,i==null?void 0:i.triggerOperator,i==null?void 0:i.triggerType,i==null?void 0:i.triggerValue,i==null?void 0:i.unknownMessage,i==null?void 0:i.splitMessages,i==null?void 0:i.timePerChar]),f=async g=>{var m,x,b;try{if(r&&r.name&&e){const y={enabled:g.enabled,description:g.description,botType:g.botType,apiUrl:g.apiUrl,apiKey:g.apiKey,triggerType:g.triggerType,triggerOperator:g.triggerOperator||"",triggerValue:g.triggerValue||"",expire:g.expire||0,keywordFinish:g.keywordFinish||"",delayMessage:g.delayMessage||1e3,unknownMessage:g.unknownMessage||"",listeningFromMe:g.listeningFromMe||!1,stopBotFromMe:g.stopBotFromMe||!1,keepOpen:g.keepOpen||!1,debounceTime:g.debounceTime||0,splitMessages:g.splitMessages||!1,timePerChar:g.timePerChar||0};await c({instanceName:r.name,difyId:e,data:y}),X.success(n("dify.toast.success.update")),t(),s(`/manager/instance/${r.id}/dify/${e}`)}else console.error("Token not found")}catch(y){console.error("Error:",y),X.error(`Error: ${(b=(x=(m=y==null?void 0:y.response)==null?void 0:m.data)==null?void 0:x.response)==null?void 0:b.message}`)}},h=async()=>{try{r&&r.name&&e?(await l({instanceName:r.name,difyId:e}),X.success(n("dify.toast.success.delete")),a(!1),t(),s(`/manager/instance/${r.id}/dify`)):console.error("instance not found")}catch(g){console.error("Erro ao excluir dify:",g)}};return d?u.jsx(wr,{}):u.jsx("div",{className:"m-4",children:u.jsx(_I,{initialData:p,onSubmit:f,difyId:e,handleDelete:h,isModal:!1,isLoading:d,openDeletionDialog:o,setOpenDeletionDialog:a})})}function nE(){const{t:e}=ze(),t=Ou("(min-width: 768px)"),{instance:n}=nt(),{difyId:r}=So(),{data:s,refetch:o,isLoading:a}=dI({instanceName:n==null?void 0:n.name}),l=An(),c=d=>{n&&l(`/manager/instance/${n.id}/dify/${d}`)},i=()=>{o()};return u.jsxs("main",{className:"pt-5",children:[u.jsxs("div",{className:"mb-1 flex items-center justify-between",children:[u.jsx("h3",{className:"text-lg font-medium",children:e("dify.title")}),u.jsxs("div",{className:"flex items-center justify-end gap-2",children:[u.jsx(kI,{}),u.jsx(FY,{}),u.jsx($X,{resetTable:i})]})]}),u.jsx($t,{className:"my-4"}),u.jsxs(Pu,{direction:t?"horizontal":"vertical",children:[u.jsx(Ur,{defaultSize:35,className:"pr-4",children:u.jsx("div",{className:"flex flex-col gap-3",children:a?u.jsx(wr,{}):u.jsx(u.Fragment,{children:s&&s.length>0&&Array.isArray(s)?s.map(d=>u.jsxs(q,{className:"flex h-auto flex-col items-start justify-start",onClick:()=>c(`${d.id}`),variant:r===d.id?"secondary":"outline",children:[u.jsx("h4",{className:"text-base",children:d.description||d.id}),u.jsx("p",{className:"text-sm font-normal text-muted-foreground",children:d.botType})]},d.id)):u.jsx(q,{variant:"link",children:e("dify.table.none")})})})}),r&&u.jsxs(u.Fragment,{children:[u.jsx(Mu,{withHandle:!0,className:"border border-border"}),u.jsx(Ur,{children:u.jsx(VX,{difyId:r,resetTable:i})})]})]})]})}const HX=e=>["evolutionBot","findEvolutionBot",JSON.stringify(e)],KX=async({instanceName:e,token:t})=>(await he.get(`/evolutionBot/find/${e}`,{headers:{apiKey:t}})).data,jI=e=>{const{instanceName:t,token:n,...r}=e;return lt({...r,queryKey:HX({instanceName:t}),queryFn:()=>KX({instanceName:t,token:n}),enabled:!!t&&(e.enabled??!0)})},qX=e=>["evolutionBot","fetchDefaultSettings",JSON.stringify(e)],WX=async({instanceName:e,token:t})=>{const n=await he.get(`/evolutionBot/fetchSettings/${e}`,{headers:{apiKey:t}});return Array.isArray(n.data)?n.data[0]:n.data},GX=e=>{const{instanceName:t,token:n,...r}=e;return lt({...r,queryKey:qX({instanceName:t}),queryFn:()=>WX({instanceName:t,token:n}),enabled:!!t&&(e.enabled??!0)})},JX=async({instanceName:e,token:t,data:n})=>(await he.post(`/evolutionBot/create/${e}`,n,{headers:{apikey:t}})).data,QX=async({instanceName:e,token:t,evolutionBotId:n,data:r})=>(await he.put(`/evolutionBot/update/${n}/${e}`,r,{headers:{apikey:t}})).data,ZX=async({instanceName:e,evolutionBotId:t})=>(await he.delete(`/evolutionBot/delete/${t}/${e}`)).data,YX=async({instanceName:e,token:t,data:n})=>(await he.post(`/evolutionBot/settings/${e}`,n,{headers:{apikey:t}})).data,XX=async({instanceName:e,token:t,remoteJid:n,status:r})=>(await he.post(`/evolutionBot/changeStatus/${e}`,{remoteJid:n,status:r},{headers:{apikey:t}})).data;function Xg(){const e=Ye(YX,{invalidateKeys:[["evolutionBot","fetchDefaultSettings"]]}),t=Ye(XX,{invalidateKeys:[["evolutionBot","getEvolutionBot"],["evolutionBot","fetchSessions"]]}),n=Ye(ZX,{invalidateKeys:[["evolutionBot","getEvolutionBot"],["evolutionBot","findEvolutionBot"],["evolutionBot","fetchSessions"]]}),r=Ye(QX,{invalidateKeys:[["evolutionBot","getEvolutionBot"],["evolutionBot","findEvolutionBot"],["evolutionBot","fetchSessions"]]}),s=Ye(JX,{invalidateKeys:[["evolutionBot","findEvolutionBot"]]});return{setDefaultSettingsEvolutionBot:e,changeStatusEvolutionBot:t,deleteEvolutionBot:n,updateEvolutionBot:r,createEvolutionBot:s}}const eee=_.object({expire:_.string(),keywordFinish:_.string(),delayMessage:_.string(),unknownMessage:_.string(),listeningFromMe:_.boolean(),stopBotFromMe:_.boolean(),keepOpen:_.boolean(),debounceTime:_.string(),ignoreJids:_.array(_.string()).default([]),botIdFallback:_.union([_.null(),_.string()]).optional(),splitMessages:_.boolean(),timePerChar:_.string()});function tee(){const{t:e}=ze(),{instance:t}=nt(),[n,r]=v.useState(!1),{data:s,refetch:o}=GX({instanceName:t==null?void 0:t.name,enabled:n}),{data:a,refetch:l}=jI({instanceName:t==null?void 0:t.name,enabled:n}),{setDefaultSettingsEvolutionBot:c}=Xg(),i=sn({resolver:on(eee),defaultValues:{expire:"0",keywordFinish:e("evolutionBot.form.examples.keywordFinish"),delayMessage:"1000",unknownMessage:e("evolutionBot.form.examples.unknownMessage"),listeningFromMe:!1,stopBotFromMe:!1,keepOpen:!1,debounceTime:"0",ignoreJids:[],botIdFallback:void 0,splitMessages:!1,timePerChar:"0"}});v.useEffect(()=>{s&&i.reset({expire:s!=null&&s.expire?s.expire.toString():"0",keywordFinish:s.keywordFinish,delayMessage:s.delayMessage?s.delayMessage.toString():"0",unknownMessage:s.unknownMessage,listeningFromMe:s.listeningFromMe,stopBotFromMe:s.stopBotFromMe,keepOpen:s.keepOpen,debounceTime:s.debounceTime?s.debounceTime.toString():"0",ignoreJids:s.ignoreJids,botIdFallback:s.botIdFallback,splitMessages:s.splitMessages,timePerChar:s.timePerChar?s.timePerChar.toString():"0"})},[s]);const d=async f=>{var h,g,m;try{if(!t||!t.name)throw new Error("instance not found.");const x={expire:parseInt(f.expire),keywordFinish:f.keywordFinish,delayMessage:parseInt(f.delayMessage),unknownMessage:f.unknownMessage,listeningFromMe:f.listeningFromMe,stopBotFromMe:f.stopBotFromMe,keepOpen:f.keepOpen,debounceTime:parseInt(f.debounceTime),botIdFallback:f.botIdFallback||void 0,ignoreJids:f.ignoreJids,splitMessages:f.splitMessages,timePerChar:parseInt(f.timePerChar)};await c({instanceName:t.name,token:t.token,data:x}),X.success(e("evolutionBot.toast.defaultSettings.success"))}catch(x){console.error("Error:",x),X.error(`Error: ${(m=(g=(h=x==null?void 0:x.response)==null?void 0:h.data)==null?void 0:g.response)==null?void 0:m.message}`)}};function p(){o(),l()}return u.jsxs(Tt,{open:n,onOpenChange:r,children:[u.jsx(Nt,{asChild:!0,children:u.jsxs(q,{variant:"secondary",size:"sm",children:[u.jsx(Oi,{size:16,className:"mr-1"}),u.jsx("span",{className:"hidden sm:inline",children:e("evolutionBot.defaultSettings")})]})}),u.jsxs(xt,{className:"overflow-y-auto sm:max-h-[600px] sm:max-w-[740px]",onCloseAutoFocus:p,children:[u.jsx(wt,{children:u.jsx(Ut,{children:e("evolutionBot.defaultSettings")})}),u.jsx(Tr,{...i,children:u.jsxs("form",{className:"w-full space-y-6",onSubmit:i.handleSubmit(d),children:[u.jsx("div",{children:u.jsxs("div",{className:"space-y-4",children:[u.jsx(Qt,{name:"botIdFallback",label:e("evolutionBot.form.botIdFallback.label"),options:(a==null?void 0:a.filter(f=>!!f.id).map(f=>({label:f.description,value:f.id})))??[]}),u.jsx(G,{name:"expire",label:e("evolutionBot.form.expire.label"),children:u.jsx(K,{type:"number"})}),u.jsx(G,{name:"keywordFinish",label:e("evolutionBot.form.keywordFinish.label"),children:u.jsx(K,{})}),u.jsx(G,{name:"delayMessage",label:e("evolutionBot.form.delayMessage.label"),children:u.jsx(K,{type:"number"})}),u.jsx(G,{name:"unknownMessage",label:e("evolutionBot.form.unknownMessage.label"),children:u.jsx(K,{})}),u.jsx(ke,{name:"listeningFromMe",label:e("evolutionBot.form.listeningFromMe.label"),reverse:!0}),u.jsx(ke,{name:"stopBotFromMe",label:e("evolutionBot.form.stopBotFromMe.label"),reverse:!0}),u.jsx(ke,{name:"keepOpen",label:e("evolutionBot.form.keepOpen.label"),reverse:!0}),u.jsx(G,{name:"debounceTime",label:e("evolutionBot.form.debounceTime.label"),children:u.jsx(K,{type:"number"})}),u.jsx(ke,{name:"splitMessages",label:e("evolutionBot.form.splitMessages.label"),reverse:!0}),i.watch("splitMessages")&&u.jsx(G,{name:"timePerChar",label:e("evolutionBot.form.timePerChar.label"),children:u.jsx(K,{type:"number"})}),u.jsx(Ru,{name:"ignoreJids",label:e("evolutionBot.form.ignoreJids.label"),placeholder:e("evolutionBot.form.ignoreJids.placeholder")})]})}),u.jsx(rn,{children:u.jsx(q,{type:"submit",children:e("evolutionBot.button.save")})})]})})]})]})}const nee=e=>["evolutionBot","fetchSessions",JSON.stringify(e)],ree=async({instanceName:e,evolutionBotId:t,token:n})=>(await he.get(`/evolutionBot/fetchSessions/${t}/${e}`,{headers:{apiKey:n}})).data,see=e=>{const{instanceName:t,token:n,evolutionBotId:r,...s}=e;return lt({...s,queryKey:nee({instanceName:t}),queryFn:()=>ree({instanceName:t,token:n,evolutionBotId:r}),enabled:!!t&&!!r&&(e.enabled??!0)})};function RI({evolutionBotId:e}){const{t}=ze(),{instance:n}=nt(),[r,s]=v.useState([]),[o,a]=v.useState(!1),[l,c]=v.useState(""),{data:i,refetch:d}=see({instanceName:n==null?void 0:n.name,evolutionBotId:e,enabled:o}),{changeStatusEvolutionBot:p}=Xg();function f(){d()}const h=async(m,x)=>{var b,y,w;try{if(!n)return;await p({instanceName:n.name,token:n.token,remoteJid:m,status:x}),X.success(t("evolutionBot.toast.success.status")),f()}catch(S){console.error("Error:",S),X.error(`Error : ${(w=(y=(b=S==null?void 0:S.response)==null?void 0:b.data)==null?void 0:y.response)==null?void 0:w.message}`)}},g=[{accessorKey:"remoteJid",header:()=>u.jsx("div",{className:"text-center",children:t("evolutionBot.sessions.table.remoteJid")}),cell:({row:m})=>u.jsx("div",{children:m.getValue("remoteJid")})},{accessorKey:"pushName",header:()=>u.jsx("div",{className:"text-center",children:t("evolutionBot.sessions.table.pushName")}),cell:({row:m})=>u.jsx("div",{children:m.getValue("pushName")})},{accessorKey:"sessionId",header:()=>u.jsx("div",{className:"text-center",children:t("evolutionBot.sessions.table.sessionId")}),cell:({row:m})=>u.jsx("div",{children:m.getValue("sessionId")})},{accessorKey:"status",header:()=>u.jsx("div",{className:"text-center",children:t("evolutionBot.sessions.table.status")}),cell:({row:m})=>u.jsx("div",{children:m.getValue("status")})},{id:"actions",enableHiding:!1,cell:({row:m})=>{const x=m.original;return u.jsxs(Eo,{children:[u.jsx(To,{asChild:!0,children:u.jsxs(q,{variant:"ghost",className:"h-8 w-8 p-0",children:[u.jsx("span",{className:"sr-only",children:t("evolutionBot.sessions.table.actions.title")}),u.jsx(vu,{className:"h-4 w-4"})]})}),u.jsxs(ps,{align:"end",children:[u.jsx(Ai,{children:t("evolutionBot.sessions.table.actions.title")}),u.jsx(Pa,{}),x.status!=="opened"&&u.jsxs(ft,{onClick:()=>h(x.remoteJid,"opened"),children:[u.jsx(qd,{className:"mr-2 h-4 w-4"}),t("evolutionBot.sessions.table.actions.open")]}),x.status!=="paused"&&x.status!=="closed"&&u.jsxs(ft,{onClick:()=>h(x.remoteJid,"paused"),children:[u.jsx(Kd,{className:"mr-2 h-4 w-4"}),t("evolutionBot.sessions.table.actions.pause")]}),x.status!=="closed"&&u.jsxs(ft,{onClick:()=>h(x.remoteJid,"closed"),children:[u.jsx(Ud,{className:"mr-2 h-4 w-4"}),t("evolutionBot.sessions.table.actions.close")]}),u.jsxs(ft,{onClick:()=>h(x.remoteJid,"delete"),children:[u.jsx(Vd,{className:"mr-2 h-4 w-4"}),t("evolutionBot.sessions.table.actions.delete")]})]})]})}}];return u.jsxs(Tt,{open:o,onOpenChange:a,children:[u.jsx(Nt,{asChild:!0,children:u.jsxs(q,{variant:"secondary",size:"sm",children:[u.jsx(Hd,{size:16,className:"mr-1"}),u.jsx("span",{className:"hidden sm:inline",children:t("evolutionBot.sessions.label")})]})}),u.jsxs(xt,{className:"overflow-y-auto sm:max-w-[950px]",onCloseAutoFocus:f,children:[u.jsx(wt,{children:u.jsx(Ut,{children:t("evolutionBot.sessions.label")})}),u.jsxs("div",{children:[u.jsxs("div",{className:"flex items-center justify-between gap-6 p-5",children:[u.jsx(K,{placeholder:t("evolutionBot.sessions.search"),value:l,onChange:m=>c(m.target.value)}),u.jsx(q,{variant:"outline",onClick:f,size:"icon",children:u.jsx(Wd,{})})]}),u.jsx(Nu,{columns:g,data:i??[],onSortingChange:s,state:{sorting:r,globalFilter:l},onGlobalFilterChange:c,enableGlobalFilter:!0,noResultsMessage:t("evolutionBot.sessions.table.none")})]})]})]})}const oee=_.object({enabled:_.boolean(),description:_.string(),apiUrl:_.string(),apiKey:_.string().optional(),triggerType:_.string(),triggerOperator:_.string().optional(),triggerValue:_.string().optional(),expire:_.coerce.number().optional(),keywordFinish:_.string().optional(),delayMessage:_.coerce.number().optional(),unknownMessage:_.string().optional(),listeningFromMe:_.boolean().optional(),stopBotFromMe:_.boolean().optional(),keepOpen:_.boolean().optional(),debounceTime:_.coerce.number().optional(),splitMessages:_.boolean().optional(),timePerChar:_.coerce.number().optional()});function PI({initialData:e,onSubmit:t,handleDelete:n,evolutionBotId:r,isModal:s=!1,isLoading:o=!1,openDeletionDialog:a=!1,setOpenDeletionDialog:l=()=>{}}){const{t:c}=ze(),i=sn({resolver:on(oee),defaultValues:e||{enabled:!0,description:"",apiUrl:"",apiKey:"",triggerType:"keyword",triggerOperator:"contains",triggerValue:"",expire:0,keywordFinish:"",delayMessage:0,unknownMessage:"",listeningFromMe:!1,stopBotFromMe:!1,keepOpen:!1,debounceTime:0,splitMessages:!1,timePerChar:0}}),d=i.watch("triggerType");return u.jsx(Tr,{...i,children:u.jsxs("form",{onSubmit:i.handleSubmit(t),className:"w-full space-y-6",children:[u.jsxs("div",{className:"space-y-4",children:[u.jsx(ke,{name:"enabled",label:c("evolutionBot.form.enabled.label"),reverse:!0}),u.jsx(G,{name:"description",label:c("evolutionBot.form.description.label"),required:!0,children:u.jsx(K,{})}),u.jsxs("div",{className:"flex flex-col",children:[u.jsx("h3",{className:"my-4 text-lg font-medium",children:c("evolutionBot.form.evolutionBotSettings.label")}),u.jsx($t,{})]}),u.jsx(G,{name:"apiUrl",label:c("evolutionBot.form.apiUrl.label"),required:!0,children:u.jsx(K,{})}),u.jsx(G,{name:"apiKey",label:c("evolutionBot.form.apiKey.label"),children:u.jsx(K,{type:"password"})}),u.jsxs("div",{className:"flex flex-col",children:[u.jsx("h3",{className:"my-4 text-lg font-medium",children:c("evolutionBot.form.triggerSettings.label")}),u.jsx($t,{})]}),u.jsx(Qt,{name:"triggerType",label:c("evolutionBot.form.triggerType.label"),options:[{label:c("evolutionBot.form.triggerType.keyword"),value:"keyword"},{label:c("evolutionBot.form.triggerType.all"),value:"all"},{label:c("evolutionBot.form.triggerType.advanced"),value:"advanced"},{label:c("evolutionBot.form.triggerType.none"),value:"none"}]}),d==="keyword"&&u.jsxs(u.Fragment,{children:[u.jsx(Qt,{name:"triggerOperator",label:c("evolutionBot.form.triggerOperator.label"),options:[{label:c("evolutionBot.form.triggerOperator.contains"),value:"contains"},{label:c("evolutionBot.form.triggerOperator.equals"),value:"equals"},{label:c("evolutionBot.form.triggerOperator.startsWith"),value:"startsWith"},{label:c("evolutionBot.form.triggerOperator.endsWith"),value:"endsWith"},{label:c("evolutionBot.form.triggerOperator.regex"),value:"regex"}]}),u.jsx(G,{name:"triggerValue",label:c("evolutionBot.form.triggerValue.label"),children:u.jsx(K,{})})]}),d==="advanced"&&u.jsx(G,{name:"triggerValue",label:c("evolutionBot.form.triggerConditions.label"),children:u.jsx(K,{})}),u.jsxs("div",{className:"flex flex-col",children:[u.jsx("h3",{className:"my-4 text-lg font-medium",children:c("evolutionBot.form.generalSettings.label")}),u.jsx($t,{})]}),u.jsx(G,{name:"expire",label:c("evolutionBot.form.expire.label"),children:u.jsx(K,{type:"number"})}),u.jsx(G,{name:"keywordFinish",label:c("evolutionBot.form.keywordFinish.label"),children:u.jsx(K,{})}),u.jsx(G,{name:"delayMessage",label:c("evolutionBot.form.delayMessage.label"),children:u.jsx(K,{type:"number"})}),u.jsx(G,{name:"unknownMessage",label:c("evolutionBot.form.unknownMessage.label"),children:u.jsx(K,{})}),u.jsx(ke,{name:"listeningFromMe",label:c("evolutionBot.form.listeningFromMe.label"),reverse:!0}),u.jsx(ke,{name:"stopBotFromMe",label:c("evolutionBot.form.stopBotFromMe.label"),reverse:!0}),u.jsx(ke,{name:"keepOpen",label:c("evolutionBot.form.keepOpen.label"),reverse:!0}),u.jsx(G,{name:"debounceTime",label:c("evolutionBot.form.debounceTime.label"),children:u.jsx(K,{type:"number"})}),u.jsx(ke,{name:"splitMessages",label:c("evolutionBot.form.splitMessages.label"),reverse:!0}),i.watch("splitMessages")&&u.jsx(G,{name:"timePerChar",label:c("evolutionBot.form.timePerChar.label"),children:u.jsx(K,{type:"number"})})]}),s&&u.jsx(rn,{children:u.jsx(q,{disabled:o,type:"submit",children:c(o?"evolutionBot.button.saving":"evolutionBot.button.save")})}),!s&&u.jsxs("div",{children:[u.jsx(RI,{evolutionBotId:r}),u.jsxs("div",{className:"mt-5 flex items-center gap-3",children:[u.jsxs(Tt,{open:a,onOpenChange:l,children:[u.jsx(Nt,{asChild:!0,children:u.jsx(q,{variant:"destructive",size:"sm",children:c("dify.button.delete")})}),u.jsx(xt,{children:u.jsxs(wt,{children:[u.jsx(Ut,{children:c("modal.delete.title")}),u.jsx(Fi,{children:c("modal.delete.messageSingle")}),u.jsxs(rn,{children:[u.jsx(q,{size:"sm",variant:"outline",onClick:()=>l(!1),children:c("button.cancel")}),u.jsx(q,{variant:"destructive",onClick:n,children:c("button.delete")})]})]})})]}),u.jsx(q,{disabled:o,type:"submit",children:c(o?"evolutionBot.button.saving":"evolutionBot.button.update")})]})]})]})})}function aee({resetTable:e}){const{t}=ze(),{instance:n}=nt(),[r,s]=v.useState(!1),[o,a]=v.useState(!1),{createEvolutionBot:l}=Xg(),c=async i=>{var d,p,f;try{if(!n||!n.name)throw new Error("instance not found");s(!0);const h={enabled:i.enabled,description:i.description,apiUrl:i.apiUrl,apiKey:i.apiKey,triggerType:i.triggerType,triggerOperator:i.triggerOperator||"",triggerValue:i.triggerValue||"",expire:i.expire||0,keywordFinish:i.keywordFinish||"",delayMessage:i.delayMessage||0,unknownMessage:i.unknownMessage||"",listeningFromMe:i.listeningFromMe||!1,stopBotFromMe:i.stopBotFromMe||!1,keepOpen:i.keepOpen||!1,debounceTime:i.debounceTime||0,splitMessages:i.splitMessages||!1,timePerChar:i.timePerChar?i.timePerChar:0};await l({instanceName:n.name,token:n.token,data:h}),X.success(t("evolutionBot.toast.success.create")),a(!1),e()}catch(h){console.error("Error:",h),X.error(`Error: ${(f=(p=(d=h==null?void 0:h.response)==null?void 0:d.data)==null?void 0:p.response)==null?void 0:f.message}`)}finally{s(!1)}};return u.jsxs(Tt,{open:o,onOpenChange:a,children:[u.jsx(Nt,{asChild:!0,children:u.jsxs(q,{size:"sm",children:[u.jsx(Ni,{size:16,className:"mr-1"}),u.jsx("span",{className:"hidden sm:inline",children:t("evolutionBot.button.create")})]})}),u.jsxs(xt,{className:"overflow-y-auto sm:max-h-[600px] sm:max-w-[740px]",children:[u.jsx(wt,{children:u.jsx(Ut,{children:t("evolutionBot.form.title")})}),u.jsx(PI,{onSubmit:c,isModal:!0,isLoading:r})]})]})}const iee=e=>["evolutionBot","getEvolutionBot",JSON.stringify(e)],lee=async({instanceName:e,token:t,evolutionBotId:n})=>{const r=await he.get(`/evolutionBot/fetch/${n}/${e}`,{headers:{apiKey:t}});return Array.isArray(r.data)?r.data[0]:r.data},uee=e=>{const{instanceName:t,token:n,evolutionBotId:r,...s}=e;return lt({...s,queryKey:iee({instanceName:t}),queryFn:()=>lee({instanceName:t,token:n,evolutionBotId:r}),enabled:!!t&&!!r&&(e.enabled??!0)})};function cee({evolutionBotId:e,resetTable:t}){const{t:n}=ze(),{instance:r}=nt(),s=An(),[o,a]=v.useState(!1),{deleteEvolutionBot:l,updateEvolutionBot:c}=Xg(),{data:i,isLoading:d}=uee({instanceName:r==null?void 0:r.name,evolutionBotId:e}),p=v.useMemo(()=>({enabled:(i==null?void 0:i.enabled)??!0,description:(i==null?void 0:i.description)??"",apiUrl:(i==null?void 0:i.apiUrl)??"",apiKey:(i==null?void 0:i.apiKey)??"",triggerType:(i==null?void 0:i.triggerType)??"",triggerOperator:(i==null?void 0:i.triggerOperator)??"",triggerValue:i==null?void 0:i.triggerValue,expire:(i==null?void 0:i.expire)??0,keywordFinish:i==null?void 0:i.keywordFinish,delayMessage:(i==null?void 0:i.delayMessage)??0,unknownMessage:i==null?void 0:i.unknownMessage,listeningFromMe:i==null?void 0:i.listeningFromMe,stopBotFromMe:!!(i!=null&&i.stopBotFromMe),keepOpen:!!(i!=null&&i.keepOpen),debounceTime:(i==null?void 0:i.debounceTime)??0,splitMessages:(i==null?void 0:i.splitMessages)??!1,timePerChar:i!=null&&i.timePerChar?i==null?void 0:i.timePerChar:0}),[i==null?void 0:i.apiKey,i==null?void 0:i.apiUrl,i==null?void 0:i.debounceTime,i==null?void 0:i.delayMessage,i==null?void 0:i.description,i==null?void 0:i.enabled,i==null?void 0:i.expire,i==null?void 0:i.keepOpen,i==null?void 0:i.keywordFinish,i==null?void 0:i.listeningFromMe,i==null?void 0:i.stopBotFromMe,i==null?void 0:i.triggerOperator,i==null?void 0:i.triggerType,i==null?void 0:i.triggerValue,i==null?void 0:i.unknownMessage,i==null?void 0:i.splitMessages,i==null?void 0:i.timePerChar]),f=async g=>{var m,x,b;try{if(r&&r.name&&e){const y={enabled:g.enabled,description:g.description,apiUrl:g.apiUrl,apiKey:g.apiKey,triggerType:g.triggerType,triggerOperator:g.triggerOperator||"",triggerValue:g.triggerValue||"",expire:g.expire||0,keywordFinish:g.keywordFinish||"",delayMessage:g.delayMessage||1e3,unknownMessage:g.unknownMessage||"",listeningFromMe:g.listeningFromMe||!1,stopBotFromMe:g.stopBotFromMe||!1,keepOpen:g.keepOpen||!1,debounceTime:g.debounceTime||0,splitMessages:g.splitMessages||!1,timePerChar:g.timePerChar?g.timePerChar:0};await c({instanceName:r.name,evolutionBotId:e,data:y}),X.success(n("evolutionBot.toast.success.update")),t(),s(`/manager/instance/${r.id}/evolutionBot/${e}`)}else console.error("Token not found")}catch(y){console.error("Error:",y),X.error(`Error: ${(b=(x=(m=y==null?void 0:y.response)==null?void 0:m.data)==null?void 0:x.response)==null?void 0:b.message}`)}},h=async()=>{try{r&&r.name&&e?(await l({instanceName:r.name,evolutionBotId:e}),X.success(n("evolutionBot.toast.success.delete")),a(!1),t(),s(`/manager/instance/${r.id}/evolutionBot`)):console.error("instance not found")}catch(g){console.error("Erro ao excluir evolutionBot:",g)}};return d?u.jsx(wr,{}):u.jsx("div",{className:"m-4",children:u.jsx(PI,{initialData:p,onSubmit:f,evolutionBotId:e,handleDelete:h,isModal:!1,openDeletionDialog:o,setOpenDeletionDialog:a})})}function rE(){const{t:e}=ze(),t=Ou("(min-width: 768px)"),{instance:n}=nt(),{evolutionBotId:r}=So(),{data:s,isLoading:o,refetch:a}=jI({instanceName:n==null?void 0:n.name}),l=An(),c=d=>{n&&l(`/manager/instance/${n.id}/evolutionBot/${d}`)},i=()=>{a()};return u.jsxs("main",{className:"pt-5",children:[u.jsxs("div",{className:"mb-1 flex items-center justify-between",children:[u.jsx("h3",{className:"text-lg font-medium",children:e("evolutionBot.title")}),u.jsxs("div",{className:"flex items-center justify-end gap-2",children:[u.jsx(RI,{}),u.jsx(tee,{}),u.jsx(aee,{resetTable:i})]})]}),u.jsx($t,{className:"my-4"}),u.jsxs(Pu,{direction:t?"horizontal":"vertical",children:[u.jsx(Ur,{defaultSize:35,className:"pr-4",children:u.jsx("div",{className:"flex flex-col gap-3",children:o?u.jsx(wr,{}):u.jsx(u.Fragment,{children:s&&s.length>0&&Array.isArray(s)?s.map(d=>u.jsx(q,{className:"flex h-auto flex-col items-start justify-start",onClick:()=>c(`${d.id}`),variant:r===d.id?"secondary":"outline",children:u.jsx("h4",{className:"text-base",children:d.description||d.id})},d.id)):u.jsx(q,{variant:"link",children:e("evolutionBot.table.none")})})})}),r&&u.jsxs(u.Fragment,{children:[u.jsx(Mu,{withHandle:!0,className:"border border-border"}),u.jsx(Ur,{children:u.jsx(cee,{evolutionBotId:r,resetTable:i})})]})]})]})}const dee=e=>["flowise","findFlowise",JSON.stringify(e)],fee=async({instanceName:e,token:t})=>(await he.get(`/flowise/find/${e}`,{headers:{apiKey:t}})).data,MI=e=>{const{instanceName:t,token:n,...r}=e;return lt({...r,queryKey:dee({instanceName:t}),queryFn:()=>fee({instanceName:t,token:n}),enabled:!!t&&(e.enabled??!0)})},pee=e=>["flowise","fetchDefaultSettings",JSON.stringify(e)],hee=async({instanceName:e,token:t})=>{const n=await he.get(`/flowise/fetchSettings/${e}`,{headers:{apiKey:t}});return Array.isArray(n.data)?n.data[0]:n.data},gee=e=>{const{instanceName:t,token:n,...r}=e;return lt({...r,queryKey:pee({instanceName:t}),queryFn:()=>hee({instanceName:t,token:n}),enabled:!!t&&(e.enabled??!0)})},mee=async({instanceName:e,token:t,data:n})=>(await he.post(`/flowise/create/${e}`,n,{headers:{apikey:t}})).data,vee=async({instanceName:e,flowiseId:t,data:n})=>(await he.put(`/flowise/update/${t}/${e}`,n)).data,yee=async({instanceName:e,flowiseId:t})=>(await he.delete(`/flowise/delete/${t}/${e}`)).data,bee=async({instanceName:e,token:t,remoteJid:n,status:r})=>(await he.post(`/flowise/changeStatus/${e}`,{remoteJid:n,status:r},{headers:{apikey:t}})).data,xee=async({instanceName:e,token:t,data:n})=>(await he.post(`/flowise/settings/${e}`,n,{headers:{apikey:t}})).data;function em(){const e=Ye(xee,{invalidateKeys:[["flowise","fetchDefaultSettings"]]}),t=Ye(bee,{invalidateKeys:[["flowise","getFlowise"],["flowise","fetchSessions"]]}),n=Ye(yee,{invalidateKeys:[["flowise","getFlowise"],["flowise","findFlowise"],["flowise","fetchSessions"]]}),r=Ye(vee,{invalidateKeys:[["flowise","getFlowise"],["flowise","findFlowise"],["flowise","fetchSessions"]]}),s=Ye(mee,{invalidateKeys:[["flowise","findFlowise"]]});return{setDefaultSettingsFlowise:e,changeStatusFlowise:t,deleteFlowise:n,updateFlowise:r,createFlowise:s}}const wee=_.object({expire:_.string(),keywordFinish:_.string(),delayMessage:_.string(),unknownMessage:_.string(),listeningFromMe:_.boolean(),stopBotFromMe:_.boolean(),keepOpen:_.boolean(),debounceTime:_.string(),ignoreJids:_.array(_.string()).default([]),flowiseIdFallback:_.union([_.null(),_.string()]).optional(),splitMessages:_.boolean(),timePerChar:_.string()});function See(){const{t:e}=ze(),{instance:t}=nt(),{setDefaultSettingsFlowise:n}=em(),[r,s]=v.useState(!1),{data:o,refetch:a}=gee({instanceName:t==null?void 0:t.name,enabled:r}),{data:l,refetch:c}=MI({instanceName:t==null?void 0:t.name,enabled:r}),i=sn({resolver:on(wee),defaultValues:{expire:"0",keywordFinish:e("flowise.form.examples.keywordFinish"),delayMessage:"1000",unknownMessage:e("flowise.form.examples.unknownMessage"),listeningFromMe:!1,stopBotFromMe:!1,keepOpen:!1,debounceTime:"0",ignoreJids:[],flowiseIdFallback:void 0,splitMessages:!1,timePerChar:"0"}});v.useEffect(()=>{o&&i.reset({expire:o!=null&&o.expire?o.expire.toString():"0",keywordFinish:o.keywordFinish,delayMessage:o.delayMessage?o.delayMessage.toString():"0",unknownMessage:o.unknownMessage,listeningFromMe:o.listeningFromMe,stopBotFromMe:o.stopBotFromMe,keepOpen:o.keepOpen,debounceTime:o.debounceTime?o.debounceTime.toString():"0",ignoreJids:o.ignoreJids,flowiseIdFallback:o.flowiseIdFallback,splitMessages:o.splitMessages,timePerChar:o.timePerChar?o.timePerChar.toString():"0"})},[o]);const d=async f=>{var h,g,m;try{if(!t||!t.name)throw new Error("instance not found.");const x={expire:parseInt(f.expire),keywordFinish:f.keywordFinish,delayMessage:parseInt(f.delayMessage),unknownMessage:f.unknownMessage,listeningFromMe:f.listeningFromMe,stopBotFromMe:f.stopBotFromMe,keepOpen:f.keepOpen,debounceTime:parseInt(f.debounceTime),flowiseIdFallback:f.flowiseIdFallback||void 0,ignoreJids:f.ignoreJids,splitMessages:f.splitMessages,timePerChar:parseInt(f.timePerChar)};await n({instanceName:t.name,token:t.token,data:x}),X.success(e("flowise.toast.defaultSettings.success"))}catch(x){console.error("Error:",x),X.error(`Error: ${(m=(g=(h=x==null?void 0:x.response)==null?void 0:h.data)==null?void 0:g.response)==null?void 0:m.message}`)}};function p(){a(),c()}return u.jsxs(Tt,{open:r,onOpenChange:s,children:[u.jsx(Nt,{asChild:!0,children:u.jsxs(q,{variant:"secondary",size:"sm",children:[u.jsx(Oi,{size:16,className:"mr-1"}),u.jsx("span",{className:"hidden sm:inline",children:e("flowise.defaultSettings")})]})}),u.jsxs(xt,{className:"overflow-y-auto sm:max-h-[600px] sm:max-w-[740px]",onCloseAutoFocus:p,children:[u.jsx(wt,{children:u.jsx(Ut,{children:e("flowise.defaultSettings")})}),u.jsx(Tr,{...i,children:u.jsxs("form",{className:"w-full space-y-6",onSubmit:i.handleSubmit(d),children:[u.jsx("div",{children:u.jsxs("div",{className:"space-y-4",children:[u.jsx(Qt,{name:"flowiseIdFallback",label:e("flowise.form.flowiseIdFallback.label"),options:(l==null?void 0:l.filter(f=>!!f.id).map(f=>({label:f.description,value:f.id})))??[]}),u.jsx(G,{name:"expire",label:e("flowise.form.expire.label"),children:u.jsx(K,{type:"number"})}),u.jsx(G,{name:"keywordFinish",label:e("flowise.form.keywordFinish.label"),children:u.jsx(K,{})}),u.jsx(G,{name:"delayMessage",label:e("flowise.form.delayMessage.label"),children:u.jsx(K,{type:"number"})}),u.jsx(G,{name:"unknownMessage",label:e("flowise.form.unknownMessage.label"),children:u.jsx(K,{})}),u.jsx(ke,{name:"listeningFromMe",label:e("flowise.form.listeningFromMe.label"),reverse:!0}),u.jsx(ke,{name:"stopBotFromMe",label:e("flowise.form.stopBotFromMe.label"),reverse:!0}),u.jsx(ke,{name:"keepOpen",label:e("flowise.form.keepOpen.label"),reverse:!0}),u.jsx(G,{name:"debounceTime",label:e("flowise.form.debounceTime.label"),children:u.jsx(K,{type:"number"})}),u.jsx(ke,{name:"splitMessages",label:e("flowise.form.splitMessages.label"),reverse:!0}),i.watch("splitMessages")&&u.jsx(G,{name:"timePerChar",label:e("flowise.form.timePerChar.label"),children:u.jsx(K,{type:"number"})}),u.jsx(Ru,{name:"ignoreJids",label:e("flowise.form.ignoreJids.label"),placeholder:e("flowise.form.ignoreJids.placeholder")})]})}),u.jsx(rn,{children:u.jsx(q,{type:"submit",children:e("flowise.button.save")})})]})})]})]})}const Cee=e=>["flowise","fetchSessions",JSON.stringify(e)],Eee=async({instanceName:e,flowiseId:t,token:n})=>(await he.get(`/flowise/fetchSessions/${t}/${e}`,{headers:{apiKey:n}})).data,Tee=e=>{const{instanceName:t,token:n,flowiseId:r,...s}=e;return lt({...s,queryKey:Cee({instanceName:t}),queryFn:()=>Eee({instanceName:t,token:n,flowiseId:r}),enabled:!!t&&!!r&&(e.enabled??!0)})};function OI({flowiseId:e}){const{t}=ze(),{instance:n}=nt(),{changeStatusFlowise:r}=em(),[s,o]=v.useState([]),[a,l]=v.useState(!1),[c,i]=v.useState(""),{data:d,refetch:p}=Tee({instanceName:n==null?void 0:n.name,flowiseId:e,enabled:a});function f(){p()}const h=async(m,x)=>{var b,y,w;try{if(!n)return;await r({instanceName:n.name,token:n.token,remoteJid:m,status:x}),X.success(t("flowise.toast.success.status")),f()}catch(S){console.error("Error:",S),X.error(`Error : ${(w=(y=(b=S==null?void 0:S.response)==null?void 0:b.data)==null?void 0:y.response)==null?void 0:w.message}`)}},g=[{accessorKey:"remoteJid",header:()=>u.jsx("div",{className:"text-center",children:t("flowise.sessions.table.remoteJid")}),cell:({row:m})=>u.jsx("div",{children:m.getValue("remoteJid")})},{accessorKey:"pushName",header:()=>u.jsx("div",{className:"text-center",children:t("flowise.sessions.table.pushName")}),cell:({row:m})=>u.jsx("div",{children:m.getValue("pushName")})},{accessorKey:"sessionId",header:()=>u.jsx("div",{className:"text-center",children:t("flowise.sessions.table.sessionId")}),cell:({row:m})=>u.jsx("div",{children:m.getValue("sessionId")})},{accessorKey:"status",header:()=>u.jsx("div",{className:"text-center",children:t("flowise.sessions.table.status")}),cell:({row:m})=>u.jsx("div",{children:m.getValue("status")})},{id:"actions",enableHiding:!1,cell:({row:m})=>{const x=m.original;return u.jsxs(Eo,{children:[u.jsx(To,{asChild:!0,children:u.jsxs(q,{variant:"ghost",className:"h-8 w-8 p-0",children:[u.jsx("span",{className:"sr-only",children:t("flowise.sessions.table.actions.title")}),u.jsx(vu,{className:"h-4 w-4"})]})}),u.jsxs(ps,{align:"end",children:[u.jsx(Ai,{children:t("flowise.sessions.table.actions.title")}),u.jsx(Pa,{}),x.status!=="opened"&&u.jsxs(ft,{onClick:()=>h(x.remoteJid,"opened"),children:[u.jsx(qd,{className:"mr-2 h-4 w-4"}),t("flowise.sessions.table.actions.open")]}),x.status!=="paused"&&x.status!=="closed"&&u.jsxs(ft,{onClick:()=>h(x.remoteJid,"paused"),children:[u.jsx(Kd,{className:"mr-2 h-4 w-4"}),t("flowise.sessions.table.actions.pause")]}),x.status!=="closed"&&u.jsxs(ft,{onClick:()=>h(x.remoteJid,"closed"),children:[u.jsx(Ud,{className:"mr-2 h-4 w-4"}),t("flowise.sessions.table.actions.close")]}),u.jsxs(ft,{onClick:()=>h(x.remoteJid,"delete"),children:[u.jsx(Vd,{className:"mr-2 h-4 w-4"}),t("flowise.sessions.table.actions.delete")]})]})]})}}];return u.jsxs(Tt,{open:a,onOpenChange:l,children:[u.jsx(Nt,{asChild:!0,children:u.jsxs(q,{variant:"secondary",size:"sm",children:[u.jsx(Hd,{size:16,className:"mr-1"}),u.jsx("span",{className:"hidden sm:inline",children:t("flowise.sessions.label")})]})}),u.jsxs(xt,{className:"overflow-y-auto sm:max-w-[950px]",onCloseAutoFocus:f,children:[u.jsx(wt,{children:u.jsx(Ut,{children:t("flowise.sessions.label")})}),u.jsxs("div",{children:[u.jsxs("div",{className:"flex items-center justify-between gap-6 p-5",children:[u.jsx(K,{placeholder:t("flowise.sessions.search"),value:c,onChange:m=>i(m.target.value)}),u.jsx(q,{variant:"outline",onClick:f,size:"icon",children:u.jsx(Wd,{})})]}),u.jsx(Nu,{columns:g,data:d??[],onSortingChange:o,state:{sorting:s,globalFilter:c},onGlobalFilterChange:i,enableGlobalFilter:!0,noResultsMessage:t("flowise.sessions.table.none")})]})]})]})}const kee=_.object({enabled:_.boolean(),description:_.string(),apiUrl:_.string(),apiKey:_.string().optional(),triggerType:_.string(),triggerOperator:_.string().optional(),triggerValue:_.string().optional(),expire:_.coerce.number().optional(),keywordFinish:_.string().optional(),delayMessage:_.coerce.number().optional(),unknownMessage:_.string().optional(),listeningFromMe:_.boolean().optional(),stopBotFromMe:_.boolean().optional(),keepOpen:_.boolean().optional(),debounceTime:_.coerce.number().optional(),splitMessages:_.boolean().optional(),timePerChar:_.coerce.number().optional()});function NI({initialData:e,onSubmit:t,handleDelete:n,flowiseId:r,isModal:s=!1,isLoading:o=!1,openDeletionDialog:a=!1,setOpenDeletionDialog:l=()=>{}}){const{t:c}=ze(),i=sn({resolver:on(kee),defaultValues:e||{enabled:!0,description:"",apiUrl:"",apiKey:"",triggerType:"keyword",triggerOperator:"contains",triggerValue:"",expire:0,keywordFinish:"",delayMessage:0,unknownMessage:"",listeningFromMe:!1,stopBotFromMe:!1,keepOpen:!1,debounceTime:0,splitMessages:!1,timePerChar:0}}),d=i.watch("triggerType");return u.jsx(Tr,{...i,children:u.jsxs("form",{onSubmit:i.handleSubmit(t),className:"w-full space-y-6",children:[u.jsxs("div",{className:"space-y-4",children:[u.jsx(ke,{name:"enabled",label:c("flowise.form.enabled.label"),reverse:!0}),u.jsx(G,{name:"description",label:c("flowise.form.description.label"),required:!0,children:u.jsx(K,{})}),u.jsxs("div",{className:"flex flex-col",children:[u.jsx("h3",{className:"my-4 text-lg font-medium",children:c("flowise.form.flowiseSettings.label")}),u.jsx($t,{})]}),u.jsx(G,{name:"apiUrl",label:c("flowise.form.apiUrl.label"),required:!0,children:u.jsx(K,{})}),u.jsx(G,{name:"apiKey",label:c("flowise.form.apiKey.label"),children:u.jsx(K,{type:"password"})}),u.jsxs("div",{className:"flex flex-col",children:[u.jsx("h3",{className:"my-4 text-lg font-medium",children:c("flowise.form.triggerSettings.label")}),u.jsx($t,{})]}),u.jsx(Qt,{name:"triggerType",label:c("flowise.form.triggerType.label"),options:[{label:c("flowise.form.triggerType.keyword"),value:"keyword"},{label:c("flowise.form.triggerType.all"),value:"all"},{label:c("flowise.form.triggerType.advanced"),value:"advanced"},{label:c("flowise.form.triggerType.none"),value:"none"}]}),d==="keyword"&&u.jsxs(u.Fragment,{children:[u.jsx(Qt,{name:"triggerOperator",label:c("flowise.form.triggerOperator.label"),options:[{label:c("flowise.form.triggerOperator.contains"),value:"contains"},{label:c("flowise.form.triggerOperator.equals"),value:"equals"},{label:c("flowise.form.triggerOperator.startsWith"),value:"startsWith"},{label:c("flowise.form.triggerOperator.endsWith"),value:"endsWith"},{label:c("flowise.form.triggerOperator.regex"),value:"regex"}]}),u.jsx(G,{name:"triggerValue",label:c("flowise.form.triggerValue.label"),children:u.jsx(K,{})})]}),d==="advanced"&&u.jsx(G,{name:"triggerValue",label:c("flowise.form.triggerConditions.label"),children:u.jsx(K,{})}),u.jsxs("div",{className:"flex flex-col",children:[u.jsx("h3",{className:"my-4 text-lg font-medium",children:c("flowise.form.generalSettings.label")}),u.jsx($t,{})]}),u.jsx(G,{name:"expire",label:c("flowise.form.expire.label"),children:u.jsx(K,{type:"number"})}),u.jsx(G,{name:"keywordFinish",label:c("flowise.form.keywordFinish.label"),children:u.jsx(K,{})}),u.jsx(G,{name:"delayMessage",label:c("flowise.form.delayMessage.label"),children:u.jsx(K,{type:"number"})}),u.jsx(G,{name:"unknownMessage",label:c("flowise.form.unknownMessage.label"),children:u.jsx(K,{})}),u.jsx(ke,{name:"listeningFromMe",label:c("flowise.form.listeningFromMe.label"),reverse:!0}),u.jsx(ke,{name:"stopBotFromMe",label:c("flowise.form.stopBotFromMe.label"),reverse:!0}),u.jsx(ke,{name:"keepOpen",label:c("flowise.form.keepOpen.label"),reverse:!0}),u.jsx(G,{name:"debounceTime",label:c("flowise.form.debounceTime.label"),children:u.jsx(K,{type:"number"})}),u.jsx(ke,{name:"splitMessages",label:c("flowise.form.splitMessages.label"),reverse:!0}),i.watch("splitMessages")&&u.jsx(G,{name:"timePerChar",label:c("flowise.form.timePerChar.label"),children:u.jsx(K,{type:"number"})})]}),s&&u.jsx(rn,{children:u.jsx(q,{disabled:o,type:"submit",children:c(o?"flowise.button.saving":"flowise.button.save")})}),!s&&u.jsxs("div",{children:[u.jsx(OI,{flowiseId:r}),u.jsxs("div",{className:"mt-5 flex items-center gap-3",children:[u.jsxs(Tt,{open:a,onOpenChange:l,children:[u.jsx(Nt,{asChild:!0,children:u.jsx(q,{variant:"destructive",size:"sm",children:c("dify.button.delete")})}),u.jsx(xt,{children:u.jsxs(wt,{children:[u.jsx(Ut,{children:c("modal.delete.title")}),u.jsx(Fi,{children:c("modal.delete.messageSingle")}),u.jsxs(rn,{children:[u.jsx(q,{size:"sm",variant:"outline",onClick:()=>l(!1),children:c("button.cancel")}),u.jsx(q,{variant:"destructive",onClick:n,children:c("button.delete")})]})]})})]}),u.jsx(q,{disabled:o,type:"submit",children:c(o?"flowise.button.saving":"flowise.button.update")})]})]})]})})}function _ee({resetTable:e}){const{t}=ze(),{instance:n}=nt(),{createFlowise:r}=em(),[s,o]=v.useState(!1),[a,l]=v.useState(!1),c=async i=>{var d,p,f;try{if(!n||!n.name)throw new Error("instance not found");o(!0);const h={enabled:i.enabled,description:i.description,apiUrl:i.apiUrl,apiKey:i.apiKey,triggerType:i.triggerType,triggerOperator:i.triggerOperator||"",triggerValue:i.triggerValue||"",expire:i.expire||0,keywordFinish:i.keywordFinish||"",delayMessage:i.delayMessage||0,unknownMessage:i.unknownMessage||"",listeningFromMe:i.listeningFromMe||!1,stopBotFromMe:i.stopBotFromMe||!1,keepOpen:i.keepOpen||!1,debounceTime:i.debounceTime||0,splitMessages:i.splitMessages||!1,timePerChar:i.timePerChar||0};await r({instanceName:n.name,token:n.token,data:h}),X.success(t("flowise.toast.success.create")),l(!1),e()}catch(h){console.error("Error:",h),X.error(`Error: ${(f=(p=(d=h==null?void 0:h.response)==null?void 0:d.data)==null?void 0:p.response)==null?void 0:f.message}`)}finally{o(!1)}};return u.jsxs(Tt,{open:a,onOpenChange:l,children:[u.jsx(Nt,{asChild:!0,children:u.jsxs(q,{size:"sm",children:[u.jsx(Ni,{size:16,className:"mr-1"}),u.jsx("span",{className:"hidden sm:inline",children:t("flowise.button.create")})]})}),u.jsxs(xt,{className:"overflow-y-auto sm:max-h-[600px] sm:max-w-[740px]",children:[u.jsx(wt,{children:u.jsx(Ut,{children:t("flowise.form.title")})}),u.jsx(NI,{onSubmit:c,isModal:!0,isLoading:s})]})]})}const jee=e=>["flowise","getFlowise",JSON.stringify(e)],Ree=async({instanceName:e,token:t,flowiseId:n})=>{const r=await he.get(`/flowise/fetch/${n}/${e}`,{headers:{apiKey:t}});return Array.isArray(r.data)?r.data[0]:r.data},Pee=e=>{const{instanceName:t,token:n,flowiseId:r,...s}=e;return lt({...s,queryKey:jee({instanceName:t}),queryFn:()=>Ree({instanceName:t,token:n,flowiseId:r}),enabled:!!t&&!!r&&(e.enabled??!0)})};function Mee({flowiseId:e,resetTable:t}){const{t:n}=ze(),{instance:r}=nt(),s=An(),[o,a]=v.useState(!1),{deleteFlowise:l,updateFlowise:c}=em(),{data:i,isLoading:d}=Pee({instanceName:r==null?void 0:r.name,flowiseId:e}),p=v.useMemo(()=>({enabled:(i==null?void 0:i.enabled)??!0,description:(i==null?void 0:i.description)??"",apiUrl:(i==null?void 0:i.apiUrl)??"",apiKey:(i==null?void 0:i.apiKey)??"",triggerType:(i==null?void 0:i.triggerType)??"",triggerOperator:(i==null?void 0:i.triggerOperator)??"",triggerValue:i==null?void 0:i.triggerValue,expire:(i==null?void 0:i.expire)??0,keywordFinish:i==null?void 0:i.keywordFinish,delayMessage:(i==null?void 0:i.delayMessage)??0,unknownMessage:i==null?void 0:i.unknownMessage,listeningFromMe:i==null?void 0:i.listeningFromMe,stopBotFromMe:i==null?void 0:i.stopBotFromMe,keepOpen:i==null?void 0:i.keepOpen,debounceTime:(i==null?void 0:i.debounceTime)??0,splitMessages:(i==null?void 0:i.splitMessages)??!1,timePerChar:(i==null?void 0:i.timePerChar)??0}),[i==null?void 0:i.apiKey,i==null?void 0:i.apiUrl,i==null?void 0:i.debounceTime,i==null?void 0:i.delayMessage,i==null?void 0:i.description,i==null?void 0:i.enabled,i==null?void 0:i.expire,i==null?void 0:i.keepOpen,i==null?void 0:i.keywordFinish,i==null?void 0:i.listeningFromMe,i==null?void 0:i.stopBotFromMe,i==null?void 0:i.triggerOperator,i==null?void 0:i.triggerType,i==null?void 0:i.triggerValue,i==null?void 0:i.unknownMessage,i==null?void 0:i.splitMessages,i==null?void 0:i.timePerChar]),f=async g=>{var m,x,b;try{if(r&&r.name&&e){const y={enabled:g.enabled,description:g.description,apiUrl:g.apiUrl,apiKey:g.apiKey,triggerType:g.triggerType,triggerOperator:g.triggerOperator||"",triggerValue:g.triggerValue||"",expire:g.expire||0,keywordFinish:g.keywordFinish||"",delayMessage:g.delayMessage||1e3,unknownMessage:g.unknownMessage||"",listeningFromMe:g.listeningFromMe||!1,stopBotFromMe:g.stopBotFromMe||!1,keepOpen:g.keepOpen||!1,debounceTime:g.debounceTime||0,splitMessages:g.splitMessages||!1,timePerChar:g.timePerChar||0};await c({instanceName:r.name,flowiseId:e,data:y}),X.success(n("flowise.toast.success.update")),t(),s(`/manager/instance/${r.id}/flowise/${e}`)}else console.error("Token not found")}catch(y){console.error("Error:",y),X.error(`Error: ${(b=(x=(m=y==null?void 0:y.response)==null?void 0:m.data)==null?void 0:x.response)==null?void 0:b.message}`)}},h=async()=>{try{r&&r.name&&e?(await l({instanceName:r.name,flowiseId:e}),X.success(n("flowise.toast.success.delete")),a(!1),t(),s(`/manager/instance/${r.id}/flowise`)):console.error("instance not found")}catch(g){console.error("Erro ao excluir dify:",g)}};return d?u.jsx(wr,{}):u.jsx("div",{className:"m-4",children:u.jsx(NI,{initialData:p,onSubmit:f,flowiseId:e,handleDelete:h,isModal:!1,isLoading:d,openDeletionDialog:o,setOpenDeletionDialog:a})})}function sE(){const{t:e}=ze(),t=Ou("(min-width: 768px)"),{instance:n}=nt(),{flowiseId:r}=So(),{data:s,isLoading:o,refetch:a}=MI({instanceName:n==null?void 0:n.name}),l=An(),c=d=>{n&&l(`/manager/instance/${n.id}/flowise/${d}`)},i=()=>{a()};return u.jsxs("main",{className:"pt-5",children:[u.jsxs("div",{className:"mb-1 flex items-center justify-between",children:[u.jsx("h3",{className:"text-lg font-medium",children:e("flowise.title")}),u.jsxs("div",{className:"flex items-center justify-end gap-2",children:[u.jsx(OI,{}),u.jsx(See,{}),u.jsx(_ee,{resetTable:i})]})]}),u.jsx($t,{className:"my-4"}),u.jsxs(Pu,{direction:t?"horizontal":"vertical",children:[u.jsx(Ur,{defaultSize:35,className:"pr-4",children:u.jsx("div",{className:"flex flex-col gap-3",children:o?u.jsx(wr,{}):u.jsx(u.Fragment,{children:s&&s.length>0&&Array.isArray(s)?s.map(d=>u.jsx(q,{className:"flex h-auto flex-col items-start justify-start",onClick:()=>c(`${d.id}`),variant:r===d.id?"secondary":"outline",children:u.jsx("h4",{className:"text-base",children:d.description||d.id})},d.id)):u.jsx(q,{variant:"link",children:e("flowise.table.none")})})})}),r&&u.jsxs(u.Fragment,{children:[u.jsx(Mu,{withHandle:!0,className:"border border-border"}),u.jsx(Ur,{children:u.jsx(Mee,{flowiseId:r,resetTable:i})})]})]})]})}const Oee=e=>["openai","findOpenai",JSON.stringify(e)],Nee=async({instanceName:e,token:t})=>(await he.get(`/openai/find/${e}`,{headers:{apiKey:t}})).data,II=e=>{const{instanceName:t,token:n,...r}=e;return lt({...r,queryKey:Oee({instanceName:t}),queryFn:()=>Nee({instanceName:t,token:n}),enabled:!!t&&(e.enabled??!0)})},Iee=e=>["openai","findOpenaiCreds",JSON.stringify(e)],Dee=async({instanceName:e,token:t})=>(await he.get(`/openai/creds/${e}`,{headers:{apiKey:t}})).data,Vw=e=>{const{instanceName:t,token:n,...r}=e;return lt({staleTime:1e3*60*60*6,...r,queryKey:Iee({instanceName:t}),queryFn:()=>Dee({instanceName:t,token:n}),enabled:!!t&&(e.enabled??!0)})},Aee=async({instanceName:e,token:t,data:n})=>(await he.post(`/openai/creds/${e}`,n,{headers:{apikey:t}})).data,Fee=async({openaiCredsId:e,instanceName:t})=>(await he.delete(`/openai/creds/${e}/${t}`)).data,Lee=async({instanceName:e,token:t,data:n})=>(await he.post(`/openai/create/${e}`,n,{headers:{apikey:t}})).data,$ee=async({instanceName:e,token:t,openaiId:n,data:r})=>(await he.put(`/openai/update/${n}/${e}`,r,{headers:{apikey:t}})).data,Bee=async({instanceName:e,token:t,openaiId:n})=>(await he.delete(`/openai/delete/${n}/${e}`,{headers:{apikey:t}})).data,zee=async({instanceName:e,token:t,data:n})=>(await he.post(`/openai/settings/${e}`,n,{headers:{apikey:t}})).data,Uee=async({instanceName:e,token:t,remoteJid:n,status:r})=>(await he.post(`/openai/changeStatus/${e}`,{remoteJid:n,status:r},{headers:{apikey:t}})).data;function rf(){const e=Ye(zee,{invalidateKeys:[["openai","fetchDefaultSettings"]]}),t=Ye(Uee,{invalidateKeys:[["openai","getOpenai"],["openai","fetchSessions"]]}),n=Ye(Bee,{invalidateKeys:[["openai","getOpenai"],["openai","findOpenai"],["openai","fetchSessions"]]}),r=Ye($ee,{invalidateKeys:[["openai","getOpenai"],["openai","findOpenai"],["openai","fetchSessions"]]}),s=Ye(Lee,{invalidateKeys:[["openai","findOpenai"]]}),o=Ye(Aee,{invalidateKeys:[["openai","findOpenaiCreds"]]}),a=Ye(Fee,{invalidateKeys:[["openai","findOpenaiCreds"]]});return{setDefaultSettingsOpenai:e,changeStatusOpenai:t,deleteOpenai:n,updateOpenai:r,createOpenai:s,createOpenaiCreds:o,deleteOpenaiCreds:a}}const Vee=_.object({name:_.string(),apiKey:_.string()});function Hee(){const{t:e}=ze(),{instance:t}=nt(),{createOpenaiCreds:n,deleteOpenaiCreds:r}=rf(),[s,o]=v.useState(!1),[a,l]=v.useState([]),{data:c,refetch:i}=Vw({instanceName:t==null?void 0:t.name,enabled:s}),d=sn({resolver:on(Vee),defaultValues:{name:"",apiKey:""}}),p=async m=>{var x,b,y;try{if(!t||!t.name)throw new Error("instance not found.");const w={name:m.name,apiKey:m.apiKey};await n({instanceName:t.name,token:t.token,data:w}),X.success(e("openai.toast.success.credentialsCreate")),f()}catch(w){console.error("Error:",w),X.error(`Error: ${(y=(b=(x=w==null?void 0:w.response)==null?void 0:x.data)==null?void 0:b.response)==null?void 0:y.message}`)}};function f(){d.reset(),i()}const h=async m=>{var x,b,y;if(!(t!=null&&t.name)){X.error("Instance not found.");return}try{await r({openaiCredsId:m,instanceName:t==null?void 0:t.name}),X.success(e("openai.toast.success.credentialsDelete")),i()}catch(w){console.error("Error:",w),X.error(`Error: ${(y=(b=(x=w==null?void 0:w.response)==null?void 0:x.data)==null?void 0:b.response)==null?void 0:y.message}`)}},g=[{accessorKey:"name",header:({column:m})=>u.jsxs(q,{variant:"ghost",onClick:()=>m.toggleSorting(m.getIsSorted()==="asc"),children:[e("openai.credentials.table.name"),u.jsx(_3,{className:"ml-2 h-4 w-4"})]}),cell:({row:m})=>u.jsx("div",{children:m.getValue("name")})},{accessorKey:"apiKey",header:()=>u.jsx("div",{className:"text-right",children:e("openai.credentials.table.apiKey")}),cell:({row:m})=>u.jsxs("div",{children:[`${m.getValue("apiKey")}`.slice(0,20),"..."]})},{id:"actions",enableHiding:!1,cell:({row:m})=>{const x=m.original;return u.jsxs(Eo,{children:[u.jsx(To,{asChild:!0,children:u.jsxs(q,{variant:"ghost",className:"h-8 w-8 p-0",children:[u.jsx("span",{className:"sr-only",children:e("openai.credentials.table.actions.title")}),u.jsx(vu,{className:"h-4 w-4"})]})}),u.jsxs(ps,{align:"end",children:[u.jsx(Ai,{children:e("openai.credentials.table.actions.title")}),u.jsx(Pa,{}),u.jsx(ft,{onClick:()=>h(x.id),children:e("openai.credentials.table.actions.delete")})]})]})}}];return u.jsxs(Tt,{open:s,onOpenChange:o,children:[u.jsx(Nt,{asChild:!0,children:u.jsxs(q,{variant:"secondary",size:"sm",children:[u.jsx(H3,{size:16,className:"mr-1"}),u.jsx("span",{className:"hidden md:inline",children:e("openai.credentials.title")})]})}),u.jsxs(xt,{className:"overflow-y-auto sm:max-h-[600px] sm:max-w-[740px]",onCloseAutoFocus:f,children:[u.jsx(wt,{children:u.jsx(Ut,{children:e("openai.credentials.title")})}),u.jsx(Tr,{...d,children:u.jsxs("form",{onSubmit:d.handleSubmit(p),className:"w-full space-y-6",children:[u.jsx("div",{children:u.jsxs("div",{className:"grid gap-3 md:grid-cols-2",children:[u.jsx(G,{name:"name",label:e("openai.credentials.table.name"),children:u.jsx(K,{})}),u.jsx(G,{name:"apiKey",label:e("openai.credentials.table.apiKey"),children:u.jsx(K,{type:"password"})})]})}),u.jsx(rn,{children:u.jsx(q,{type:"submit",children:e("openai.button.save")})})]})}),u.jsx($t,{}),u.jsx("div",{children:u.jsx(Nu,{columns:g,data:c??[],onSortingChange:l,state:{sorting:a},noResultsMessage:e("openai.credentials.table.none")})})]})]})}const Kee=e=>["openai","fetchDefaultSettings",JSON.stringify(e)],qee=async({instanceName:e,token:t})=>{const n=await he.get(`/openai/fetchSettings/${e}`,{headers:{apiKey:t}});return Array.isArray(n.data)?n.data[0]:n.data},Wee=e=>{const{instanceName:t,token:n,...r}=e;return lt({...r,queryKey:Kee({instanceName:t}),queryFn:()=>qee({instanceName:t,token:n}),enabled:!!t&&(e.enabled??!0)})},Gee=_.object({openaiCredsId:_.string(),expire:_.coerce.number(),keywordFinish:_.string(),delayMessage:_.coerce.number().default(0),unknownMessage:_.string(),listeningFromMe:_.boolean(),stopBotFromMe:_.boolean(),keepOpen:_.boolean(),debounceTime:_.coerce.number(),speechToText:_.boolean(),ignoreJids:_.array(_.string()).default([]),openaiIdFallback:_.union([_.null(),_.string()]).optional(),splitMessages:_.boolean().optional(),timePerChar:_.coerce.number().optional()});function Jee(){const{t:e}=ze(),{instance:t}=nt(),{setDefaultSettingsOpenai:n}=rf(),[r,s]=v.useState(!1),{data:o,refetch:a}=Wee({instanceName:t==null?void 0:t.name,enabled:r}),{data:l,refetch:c}=II({instanceName:t==null?void 0:t.name,enabled:r}),{data:i}=Vw({instanceName:t==null?void 0:t.name,enabled:r}),d=sn({resolver:on(Gee),defaultValues:{openaiCredsId:"",expire:0,keywordFinish:e("openai.form.examples.keywordFinish"),delayMessage:1e3,unknownMessage:e("openai.form.examples.unknownMessage"),listeningFromMe:!1,stopBotFromMe:!1,keepOpen:!1,debounceTime:0,speechToText:!1,ignoreJids:[],openaiIdFallback:void 0,splitMessages:!1,timePerChar:0}});v.useEffect(()=>{o&&d.reset({openaiCredsId:o.openaiCredsId,expire:(o==null?void 0:o.expire)??0,keywordFinish:o.keywordFinish,delayMessage:o.delayMessage??0,unknownMessage:o.unknownMessage,listeningFromMe:o.listeningFromMe,stopBotFromMe:o.stopBotFromMe,keepOpen:o.keepOpen,debounceTime:o.debounceTime??0,speechToText:o.speechToText,ignoreJids:o.ignoreJids,openaiIdFallback:o.openaiIdFallback,splitMessages:o.splitMessages,timePerChar:o.timePerChar??0})},[o]);const p=async h=>{var g,m,x;try{if(!t||!t.name)throw new Error("instance not found.");const b={openaiCredsId:h.openaiCredsId,expire:h.expire,keywordFinish:h.keywordFinish,delayMessage:h.delayMessage,unknownMessage:h.unknownMessage,listeningFromMe:h.listeningFromMe,stopBotFromMe:h.stopBotFromMe,keepOpen:h.keepOpen,debounceTime:h.debounceTime,speechToText:h.speechToText,openaiIdFallback:h.openaiIdFallback||void 0,ignoreJids:h.ignoreJids,splitMessages:h.splitMessages,timePerChar:h.timePerChar};await n({instanceName:t.name,token:t.token,data:b}),X.success(e("openai.toast.defaultSettings.success"))}catch(b){console.error("Error:",b),X.error(`Error: ${(x=(m=(g=b==null?void 0:b.response)==null?void 0:g.data)==null?void 0:m.response)==null?void 0:x.message}`)}};function f(){a(),c()}return u.jsxs(Tt,{open:r,onOpenChange:s,children:[u.jsx(Nt,{asChild:!0,children:u.jsxs(q,{variant:"secondary",size:"sm",children:[u.jsx(Oi,{size:16,className:"mr-1"}),u.jsx("span",{className:"hidden md:inline",children:e("openai.defaultSettings")})]})}),u.jsxs(xt,{className:"overflow-y-auto sm:max-h-[600px] sm:max-w-[740px]",onCloseAutoFocus:f,children:[u.jsx(wt,{children:u.jsx(Ut,{children:e("openai.defaultSettings")})}),u.jsx(Tr,{...d,children:u.jsxs("form",{className:"w-full space-y-6",onSubmit:d.handleSubmit(p),children:[u.jsx("div",{children:u.jsxs("div",{className:"space-y-4",children:[u.jsx(Qt,{name:"openaiCredsId",label:e("openai.form.openaiCredsId.label"),options:(i==null?void 0:i.filter(h=>!!h.id).map(h=>({label:h.name?h.name:h.apiKey.substring(0,15)+"...",value:h.id})))||[]}),u.jsx(Qt,{name:"openaiIdFallback",label:e("openai.form.openaiIdFallback.label"),options:(l==null?void 0:l.filter(h=>!!h.id).map(h=>({label:h.description,value:h.id})))??[]}),u.jsx(G,{name:"expire",label:e("openai.form.expire.label"),children:u.jsx(K,{type:"number"})}),u.jsx(G,{name:"keywordFinish",label:e("openai.form.keywordFinish.label"),children:u.jsx(K,{})}),u.jsx(G,{name:"delayMessage",label:e("openai.form.delayMessage.label"),children:u.jsx(K,{type:"number"})}),u.jsx(G,{name:"unknownMessage",label:e("openai.form.unknownMessage.label"),children:u.jsx(K,{})}),u.jsx(ke,{name:"listeningFromMe",label:e("openai.form.listeningFromMe.label"),reverse:!0}),u.jsx(ke,{name:"stopBotFromMe",label:e("openai.form.stopBotFromMe.label"),reverse:!0}),u.jsx(ke,{name:"keepOpen",label:e("openai.form.keepOpen.label"),reverse:!0}),u.jsx(ke,{name:"speechToText",label:e("openai.form.speechToText.label"),reverse:!0}),u.jsx(G,{name:"debounceTime",label:e("openai.form.debounceTime.label"),children:u.jsx(K,{type:"number"})}),u.jsx(ke,{name:"splitMessages",label:e("openai.form.splitMessages.label"),reverse:!0}),d.watch("splitMessages")&&u.jsx(G,{name:"timePerChar",label:e("openai.form.timePerChar.label"),children:u.jsx(K,{type:"number"})}),u.jsx(Ru,{name:"ignoreJids",label:e("openai.form.ignoreJids.label"),placeholder:e("openai.form.ignoreJids.placeholder")})]})}),u.jsx(rn,{children:u.jsx(q,{type:"submit",children:e("openai.button.save")})})]})})]})]})}const Qee=e=>["openai","getModels",JSON.stringify(e)],Zee=async({instanceName:e,token:t})=>(await he.get(`/openai/getModels/${e}`,{headers:{apiKey:t}})).data,Yee=e=>{const{instanceName:t,token:n,...r}=e;return lt({staleTime:1e3*60*60*6,...r,queryKey:Qee({instanceName:t}),queryFn:()=>Zee({instanceName:t,token:n}),enabled:!!t&&(e.enabled??!0)})},Xee=e=>["openai","fetchSessions",JSON.stringify(e)],ete=async({instanceName:e,openaiId:t,token:n})=>(await he.get(`/openai/fetchSessions/${t}/${e}`,{headers:{apiKey:n}})).data,tte=e=>{const{instanceName:t,token:n,openaiId:r,...s}=e;return lt({...s,queryKey:Xee({instanceName:t}),queryFn:()=>ete({instanceName:t,token:n,openaiId:r}),enabled:!!t&&!!r&&(e.enabled??!0)})};function DI({openaiId:e}){const{t}=ze(),{instance:n}=nt(),{changeStatusOpenai:r}=rf(),[s,o]=v.useState([]),[a,l]=v.useState(!1),{data:c,refetch:i}=tte({instanceName:n==null?void 0:n.name,openaiId:e,enabled:a}),[d,p]=v.useState("");function f(){i()}const h=async(m,x)=>{var b,y,w;try{if(!n)return;await r({instanceName:n.name,token:n.token,remoteJid:m,status:x}),X.success(t("openai.toast.success.status")),f()}catch(S){console.error("Error:",S),X.error(`Error : ${(w=(y=(b=S==null?void 0:S.response)==null?void 0:b.data)==null?void 0:y.response)==null?void 0:w.message}`)}},g=[{accessorKey:"remoteJid",header:()=>u.jsx("div",{className:"text-center",children:t("openai.sessions.table.remoteJid")}),cell:({row:m})=>u.jsx("div",{children:m.getValue("remoteJid")})},{accessorKey:"pushName",header:()=>u.jsx("div",{className:"text-center",children:t("openai.sessions.table.pushName")}),cell:({row:m})=>u.jsx("div",{children:m.getValue("pushName")})},{accessorKey:"sessionId",header:()=>u.jsx("div",{className:"text-center",children:t("openai.sessions.table.sessionId")}),cell:({row:m})=>u.jsx("div",{children:m.getValue("sessionId")})},{accessorKey:"status",header:()=>u.jsx("div",{className:"text-center",children:t("openai.sessions.table.status")}),cell:({row:m})=>u.jsx("div",{children:m.getValue("status")})},{id:"actions",enableHiding:!1,cell:({row:m})=>{const x=m.original;return u.jsxs(Eo,{children:[u.jsx(To,{asChild:!0,children:u.jsxs(q,{variant:"ghost",size:"icon",children:[u.jsx("span",{className:"sr-only",children:t("openai.sessions.table.actions.title")}),u.jsx(vu,{className:"h-4 w-4"})]})}),u.jsxs(ps,{align:"end",children:[u.jsx(Ai,{children:t("openai.sessions.table.actions.title")}),u.jsx(Pa,{}),x.status!=="opened"&&u.jsxs(ft,{onClick:()=>h(x.remoteJid,"opened"),children:[u.jsx(qd,{className:"mr-2 h-4 w-4"}),t("openai.sessions.table.actions.open")]}),x.status!=="paused"&&x.status!=="closed"&&u.jsxs(ft,{onClick:()=>h(x.remoteJid,"paused"),children:[u.jsx(Kd,{className:"mr-2 h-4 w-4"}),t("openai.sessions.table.actions.pause")]}),x.status!=="closed"&&u.jsxs(ft,{onClick:()=>h(x.remoteJid,"closed"),children:[u.jsx(Ud,{className:"mr-2 h-4 w-4"}),t("openai.sessions.table.actions.close")]}),u.jsxs(ft,{onClick:()=>h(x.remoteJid,"delete"),children:[u.jsx(Vd,{className:"mr-2 h-4 w-4"}),t("openai.sessions.table.actions.delete")]})]})]})}}];return u.jsxs(Tt,{open:a,onOpenChange:l,children:[u.jsx(Nt,{asChild:!0,children:u.jsxs(q,{variant:"secondary",size:"sm",children:[u.jsx(Hd,{size:16,className:"mr-1"}),u.jsx("span",{className:"hidden md:inline",children:t("openai.sessions.label")})]})}),u.jsxs(xt,{className:"overflow-y-auto sm:max-w-[950px]",onCloseAutoFocus:f,children:[u.jsx(wt,{children:u.jsx(Ut,{children:t("openai.sessions.label")})}),u.jsxs("div",{children:[u.jsxs("div",{className:"flex items-center justify-between gap-6 p-5",children:[u.jsx(K,{placeholder:t("openai.sessions.search"),value:d,onChange:m=>p(m.target.value)}),u.jsx(q,{variant:"outline",onClick:f,size:"icon",children:u.jsx(Wd,{size:16})})]}),u.jsx(Nu,{columns:g,data:c??[],onSortingChange:o,state:{sorting:s,globalFilter:d},onGlobalFilterChange:p,enableGlobalFilter:!0,noResultsMessage:t("openai.sessions.table.none")})]})]})]})}const nte=_.object({enabled:_.boolean(),description:_.string(),openaiCredsId:_.string(),botType:_.string(),assistantId:_.string().optional(),functionUrl:_.string().optional(),model:_.string().optional(),systemMessages:_.string().optional(),assistantMessages:_.string().optional(),userMessages:_.string().optional(),maxTokens:_.coerce.number().optional(),triggerType:_.string(),triggerOperator:_.string().optional(),triggerValue:_.string().optional(),expire:_.coerce.number().optional(),keywordFinish:_.string().optional(),delayMessage:_.coerce.number().optional(),unknownMessage:_.string().optional(),listeningFromMe:_.boolean().optional(),stopBotFromMe:_.boolean().optional(),keepOpen:_.boolean().optional(),debounceTime:_.coerce.number().optional(),splitMessages:_.boolean().optional(),timePerChar:_.coerce.number().optional()});function AI({initialData:e,onSubmit:t,handleDelete:n,openaiId:r,isModal:s=!1,isLoading:o=!1,openDeletionDialog:a=!1,setOpenDeletionDialog:l=()=>{},open:c}){const{t:i}=ze(),{instance:d}=nt(),{data:p}=Vw({instanceName:d==null?void 0:d.name,enabled:c}),{data:f}=Yee({instanceName:d==null?void 0:d.name,enabled:c}),h=sn({resolver:on(nte),defaultValues:e||{enabled:!0,description:"",openaiCredsId:"",botType:"assistant",assistantId:"",functionUrl:"",model:"",systemMessages:"",assistantMessages:"",userMessages:"",maxTokens:0,triggerType:"keyword",triggerOperator:"contains",triggerValue:"",expire:0,keywordFinish:"",delayMessage:0,unknownMessage:"",listeningFromMe:!1,stopBotFromMe:!1,keepOpen:!1,debounceTime:0,splitMessages:!1,timePerChar:0}}),g=h.watch("botType"),m=h.watch("triggerType");return u.jsx(Tr,{...h,children:u.jsxs("form",{onSubmit:h.handleSubmit(t),className:"w-full space-y-6",children:[u.jsxs("div",{className:"space-y-4",children:[u.jsx(ke,{name:"enabled",label:i("openai.form.enabled.label"),reverse:!0}),u.jsx(G,{name:"description",label:i("openai.form.description.label"),required:!0,children:u.jsx(K,{})}),u.jsx(Qt,{name:"openaiCredsId",label:i("openai.form.openaiCredsId.label"),required:!0,options:(p==null?void 0:p.filter(x=>!!x.id).map(x=>({label:x.name?x.name:x.apiKey.substring(0,15)+"...",value:x.id})))??[]}),u.jsxs("div",{className:"flex flex-col",children:[u.jsx("h3",{className:"my-4 text-lg font-medium",children:i("openai.form.openaiSettings.label")}),u.jsx($t,{})]}),u.jsx(Qt,{name:"botType",label:i("openai.form.botType.label"),required:!0,options:[{label:i("openai.form.botType.assistant"),value:"assistant"},{label:i("openai.form.botType.chatCompletion"),value:"chatCompletion"}]}),g==="assistant"&&u.jsxs(u.Fragment,{children:[u.jsx(G,{name:"assistantId",label:i("openai.form.assistantId.label"),required:!0,children:u.jsx(K,{})}),u.jsx(G,{name:"functionUrl",label:i("openai.form.functionUrl.label"),required:!0,children:u.jsx(K,{})})]}),g==="chatCompletion"&&u.jsxs(u.Fragment,{children:[u.jsx(Qt,{name:"model",label:i("openai.form.model.label"),required:!0,options:(f==null?void 0:f.map(x=>({label:x.id,value:x.id})))??[]}),u.jsx(G,{name:"systemMessages",label:i("openai.form.systemMessages.label"),children:u.jsx(Ml,{})}),u.jsx(G,{name:"assistantMessages",label:i("openai.form.assistantMessages.label"),children:u.jsx(Ml,{})}),u.jsx(G,{name:"userMessages",label:i("openai.form.userMessages.label"),children:u.jsx(Ml,{})}),u.jsx(G,{name:"maxTokens",label:i("openai.form.maxTokens.label"),children:u.jsx(K,{type:"number"})})]}),u.jsxs("div",{className:"flex flex-col",children:[u.jsx("h3",{className:"my-4 text-lg font-medium",children:i("openai.form.triggerSettings.label")}),u.jsx($t,{})]}),u.jsx(Qt,{name:"triggerType",label:i("openai.form.triggerType.label"),required:!0,options:[{label:i("openai.form.triggerType.keyword"),value:"keyword"},{label:i("openai.form.triggerType.all"),value:"all"},{label:i("openai.form.triggerType.advanced"),value:"advanced"},{label:i("openai.form.triggerType.none"),value:"none"}]}),m==="keyword"&&u.jsxs(u.Fragment,{children:[u.jsx(Qt,{name:"triggerOperator",label:i("openai.form.triggerOperator.label"),required:!0,options:[{label:i("openai.form.triggerOperator.contains"),value:"contains"},{label:i("openai.form.triggerOperator.equals"),value:"equals"},{label:i("openai.form.triggerOperator.startsWith"),value:"startsWith"},{label:i("openai.form.triggerOperator.endsWith"),value:"endsWith"},{label:i("openai.form.triggerOperator.regex"),value:"regex"}]}),u.jsx(G,{name:"triggerValue",label:i("openai.form.triggerValue.label"),required:!0,children:u.jsx(K,{})})]}),m==="advanced"&&u.jsx(G,{name:"triggerValue",label:i("openai.form.triggerConditions.label"),required:!0,children:u.jsx(K,{})}),u.jsxs("div",{className:"flex flex-col",children:[u.jsx("h3",{className:"my-4 text-lg font-medium",children:i("openai.form.generalSettings.label")}),u.jsx($t,{})]}),u.jsx(G,{name:"expire",label:i("openai.form.expire.label"),children:u.jsx(K,{type:"number"})}),u.jsx(G,{name:"keywordFinish",label:i("openai.form.keywordFinish.label"),children:u.jsx(K,{})}),u.jsx(G,{name:"delayMessage",label:i("openai.form.delayMessage.label"),children:u.jsx(K,{type:"number"})}),u.jsx(G,{name:"unknownMessage",label:i("openai.form.unknownMessage.label"),children:u.jsx(K,{})}),u.jsx(ke,{name:"listeningFromMe",label:i("openai.form.listeningFromMe.label"),reverse:!0}),u.jsx(ke,{name:"stopBotFromMe",label:i("openai.form.stopBotFromMe.label"),reverse:!0}),u.jsx(ke,{name:"keepOpen",label:i("openai.form.keepOpen.label"),reverse:!0}),u.jsx(G,{name:"debounceTime",label:i("openai.form.debounceTime.label"),children:u.jsx(K,{type:"number"})}),u.jsx(ke,{name:"splitMessages",label:i("openai.form.splitMessages.label"),reverse:!0}),h.watch("splitMessages")&&u.jsx(G,{name:"timePerChar",label:i("openai.form.timePerChar.label"),children:u.jsx(K,{type:"number"})})]}),s&&u.jsx(rn,{children:u.jsx(q,{disabled:o,type:"submit",children:i(o?"openai.button.saving":"openai.button.save")})}),!s&&u.jsxs("div",{children:[u.jsx(DI,{openaiId:r}),u.jsxs("div",{className:"mt-5 flex items-center gap-3",children:[u.jsxs(Tt,{open:a,onOpenChange:l,children:[u.jsx(Nt,{asChild:!0,children:u.jsx(q,{variant:"destructive",size:"sm",children:i("dify.button.delete")})}),u.jsx(xt,{children:u.jsxs(wt,{children:[u.jsx(Ut,{children:i("modal.delete.title")}),u.jsx(Fi,{children:i("modal.delete.messageSingle")}),u.jsxs(rn,{children:[u.jsx(q,{size:"sm",variant:"outline",onClick:()=>l(!1),children:i("button.cancel")}),u.jsx(q,{variant:"destructive",onClick:n,children:i("button.delete")})]})]})})]}),u.jsx(q,{disabled:o,type:"submit",children:i(o?"openai.button.saving":"openai.button.update")})]})]})]})})}function rte({resetTable:e}){const{t}=ze(),{instance:n}=nt(),{createOpenai:r}=rf(),[s,o]=v.useState(!1),[a,l]=v.useState(!1),c=async i=>{var d,p,f;try{if(!n||!n.name)throw new Error("instance not found");o(!0);const h={enabled:i.enabled,description:i.description,openaiCredsId:i.openaiCredsId,botType:i.botType,assistantId:i.assistantId||"",functionUrl:i.functionUrl||"",model:i.model||"",systemMessages:[i.systemMessages||""],assistantMessages:[i.assistantMessages||""],userMessages:[i.userMessages||""],maxTokens:i.maxTokens||0,triggerType:i.triggerType,triggerOperator:i.triggerOperator||"",triggerValue:i.triggerValue||"",expire:i.expire||0,keywordFinish:i.keywordFinish||"",delayMessage:i.delayMessage||0,unknownMessage:i.unknownMessage||"",listeningFromMe:i.listeningFromMe||!1,stopBotFromMe:i.stopBotFromMe||!1,keepOpen:i.keepOpen||!1,debounceTime:i.debounceTime||0,splitMessages:i.splitMessages||!1,timePerChar:i.timePerChar||0};await r({instanceName:n.name,token:n.token,data:h}),X.success(t("openai.toast.success.create")),l(!1),e()}catch(h){console.error("Error:",h),X.error(`Error: ${(f=(p=(d=h==null?void 0:h.response)==null?void 0:d.data)==null?void 0:p.response)==null?void 0:f.message}`)}finally{o(!1)}};return u.jsxs(Tt,{open:a,onOpenChange:l,children:[u.jsx(Nt,{asChild:!0,children:u.jsxs(q,{size:"sm",children:[u.jsx(Ni,{size:16,className:"mr-1"}),u.jsx("span",{className:"hidden sm:inline",children:t("openai.button.create")})]})}),u.jsxs(xt,{className:"overflow-y-auto sm:max-h-[600px] sm:max-w-[740px]",children:[u.jsx(wt,{children:u.jsx(Ut,{children:t("openai.form.title")})}),u.jsx(AI,{onSubmit:c,isModal:!0,isLoading:s,open:a})]})]})}const ste=e=>["openai","getOpenai",JSON.stringify(e)],ote=async({instanceName:e,token:t,openaiId:n})=>{const r=await he.get(`/openai/fetch/${n}/${e}`,{headers:{apiKey:t}});return Array.isArray(r.data)?r.data[0]:r.data},ate=e=>{const{instanceName:t,token:n,openaiId:r,...s}=e;return lt({...s,queryKey:ste({instanceName:t}),queryFn:()=>ote({instanceName:t,token:n,openaiId:r}),enabled:!!t&&!!r&&(e.enabled??!0)})};function ite({openaiId:e,resetTable:t}){const{t:n}=ze(),{instance:r}=nt(),s=An(),[o,a]=v.useState(!1),{deleteOpenai:l,updateOpenai:c}=rf(),{data:i,isLoading:d}=ate({instanceName:r==null?void 0:r.name,openaiId:e}),p=v.useMemo(()=>({enabled:(i==null?void 0:i.enabled)??!0,description:(i==null?void 0:i.description)??"",openaiCredsId:(i==null?void 0:i.openaiCredsId)??"",botType:(i==null?void 0:i.botType)??"",assistantId:(i==null?void 0:i.assistantId)||"",functionUrl:(i==null?void 0:i.functionUrl)||"",model:(i==null?void 0:i.model)||"",systemMessages:Array.isArray(i==null?void 0:i.systemMessages)?i==null?void 0:i.systemMessages.join(", "):(i==null?void 0:i.systemMessages)||"",assistantMessages:Array.isArray(i==null?void 0:i.assistantMessages)?i==null?void 0:i.assistantMessages.join(", "):(i==null?void 0:i.assistantMessages)||"",userMessages:Array.isArray(i==null?void 0:i.userMessages)?i==null?void 0:i.userMessages.join(", "):(i==null?void 0:i.userMessages)||"",maxTokens:(i==null?void 0:i.maxTokens)||0,triggerType:(i==null?void 0:i.triggerType)||"",triggerOperator:(i==null?void 0:i.triggerOperator)||"",triggerValue:i==null?void 0:i.triggerValue,expire:(i==null?void 0:i.expire)||0,keywordFinish:i==null?void 0:i.keywordFinish,delayMessage:(i==null?void 0:i.delayMessage)||0,unknownMessage:i==null?void 0:i.unknownMessage,listeningFromMe:i==null?void 0:i.listeningFromMe,stopBotFromMe:i==null?void 0:i.stopBotFromMe,keepOpen:i==null?void 0:i.keepOpen,debounceTime:(i==null?void 0:i.debounceTime)||0,splitMessages:(i==null?void 0:i.splitMessages)||!1,timePerChar:(i==null?void 0:i.timePerChar)||0}),[i==null?void 0:i.assistantId,i==null?void 0:i.assistantMessages,i==null?void 0:i.botType,i==null?void 0:i.debounceTime,i==null?void 0:i.delayMessage,i==null?void 0:i.description,i==null?void 0:i.enabled,i==null?void 0:i.expire,i==null?void 0:i.functionUrl,i==null?void 0:i.keepOpen,i==null?void 0:i.keywordFinish,i==null?void 0:i.listeningFromMe,i==null?void 0:i.maxTokens,i==null?void 0:i.model,i==null?void 0:i.openaiCredsId,i==null?void 0:i.stopBotFromMe,i==null?void 0:i.systemMessages,i==null?void 0:i.triggerOperator,i==null?void 0:i.triggerType,i==null?void 0:i.triggerValue,i==null?void 0:i.unknownMessage,i==null?void 0:i.userMessages,i==null?void 0:i.splitMessages,i==null?void 0:i.timePerChar]),f=async g=>{var m,x,b;try{if(r&&r.name&&e){const y={enabled:g.enabled,description:g.description,openaiCredsId:g.openaiCredsId,botType:g.botType,assistantId:g.assistantId||"",functionUrl:g.functionUrl||"",model:g.model||"",systemMessages:[g.systemMessages||""],assistantMessages:[g.assistantMessages||""],userMessages:[g.userMessages||""],maxTokens:g.maxTokens||0,triggerType:g.triggerType,triggerOperator:g.triggerOperator||"",triggerValue:g.triggerValue||"",expire:g.expire||0,keywordFinish:g.keywordFinish||"",delayMessage:g.delayMessage||1e3,unknownMessage:g.unknownMessage||"",listeningFromMe:g.listeningFromMe||!1,stopBotFromMe:g.stopBotFromMe||!1,keepOpen:g.keepOpen||!1,debounceTime:g.debounceTime||0,splitMessages:g.splitMessages||!1,timePerChar:g.timePerChar||0};await c({instanceName:r.name,openaiId:e,data:y}),X.success(n("openai.toast.success.update")),t(),s(`/manager/instance/${r.id}/openai/${e}`)}else console.error("Token not found")}catch(y){console.error("Error:",y),X.error(`Error: ${(b=(x=(m=y==null?void 0:y.response)==null?void 0:m.data)==null?void 0:x.response)==null?void 0:b.message}`)}},h=async()=>{try{r&&r.name&&e?(await l({instanceName:r.name,openaiId:e}),X.success(n("openai.toast.success.delete")),a(!1),t(),s(`/manager/instance/${r.id}/openai`)):console.error("instance not found")}catch(g){console.error("Erro ao excluir dify:",g)}};return d?u.jsx(wr,{}):u.jsx("div",{className:"m-4",children:u.jsx(AI,{initialData:p,onSubmit:f,openaiId:e,handleDelete:h,isModal:!1,isLoading:d,openDeletionDialog:o,setOpenDeletionDialog:a})})}function oE(){const{t:e}=ze(),t=Ou("(min-width: 768px)"),{instance:n}=nt(),{botId:r}=So(),{data:s,isLoading:o,refetch:a}=II({instanceName:n==null?void 0:n.name}),l=An(),c=d=>{n&&l(`/manager/instance/${n.id}/openai/${d}`)},i=()=>{a()};return u.jsxs("main",{className:"pt-5",children:[u.jsxs("div",{className:"mb-1 flex items-center justify-between",children:[u.jsx("h3",{className:"text-lg font-medium",children:e("openai.title")}),u.jsxs("div",{className:"flex items-center justify-end gap-2",children:[u.jsx(DI,{}),u.jsx(Jee,{}),u.jsx(Hee,{}),u.jsx(rte,{resetTable:i})]})]}),u.jsx($t,{className:"my-4"}),u.jsxs(Pu,{direction:t?"horizontal":"vertical",children:[u.jsx(Ur,{defaultSize:35,className:"pr-4",children:u.jsx("div",{className:"flex flex-col gap-3",children:o?u.jsx(wr,{}):u.jsx(u.Fragment,{children:s&&s.length>0&&Array.isArray(s)?s.map(d=>u.jsxs(q,{className:"flex h-auto flex-col items-start justify-start",onClick:()=>c(`${d.id}`),variant:r===d.id?"secondary":"outline",children:[u.jsx("h4",{className:"text-base",children:d.description||d.id}),u.jsx("p",{className:"text-sm font-normal text-muted-foreground",children:d.botType})]},d.id)):u.jsx(q,{variant:"link",children:e("openai.table.none")})})})}),r&&u.jsxs(u.Fragment,{children:[u.jsx(Mu,{withHandle:!0,className:"border border-border"}),u.jsx(Ur,{children:u.jsx(ite,{openaiId:r,resetTable:i})})]})]})]})}const lte=e=>["proxy","fetchProxy",JSON.stringify(e)],ute=async({instanceName:e,token:t})=>(await he.get(`/proxy/find/${e}`,{headers:{apiKey:t}})).data,cte=e=>{const{instanceName:t,token:n,...r}=e;return lt({...r,queryKey:lte({instanceName:t,token:n}),queryFn:()=>ute({instanceName:t,token:n}),enabled:!!t})},dte=async({instanceName:e,token:t,data:n})=>(await he.post(`/proxy/set/${e}`,n,{headers:{apikey:t}})).data;function fte(){return{createProxy:Ye(dte,{invalidateKeys:[["proxy","fetchProxy"]]})}}const pte=_.object({enabled:_.boolean(),host:_.string(),port:_.string(),protocol:_.string(),username:_.string(),password:_.string()});function hte(){const{t:e}=ze(),{instance:t}=nt(),[n,r]=v.useState(!1),{createProxy:s}=fte(),{data:o}=cte({instanceName:t==null?void 0:t.name}),a=sn({resolver:on(pte),defaultValues:{enabled:!1,host:"",port:"",protocol:"http",username:"",password:""}});v.useEffect(()=>{o&&a.reset({enabled:o.enabled,host:o.host,port:o.port,protocol:o.protocol,username:o.username,password:o.password})},[o]);const l=async c=>{var i,d,p;if(t){r(!0);try{const f={enabled:c.enabled,host:c.host,port:c.port,protocol:c.protocol,username:c.username,password:c.password};await s({instanceName:t.name,token:t.token,data:f}),X.success(e("proxy.toast.success"))}catch(f){console.error(e("proxy.toast.error"),f),X.error(`Error : ${(p=(d=(i=f==null?void 0:f.response)==null?void 0:i.data)==null?void 0:d.response)==null?void 0:p.message}`)}finally{r(!1)}}};return u.jsx(u.Fragment,{children:u.jsx(Na,{...a,children:u.jsx("form",{onSubmit:a.handleSubmit(l),className:"w-full space-y-6",children:u.jsxs("div",{children:[u.jsx("h3",{className:"mb-1 text-lg font-medium",children:e("proxy.title")}),u.jsx(Ra,{className:"my-4"}),u.jsxs("div",{className:"mx-4 space-y-2 divide-y [&>*]:p-4",children:[u.jsx(ke,{name:"enabled",label:e("proxy.form.enabled.label"),className:"w-full justify-between",helper:e("proxy.form.enabled.description")}),u.jsxs("div",{className:"grid gap-4 sm:grid-cols-[10rem_1fr_10rem] md:gap-8",children:[u.jsx(G,{name:"protocol",label:e("proxy.form.protocol.label"),children:u.jsx(K,{})}),u.jsx(G,{name:"host",label:e("proxy.form.host.label"),children:u.jsx(K,{})}),u.jsx(G,{name:"port",label:e("proxy.form.port.label"),children:u.jsx(K,{type:"number"})})]}),u.jsxs("div",{className:"grid gap-4 sm:grid-cols-2 md:gap-8",children:[u.jsx(G,{name:"username",label:e("proxy.form.username.label"),children:u.jsx(K,{})}),u.jsx(G,{name:"password",label:e("proxy.form.password.label"),children:u.jsx(K,{type:"password"})})]}),u.jsx("div",{className:"flex justify-end px-4 pt-6",children:u.jsx(q,{type:"submit",disabled:n,children:e(n?"proxy.button.saving":"proxy.button.save")})})]})]})})})})}const gte=e=>["rabbitmq","fetchRabbitmq",JSON.stringify(e)],mte=async({instanceName:e,token:t})=>(await he.get(`/rabbitmq/find/${e}`,{headers:{apiKey:t}})).data,vte=e=>{const{instanceName:t,token:n,...r}=e;return lt({...r,queryKey:gte({instanceName:t,token:n}),queryFn:()=>mte({instanceName:t,token:n}),enabled:!!t})},yte=async({instanceName:e,token:t,data:n})=>(await he.post(`/rabbitmq/set/${e}`,{rabbitmq:n},{headers:{apikey:t}})).data;function bte(){return{createRabbitmq:Ye(yte,{invalidateKeys:[["rabbitmq","fetchRabbitmq"]]})}}const xte=_.object({enabled:_.boolean(),events:_.array(_.string())});function wte(){const{t:e}=ze(),{instance:t}=nt(),[n,r]=v.useState(!1),{createRabbitmq:s}=bte(),{data:o}=vte({instanceName:t==null?void 0:t.name,token:t==null?void 0:t.token}),a=sn({resolver:on(xte),defaultValues:{enabled:!1,events:[]}});v.useEffect(()=>{o&&a.reset({enabled:o.enabled,events:o.events})},[o]);const l=async p=>{var f,h,g;if(t){r(!0);try{const m={enabled:p.enabled,events:p.events};await s({instanceName:t.name,token:t.token,data:m}),X.success(e("rabbitmq.toast.success"))}catch(m){console.error(e("rabbitmq.toast.error"),m),X.error(`Error: ${(g=(h=(f=m==null?void 0:m.response)==null?void 0:f.data)==null?void 0:h.response)==null?void 0:g.message}`)}finally{r(!1)}}},c=["APPLICATION_STARTUP","QRCODE_UPDATED","MESSAGES_SET","MESSAGES_UPSERT","MESSAGES_UPDATE","MESSAGES_DELETE","SEND_MESSAGE","CONTACTS_SET","CONTACTS_UPSERT","CONTACTS_UPDATE","PRESENCE_UPDATE","CHATS_SET","CHATS_UPSERT","CHATS_UPDATE","CHATS_DELETE","GROUPS_UPSERT","GROUP_UPDATE","GROUP_PARTICIPANTS_UPDATE","CONNECTION_UPDATE","REMOVE_INSTANCE","LOGOUT_INSTANCE","LABELS_EDIT","LABELS_ASSOCIATION","CALL","TYPEBOT_START","TYPEBOT_CHANGE_STATUS"],i=()=>{a.setValue("events",c)},d=()=>{a.setValue("events",[])};return u.jsx(u.Fragment,{children:u.jsx(Na,{...a,children:u.jsx("form",{onSubmit:a.handleSubmit(l),className:"w-full space-y-6",children:u.jsxs("div",{children:[u.jsx("h3",{className:"mb-1 text-lg font-medium",children:e("rabbitmq.title")}),u.jsx(Ra,{className:"my-4"}),u.jsxs("div",{className:"mx-4 space-y-2 divide-y [&>*]:p-4",children:[u.jsx(ke,{name:"enabled",label:e("rabbitmq.form.enabled.label"),className:"w-full justify-between",helper:e("rabbitmq.form.enabled.description")}),u.jsxs("div",{className:"mb-4 flex justify-between",children:[u.jsx(q,{variant:"outline",type:"button",onClick:i,children:e("button.markAll")}),u.jsx(q,{variant:"outline",type:"button",onClick:d,children:e("button.unMarkAll")})]}),u.jsx(Ia,{control:a.control,name:"events",render:({field:p})=>u.jsxs(_o,{className:"flex flex-col",children:[u.jsx(xr,{className:"my-2 text-lg",children:e("rabbitmq.form.events.label")}),u.jsx(Vs,{children:u.jsx("div",{className:"flex flex-col gap-2 space-y-1 divide-y",children:c.sort((f,h)=>f.localeCompare(h)).map(f=>u.jsxs("div",{className:"flex items-center justify-between gap-3 pt-3",children:[u.jsx(xr,{className:ge("break-all",p.value.includes(f)?"text-foreground":"text-muted-foreground"),children:f}),u.jsx(ju,{checked:p.value.includes(f),onCheckedChange:h=>{h?p.onChange([...p.value,f]):p.onChange(p.value.filter(g=>g!==f))}})]},f))})})]})})]}),u.jsx("div",{className:"mx-4 flex justify-end pt-6",children:u.jsx(q,{type:"submit",disabled:n,children:e(n?"rabbitmq.button.saving":"rabbitmq.button.save")})})]})})})})}const Ste=e=>["instance","fetchSettings",JSON.stringify(e)],Cte=async({instanceName:e,token:t})=>(await he.get(`/settings/find/${e}`,{headers:{apikey:t}})).data,Ete=e=>{const{instanceName:t,token:n,...r}=e;return lt({...r,queryKey:Ste({instanceName:t,token:n}),queryFn:()=>Cte({instanceName:t,token:n}),enabled:!!t})},Tte=_.object({rejectCall:_.boolean(),msgCall:_.string().optional(),groupsIgnore:_.boolean(),alwaysOnline:_.boolean(),readMessages:_.boolean(),syncFullHistory:_.boolean(),readStatus:_.boolean()});function kte(){const{t:e}=ze(),[t,n]=v.useState(!1),{instance:r}=nt(),{updateSettings:s}=_g(),{data:o,isLoading:a}=Ete({instanceName:r==null?void 0:r.name,token:r==null?void 0:r.token}),l=sn({resolver:on(Tte),defaultValues:{rejectCall:!1,msgCall:"",groupsIgnore:!1,alwaysOnline:!1,readMessages:!1,syncFullHistory:!1,readStatus:!1}});v.useEffect(()=>{o&&l.reset({rejectCall:o.rejectCall,msgCall:o.msgCall||"",groupsIgnore:o.groupsIgnore,alwaysOnline:o.alwaysOnline,readMessages:o.readMessages,syncFullHistory:o.syncFullHistory,readStatus:o.readStatus})},[l,o]);const c=async p=>{try{if(!r||!r.name)throw new Error("instance not found");n(!0);const f={rejectCall:p.rejectCall,msgCall:p.msgCall,groupsIgnore:p.groupsIgnore,alwaysOnline:p.alwaysOnline,readMessages:p.readMessages,syncFullHistory:p.syncFullHistory,readStatus:p.readStatus};await s({instanceName:r.name,token:r.token,data:f}),X.success(e("settings.toast.success"))}catch(f){console.error(e("settings.toast.success"),f),X.error(e("settings.toast.error"))}finally{n(!1)}},i=[{name:"groupsIgnore",label:e("settings.form.groupsIgnore.label"),description:e("settings.form.groupsIgnore.description")},{name:"alwaysOnline",label:e("settings.form.alwaysOnline.label"),description:e("settings.form.alwaysOnline.description")},{name:"readMessages",label:e("settings.form.readMessages.label"),description:e("settings.form.readMessages.description")},{name:"syncFullHistory",label:e("settings.form.syncFullHistory.label"),description:e("settings.form.syncFullHistory.description")},{name:"readStatus",label:e("settings.form.readStatus.label"),description:e("settings.form.readStatus.description")}],d=l.watch("rejectCall");return a?u.jsx(wr,{}):u.jsx(u.Fragment,{children:u.jsx(Na,{...l,children:u.jsx("form",{onSubmit:l.handleSubmit(c),className:"w-full space-y-6",children:u.jsxs("div",{children:[u.jsx("h3",{className:"mb-1 text-lg font-medium",children:e("settings.title")}),u.jsx($t,{className:"my-4"}),u.jsxs("div",{className:"mx-4 space-y-2 divide-y",children:[u.jsxs("div",{className:"flex flex-col p-4",children:[u.jsx(ke,{name:"rejectCall",label:e("settings.form.rejectCall.label"),className:"w-full justify-between",helper:e("settings.form.rejectCall.description")}),d&&u.jsx("div",{className:"mr-16 mt-2",children:u.jsx(G,{name:"msgCall",children:u.jsx(Ml,{placeholder:e("settings.form.msgCall.description")})})})]}),i.map(p=>u.jsx("div",{className:"flex p-4",children:u.jsx(ke,{name:p.name,label:p.label,className:"w-full justify-between",helper:p.description})},p.name)),u.jsx("div",{className:"flex justify-end pt-6",children:u.jsx(q,{type:"submit",disabled:t,children:e(t?"settings.button.saving":"settings.button.save")})})]})]})})})})}const _te=e=>["sqs","fetchSqs",JSON.stringify(e)],jte=async({instanceName:e,token:t})=>(await he.get(`/sqs/find/${e}`,{headers:{apiKey:t}})).data,Rte=e=>{const{instanceName:t,token:n,...r}=e;return lt({...r,queryKey:_te({instanceName:t,token:n}),queryFn:()=>jte({instanceName:t,token:n}),enabled:!!t})},Pte=async({instanceName:e,token:t,data:n})=>(await he.post(`/sqs/set/${e}`,{sqs:n},{headers:{apikey:t}})).data;function Mte(){return{createSqs:Ye(Pte,{invalidateKeys:[["sqs","fetchSqs"]]})}}const Ote=_.object({enabled:_.boolean(),events:_.array(_.string())});function Nte(){const{t:e}=ze(),{instance:t}=nt(),[n,r]=v.useState(!1),{createSqs:s}=Mte(),{data:o}=Rte({instanceName:t==null?void 0:t.name,token:t==null?void 0:t.token}),a=sn({resolver:on(Ote),defaultValues:{enabled:!1,events:[]}});v.useEffect(()=>{o&&a.reset({enabled:o.enabled,events:o.events})},[o]);const l=async p=>{var f,h,g;if(t){r(!0);try{const m={enabled:p.enabled,events:p.events};await s({instanceName:t.name,token:t.token,data:m}),X.success(e("sqs.toast.success"))}catch(m){console.error(e("sqs.toast.error"),m),X.error(`Error: ${(g=(h=(f=m==null?void 0:m.response)==null?void 0:f.data)==null?void 0:h.response)==null?void 0:g.message}`)}finally{r(!1)}}},c=["APPLICATION_STARTUP","QRCODE_UPDATED","MESSAGES_SET","MESSAGES_UPSERT","MESSAGES_UPDATE","MESSAGES_DELETE","SEND_MESSAGE","CONTACTS_SET","CONTACTS_UPSERT","CONTACTS_UPDATE","PRESENCE_UPDATE","CHATS_SET","CHATS_UPSERT","CHATS_UPDATE","CHATS_DELETE","GROUPS_UPSERT","GROUP_UPDATE","GROUP_PARTICIPANTS_UPDATE","CONNECTION_UPDATE","REMOVE_INSTANCE","LOGOUT_INSTANCE","LABELS_EDIT","LABELS_ASSOCIATION","CALL","TYPEBOT_START","TYPEBOT_CHANGE_STATUS"],i=()=>{a.setValue("events",c)},d=()=>{a.setValue("events",[])};return u.jsx(u.Fragment,{children:u.jsx(Na,{...a,children:u.jsx("form",{onSubmit:a.handleSubmit(l),className:"w-full space-y-6",children:u.jsxs("div",{children:[u.jsx("h3",{className:"mb-1 text-lg font-medium",children:e("sqs.title")}),u.jsx(Ra,{className:"my-4"}),u.jsxs("div",{className:"mx-4 space-y-2 divide-y [&>*]:p-4",children:[u.jsx(ke,{name:"enabled",label:e("sqs.form.enabled.label"),className:"w-full justify-between",helper:e("sqs.form.enabled.description")}),u.jsxs("div",{className:"mb-4 flex justify-between",children:[u.jsx(q,{variant:"outline",type:"button",onClick:i,children:e("button.markAll")}),u.jsx(q,{variant:"outline",type:"button",onClick:d,children:e("button.unMarkAll")})]}),u.jsx(Ia,{control:a.control,name:"events",render:({field:p})=>u.jsxs(_o,{className:"flex flex-col",children:[u.jsx(xr,{className:"my-2 text-lg",children:e("sqs.form.events.label")}),u.jsx(Vs,{children:u.jsx("div",{className:"flex flex-col gap-2 space-y-1 divide-y",children:c.sort((f,h)=>f.localeCompare(h)).map(f=>u.jsxs("div",{className:"flex items-center justify-between gap-3 pt-3",children:[u.jsx(xr,{className:ge("break-all",p.value.includes(f)?"text-foreground":"text-muted-foreground"),children:f}),u.jsx(ju,{checked:p.value.includes(f),onCheckedChange:h=>{h?p.onChange([...p.value,f]):p.onChange(p.value.filter(g=>g!==f))}})]},f))})})]})})]}),u.jsx("div",{className:"mx-4 flex justify-end pt-6",children:u.jsx(q,{type:"submit",disabled:n,children:e(n?"sqs.button.saving":"sqs.button.save")})})]})})})})}const Ite=e=>["typebot","findTypebot",JSON.stringify(e)],Dte=async({instanceName:e,token:t})=>(await he.get(`/typebot/find/${e}`,{headers:{apiKey:t}})).data,FI=e=>{const{instanceName:t,token:n,...r}=e;return lt({...r,queryKey:Ite({instanceName:t}),queryFn:()=>Dte({instanceName:t,token:n}),enabled:!!t&&(e.enabled??!0)})},Ate=e=>["typebot","fetchDefaultSettings",JSON.stringify(e)],Fte=async({instanceName:e,token:t})=>{const n=await he.get(`/typebot/fetchSettings/${e}`,{headers:{apiKey:t}});return Array.isArray(n.data)?n.data[0]:n.data},Lte=e=>{const{instanceName:t,token:n,...r}=e;return lt({...r,queryKey:Ate({instanceName:t}),queryFn:()=>Fte({instanceName:t,token:n}),enabled:!!t&&(e.enabled??!0)})},$te=async({instanceName:e,token:t,data:n})=>(await he.post(`/typebot/create/${e}`,n,{headers:{apikey:t}})).data,Bte=async({instanceName:e,token:t,typebotId:n,data:r})=>(await he.put(`/typebot/update/${n}/${e}`,r,{headers:{apikey:t}})).data,zte=async({instanceName:e,typebotId:t})=>(await he.delete(`/typebot/delete/${t}/${e}`)).data,Ute=async({instanceName:e,token:t,data:n})=>(await he.post(`/typebot/settings/${e}`,n,{headers:{apikey:t}})).data,Vte=async({instanceName:e,token:t,remoteJid:n,status:r})=>(await he.post(`/typebot/changeStatus/${e}`,{remoteJid:n,status:r},{headers:{apikey:t}})).data;function tm(){const e=Ye(Ute,{invalidateKeys:[["typebot","fetchDefaultSettings"]]}),t=Ye(Vte,{invalidateKeys:[["typebot","getTypebot"],["typebot","fetchSessions"]]}),n=Ye(zte,{invalidateKeys:[["typebot","getTypebot"],["typebot","findTypebot"],["typebot","fetchSessions"]]}),r=Ye(Bte,{invalidateKeys:[["typebot","getTypebot"],["typebot","findTypebot"],["typebot","fetchSessions"]]}),s=Ye($te,{invalidateKeys:[["typebot","findTypebot"]]});return{setDefaultSettingsTypebot:e,changeStatusTypebot:t,deleteTypebot:n,updateTypebot:r,createTypebot:s}}const Hte=_.object({expire:_.coerce.number(),keywordFinish:_.string(),delayMessage:_.coerce.number(),unknownMessage:_.string(),listeningFromMe:_.boolean(),stopBotFromMe:_.boolean(),keepOpen:_.boolean(),debounceTime:_.coerce.number()});function Kte(){const{t:e}=ze(),{instance:t}=nt(),[n,r]=v.useState(!1),{setDefaultSettingsTypebot:s}=tm(),{data:o,refetch:a}=Lte({instanceName:t==null?void 0:t.name,token:t==null?void 0:t.token,enabled:n}),{data:l,refetch:c}=FI({instanceName:t==null?void 0:t.name,token:t==null?void 0:t.token,enabled:n}),i=sn({resolver:on(Hte),defaultValues:{expire:0,keywordFinish:e("typebot.form.examples.keywordFinish"),delayMessage:1e3,unknownMessage:e("typebot.form.examples.unknownMessage"),listeningFromMe:!1,stopBotFromMe:!1,keepOpen:!1,debounceTime:0}});v.useEffect(()=>{o&&i.reset({expire:(o==null?void 0:o.expire)??0,keywordFinish:o.keywordFinish,delayMessage:o.delayMessage??0,unknownMessage:o.unknownMessage,listeningFromMe:o.listeningFromMe,stopBotFromMe:o.stopBotFromMe,keepOpen:o.keepOpen,debounceTime:o.debounceTime??0})},[o]);const d=async f=>{var h,g,m;try{if(!t||!t.name)throw new Error("instance not found.");const x={expire:f.expire,keywordFinish:f.keywordFinish,delayMessage:f.delayMessage,unknownMessage:f.unknownMessage,listeningFromMe:f.listeningFromMe,stopBotFromMe:f.stopBotFromMe,keepOpen:f.keepOpen,debounceTime:f.debounceTime};await s({instanceName:t.name,token:t.token,data:x}),X.success(e("typebot.toast.defaultSettings.success"))}catch(x){console.error(e("typebot.toast.defaultSettings.error"),x),X.error(`Error: ${(m=(g=(h=x==null?void 0:x.response)==null?void 0:h.data)==null?void 0:g.response)==null?void 0:m.message}`)}};function p(){a(),c()}return u.jsxs(Tt,{open:n,onOpenChange:r,children:[u.jsx(Nt,{asChild:!0,children:u.jsxs(q,{variant:"secondary",size:"sm",children:[u.jsx(Oi,{size:16,className:"mr-1"}),u.jsx("span",{className:"hidden sm:inline",children:e("typebot.button.defaultSettings")})]})}),u.jsxs(xt,{className:"overflow-y-auto sm:max-h-[600px] sm:max-w-[740px]",onCloseAutoFocus:p,children:[u.jsx(wt,{children:u.jsx(Ut,{children:e("typebot.modal.defaultSettings.title")})}),u.jsx(Tr,{...i,children:u.jsxs("form",{className:"w-full space-y-6",onSubmit:i.handleSubmit(d),children:[u.jsx("div",{children:u.jsxs("div",{className:"space-y-4",children:[u.jsx(Qt,{name:"typebotIdFallback",label:e("typebot.form.typebotIdFallback.label"),options:(l==null?void 0:l.filter(f=>!!f.id).map(f=>({label:f.typebot,value:f.description})))??[]}),u.jsx(G,{name:"expire",label:e("typebot.form.expire.label"),children:u.jsx(K,{type:"number"})}),u.jsx(G,{name:"keywordFinish",label:e("typebot.form.keywordFinish.label"),children:u.jsx(K,{})}),u.jsx(G,{name:"delayMessage",label:e("typebot.form.delayMessage.label"),children:u.jsx(K,{type:"number"})}),u.jsx(G,{name:"unknownMessage",label:e("typebot.form.unknownMessage.label"),children:u.jsx(K,{})}),u.jsx(ke,{name:"listeningFromMe",label:e("typebot.form.listeningFromMe.label"),reverse:!0}),u.jsx(ke,{name:"stopBotFromMe",label:e("typebot.form.stopBotFromMe.label"),reverse:!0}),u.jsx(ke,{name:"keepOpen",label:e("typebot.form.keepOpen.label"),reverse:!0}),u.jsx(G,{name:"debounceTime",label:e("typebot.form.debounceTime.label"),children:u.jsx(K,{type:"number"})}),u.jsx(Ru,{name:"ignoreJids",label:e("typebot.form.ignoreJids.label"),placeholder:e("typebot.form.ignoreJids.placeholder")})]})}),u.jsx(rn,{children:u.jsx(q,{type:"submit",children:e("typebot.button.save")})})]})})]})]})}const qte=e=>["typebot","fetchSessions",JSON.stringify(e)],Wte=async({instanceName:e,typebotId:t,token:n})=>(await he.get(`/typebot/fetchSessions/${t}/${e}`,{headers:{apiKey:n}})).data,Gte=e=>{const{instanceName:t,token:n,typebotId:r,...s}=e;return lt({...s,queryKey:qte({instanceName:t}),queryFn:()=>Wte({instanceName:t,token:n,typebotId:r}),enabled:!!t&&!!r&&(e.enabled??!0)})};function LI({typebotId:e}){const{t}=ze(),{instance:n}=nt(),[r,s]=v.useState([]),[o,a]=v.useState(!1),[l,c]=v.useState(""),{changeStatusTypebot:i}=tm(),{data:d,refetch:p}=Gte({instanceName:n==null?void 0:n.name,token:n==null?void 0:n.token,typebotId:e});function f(){p()}const h=async(m,x)=>{var b,y,w;try{if(!n)return;await i({instanceName:n.name,token:n.token,remoteJid:m,status:x}),X.success(t("typebot.toast.success.status")),f()}catch(S){console.error("Error:",S),X.error(`Error : ${(w=(y=(b=S==null?void 0:S.response)==null?void 0:b.data)==null?void 0:y.response)==null?void 0:w.message}`)}},g=[{accessorKey:"remoteJid",header:()=>u.jsx("div",{className:"text-center",children:t("typebot.sessions.table.remoteJid")}),cell:({row:m})=>u.jsx("div",{children:m.getValue("remoteJid")})},{accessorKey:"pushName",header:()=>u.jsx("div",{className:"text-center",children:t("typebot.sessions.table.pushName")}),cell:({row:m})=>u.jsx("div",{children:m.getValue("pushName")})},{accessorKey:"sessionId",header:()=>u.jsx("div",{className:"text-center",children:t("typebot.sessions.table.sessionId")}),cell:({row:m})=>u.jsx("div",{children:m.getValue("sessionId")})},{accessorKey:"status",header:()=>u.jsx("div",{className:"text-center",children:t("typebot.sessions.table.status")}),cell:({row:m})=>u.jsx("div",{children:m.getValue("status")})},{id:"actions",enableHiding:!1,cell:({row:m})=>{const x=m.original;return u.jsxs(Eo,{children:[u.jsx(To,{asChild:!0,children:u.jsxs(q,{variant:"ghost",className:"h-8 w-8 p-0",children:[u.jsx("span",{className:"sr-only",children:t("typebot.sessions.table.actions.title")}),u.jsx(vu,{className:"h-4 w-4"})]})}),u.jsxs(ps,{align:"end",children:[u.jsx(Ai,{children:"Actions"}),u.jsx(Pa,{}),x.status!=="opened"&&u.jsxs(ft,{onClick:()=>h(x.remoteJid,"opened"),children:[u.jsx(qd,{className:"mr-2 h-4 w-4"}),t("typebot.sessions.table.actions.open")]}),x.status!=="paused"&&x.status!=="closed"&&u.jsxs(ft,{onClick:()=>h(x.remoteJid,"paused"),children:[u.jsx(Kd,{className:"mr-2 h-4 w-4"}),t("typebot.sessions.table.actions.pause")]}),x.status!=="closed"&&u.jsxs(ft,{onClick:()=>h(x.remoteJid,"closed"),children:[u.jsx(Ud,{className:"mr-2 h-4 w-4"}),t("typebot.sessions.table.actions.close")]}),u.jsxs(ft,{onClick:()=>h(x.remoteJid,"delete"),children:[u.jsx(Vd,{className:"mr-2 h-4 w-4"}),t("typebot.sessions.table.actions.delete")]})]})]})}}];return u.jsxs(Tt,{open:o,onOpenChange:a,children:[u.jsx(Nt,{asChild:!0,children:u.jsxs(q,{variant:"secondary",size:"sm",children:[u.jsx(Hd,{size:16,className:"mr-1"})," ",u.jsx("span",{className:"hidden sm:inline",children:t("typebot.sessions.label")})]})}),u.jsxs(xt,{className:"overflow-y-auto sm:max-w-[950px]",onCloseAutoFocus:f,children:[u.jsx(wt,{children:u.jsx(Ut,{children:t("typebot.sessions.label")})}),u.jsxs("div",{children:[u.jsxs("div",{className:"flex items-center justify-between gap-6 p-5",children:[u.jsx(K,{placeholder:t("typebot.sessions.search"),value:l,onChange:m=>c(m.target.value)}),u.jsx(q,{variant:"outline",onClick:f,size:"icon",children:u.jsx(Wd,{size:16})})]}),u.jsx(Nu,{columns:g,data:d??[],onSortingChange:s,state:{sorting:r,globalFilter:l},onGlobalFilterChange:c,enableGlobalFilter:!0,noResultsMessage:t("typebot.sessions.table.none")})]})]})]})}const Jte=_.object({enabled:_.boolean(),description:_.string(),url:_.string(),typebot:_.string().optional(),triggerType:_.string(),triggerOperator:_.string().optional(),triggerValue:_.string().optional(),expire:_.coerce.number().optional(),keywordFinish:_.string().optional(),delayMessage:_.coerce.number().optional(),unknownMessage:_.string().optional(),listeningFromMe:_.boolean().optional(),stopBotFromMe:_.boolean().optional(),keepOpen:_.boolean().optional(),debounceTime:_.coerce.number().optional()});function $I({initialData:e,onSubmit:t,handleDelete:n,typebotId:r,isModal:s=!1,isLoading:o=!1,openDeletionDialog:a=!1,setOpenDeletionDialog:l=()=>{}}){const{t:c}=ze(),i=sn({resolver:on(Jte),defaultValues:e||{enabled:!0,description:"",url:"",typebot:"",triggerType:"keyword",triggerOperator:"contains",triggerValue:"",expire:0,keywordFinish:"",delayMessage:0,unknownMessage:"",listeningFromMe:!1,stopBotFromMe:!1,keepOpen:!1,debounceTime:0}}),d=i.watch("triggerType");return u.jsx(Tr,{...i,children:u.jsxs("form",{onSubmit:i.handleSubmit(t),className:"w-full space-y-6",children:[u.jsxs("div",{className:"space-y-4",children:[u.jsx(ke,{name:"enabled",label:c("typebot.form.enabled.label"),reverse:!0}),u.jsx(G,{name:"description",label:c("typebot.form.description.label"),required:!0,children:u.jsx(K,{})}),u.jsxs("div",{className:"flex flex-col",children:[u.jsx("h3",{className:"my-4 text-lg font-medium",children:c("typebot.form.typebotSettings.label")}),u.jsx($t,{})]}),u.jsx(G,{name:"url",label:c("typebot.form.url.label"),required:!0,children:u.jsx(K,{})}),u.jsx(G,{name:"typebot",label:c("typebot.form.typebot.label"),children:u.jsx(K,{})}),u.jsxs("div",{className:"flex flex-col",children:[u.jsx("h3",{className:"my-4 text-lg font-medium",children:c("typebot.form.triggerSettings.label")}),u.jsx($t,{})]}),u.jsx(Qt,{name:"triggerType",label:c("typebot.form.triggerType.label"),options:[{label:c("typebot.form.triggerType.keyword"),value:"keyword"},{label:c("typebot.form.triggerType.all"),value:"all"},{label:c("typebot.form.triggerType.advanced"),value:"advanced"},{label:c("typebot.form.triggerType.none"),value:"none"}]}),d==="keyword"&&u.jsxs(u.Fragment,{children:[u.jsx(Qt,{name:"triggerOperator",label:c("typebot.form.triggerOperator.label"),options:[{label:c("typebot.form.triggerOperator.contains"),value:"contains"},{label:c("typebot.form.triggerOperator.equals"),value:"equals"},{label:c("typebot.form.triggerOperator.startsWith"),value:"startsWith"},{label:c("typebot.form.triggerOperator.endsWith"),value:"endsWith"},{label:c("typebot.form.triggerOperator.regex"),value:"regex"}]}),u.jsx(G,{name:"triggerValue",label:c("typebot.form.triggerValue.label"),children:u.jsx(K,{})})]}),d==="advanced"&&u.jsx(G,{name:"triggerValue",label:c("typebot.form.triggerConditions.label"),children:u.jsx(K,{})}),u.jsxs("div",{className:"flex flex-col",children:[u.jsx("h3",{className:"my-4 text-lg font-medium",children:c("typebot.form.generalSettings.label")}),u.jsx($t,{})]}),u.jsx(G,{name:"expire",label:c("typebot.form.expire.label"),children:u.jsx(K,{type:"number"})}),u.jsx(G,{name:"keywordFinish",label:c("typebot.form.keywordFinish.label"),children:u.jsx(K,{})}),u.jsx(G,{name:"delayMessage",label:c("typebot.form.delayMessage.label"),children:u.jsx(K,{type:"number"})}),u.jsx(G,{name:"unknownMessage",label:c("typebot.form.unknownMessage.label"),children:u.jsx(K,{})}),u.jsx(ke,{name:"listeningFromMe",label:c("typebot.form.listeningFromMe.label"),reverse:!0}),u.jsx(ke,{name:"stopBotFromMe",label:c("typebot.form.stopBotFromMe.label"),reverse:!0}),u.jsx(ke,{name:"keepOpen",label:c("typebot.form.keepOpen.label"),reverse:!0}),u.jsx(G,{name:"debounceTime",label:c("typebot.form.debounceTime.label"),children:u.jsx(K,{type:"number"})})]}),s&&u.jsx(rn,{children:u.jsx(q,{disabled:o,type:"submit",children:c(o?"typebot.button.saving":"typebot.button.save")})}),!s&&u.jsxs("div",{children:[u.jsx(LI,{typebotId:r}),u.jsxs("div",{className:"mt-5 flex items-center gap-3",children:[u.jsxs(Tt,{open:a,onOpenChange:l,children:[u.jsx(Nt,{asChild:!0,children:u.jsx(q,{variant:"destructive",size:"sm",children:c("dify.button.delete")})}),u.jsx(xt,{children:u.jsxs(wt,{children:[u.jsx(Ut,{children:c("modal.delete.title")}),u.jsx(Fi,{children:c("modal.delete.messageSingle")}),u.jsxs(rn,{children:[u.jsx(q,{size:"sm",variant:"outline",onClick:()=>l(!1),children:c("button.cancel")}),u.jsx(q,{variant:"destructive",onClick:n,children:c("button.delete")})]})]})})]}),u.jsx(q,{disabled:o,type:"submit",children:c(o?"typebot.button.saving":"typebot.button.update")})]})]})]})})}function Qte({resetTable:e}){const{t}=ze(),{instance:n}=nt(),{createTypebot:r}=tm(),[s,o]=v.useState(!1),[a,l]=v.useState(!1),c=async i=>{var d,p,f;try{if(!n||!n.name)throw new Error("instance not found");o(!0);const h={enabled:i.enabled,description:i.description,url:i.url,typebot:i.typebot||"",triggerType:i.triggerType,triggerOperator:i.triggerOperator||"",triggerValue:i.triggerValue||"",expire:i.expire||0,keywordFinish:i.keywordFinish||"",delayMessage:i.delayMessage||0,unknownMessage:i.unknownMessage||"",listeningFromMe:i.listeningFromMe||!1,stopBotFromMe:i.stopBotFromMe||!1,keepOpen:i.keepOpen||!1,debounceTime:i.debounceTime||0};await r({instanceName:n.name,token:n.token,data:h}),X.success(t("typebot.toast.success.create")),l(!1),e()}catch(h){console.error("Error:",h),X.error(`Error: ${(f=(p=(d=h==null?void 0:h.response)==null?void 0:d.data)==null?void 0:p.response)==null?void 0:f.message}`)}finally{o(!1)}};return u.jsxs(Tt,{open:a,onOpenChange:l,children:[u.jsx(Nt,{asChild:!0,children:u.jsxs(q,{size:"sm",children:[u.jsx(Ni,{size:16,className:"mr-1"}),u.jsx("span",{className:"hidden sm:inline",children:t("typebot.button.create")})]})}),u.jsxs(xt,{className:"overflow-y-auto sm:max-h-[600px] sm:max-w-[740px]",children:[u.jsx(wt,{children:u.jsx(Ut,{children:t("typebot.form.title")})}),u.jsx($I,{onSubmit:c,isModal:!0,isLoading:s})]})]})}const Zte=e=>["typebot","getTypebot",JSON.stringify(e)],Yte=async({instanceName:e,token:t,typebotId:n})=>{const r=await he.get(`/typebot/fetch/${n}/${e}`,{headers:{apiKey:t}});return Array.isArray(r.data)?r.data[0]:r.data},Xte=e=>{const{instanceName:t,token:n,typebotId:r,...s}=e;return lt({...s,queryKey:Zte({instanceName:t}),queryFn:()=>Yte({instanceName:t,token:n,typebotId:r}),enabled:!!t&&!!r&&(e.enabled??!0)})};function ene({typebotId:e,resetTable:t}){const{t:n}=ze(),{instance:r}=nt(),s=An(),[o,a]=v.useState(!1),{deleteTypebot:l,updateTypebot:c}=tm(),{data:i,isLoading:d}=Xte({instanceName:r==null?void 0:r.name,typebotId:e}),p=v.useMemo(()=>({enabled:!!(i!=null&&i.enabled),description:(i==null?void 0:i.description)??"",url:(i==null?void 0:i.url)??"",typebot:(i==null?void 0:i.typebot)??"",triggerType:(i==null?void 0:i.triggerType)??"",triggerOperator:(i==null?void 0:i.triggerOperator)??"",triggerValue:i==null?void 0:i.triggerValue,expire:(i==null?void 0:i.expire)??0,keywordFinish:i==null?void 0:i.keywordFinish,delayMessage:(i==null?void 0:i.delayMessage)??0,unknownMessage:i==null?void 0:i.unknownMessage,listeningFromMe:!!(i!=null&&i.listeningFromMe),stopBotFromMe:!!(i!=null&&i.stopBotFromMe),keepOpen:!!(i!=null&&i.keepOpen),debounceTime:(i==null?void 0:i.debounceTime)??0}),[i==null?void 0:i.debounceTime,i==null?void 0:i.delayMessage,i==null?void 0:i.description,i==null?void 0:i.enabled,i==null?void 0:i.expire,i==null?void 0:i.keepOpen,i==null?void 0:i.keywordFinish,i==null?void 0:i.listeningFromMe,i==null?void 0:i.stopBotFromMe,i==null?void 0:i.triggerOperator,i==null?void 0:i.triggerType,i==null?void 0:i.triggerValue,i==null?void 0:i.typebot,i==null?void 0:i.unknownMessage,i==null?void 0:i.url]),f=async g=>{var m,x,b;try{if(r&&r.name&&e){const y={enabled:g.enabled,description:g.description,url:g.url,typebot:g.typebot||"",triggerType:g.triggerType,triggerOperator:g.triggerOperator||"",triggerValue:g.triggerValue||"",expire:g.expire||0,keywordFinish:g.keywordFinish||"",delayMessage:g.delayMessage||1e3,unknownMessage:g.unknownMessage||"",listeningFromMe:g.listeningFromMe||!1,stopBotFromMe:g.stopBotFromMe||!1,keepOpen:g.keepOpen||!1,debounceTime:g.debounceTime||0};await c({instanceName:r.name,typebotId:e,data:y}),X.success(n("typebot.toast.success.update")),t(),s(`/manager/instance/${r.id}/typebot/${e}`)}else console.error("Token not found")}catch(y){console.error("Error:",y),X.error(`Error: ${(b=(x=(m=y==null?void 0:y.response)==null?void 0:m.data)==null?void 0:x.response)==null?void 0:b.message}`)}},h=async()=>{try{r&&r.name&&e?(await l({instanceName:r.name,typebotId:e}),X.success(n("typebot.toast.success.delete")),a(!1),t(),s(`/manager/instance/${r.id}/typebot`)):console.error("instance not found")}catch(g){console.error("Erro ao excluir dify:",g)}};return d?u.jsx(wr,{}):u.jsx("div",{className:"m-4",children:u.jsx($I,{initialData:p,onSubmit:f,typebotId:e,handleDelete:h,isModal:!1,isLoading:d,openDeletionDialog:o,setOpenDeletionDialog:a})})}function aE(){const{t:e}=ze(),t=Ou("(min-width: 768px)"),{instance:n}=nt(),{typebotId:r}=So(),{data:s,isLoading:o,refetch:a}=FI({instanceName:n==null?void 0:n.name,token:n==null?void 0:n.token}),l=An(),c=d=>{n&&l(`/manager/instance/${n.id}/typebot/${d}`)},i=()=>{a()};return u.jsxs("main",{className:"pt-5",children:[u.jsxs("div",{className:"mb-1 flex items-center justify-between",children:[u.jsx("h3",{className:"text-lg font-medium",children:e("typebot.title")}),u.jsxs("div",{className:"flex flex-wrap items-center justify-end gap-2",children:[u.jsx(LI,{}),u.jsx(Kte,{}),u.jsx(Qte,{resetTable:i})]})]}),u.jsx($t,{className:"my-4"}),u.jsxs(Pu,{direction:t?"horizontal":"vertical",children:[u.jsx(Ur,{defaultSize:35,className:"pr-4",children:u.jsx("div",{className:"flex flex-col gap-3",children:o?u.jsx(wr,{}):u.jsx(u.Fragment,{children:s&&s.length>0&&Array.isArray(s)?s.map(d=>u.jsx(q,{className:"flex h-auto flex-col items-start justify-start",onClick:()=>c(`${d.id}`),variant:r===d.id?"secondary":"outline",children:d.description?u.jsxs(u.Fragment,{children:[u.jsx("h4",{className:"text-base",children:d.description}),u.jsxs("p",{className:"text-wrap text-sm font-normal text-muted-foreground",children:[d.url," - ",d.typebot]})]}):u.jsxs(u.Fragment,{children:[u.jsx("h4",{className:"text-base",children:d.url}),u.jsx("p",{className:"text-wrap text-sm font-normal text-muted-foreground",children:d.typebot})]})},d.id)):u.jsx(q,{variant:"link",children:e("typebot.table.none")})})})}),r&&u.jsxs(u.Fragment,{children:[u.jsx(Mu,{withHandle:!0,className:"border border-black"}),u.jsx(Ur,{children:u.jsx(ene,{typebotId:r,resetTable:i})})]})]})]})}const tne=e=>["webhook","fetchWebhook",JSON.stringify(e)],nne=async({instanceName:e,token:t})=>(await he.get(`/webhook/find/${e}`,{headers:{apiKey:t}})).data,rne=e=>{const{instanceName:t,token:n,...r}=e;return lt({...r,queryKey:tne({instanceName:t,token:n}),queryFn:()=>nne({instanceName:t,token:n}),enabled:!!t})},sne=async({instanceName:e,token:t,data:n})=>(await he.post(`/webhook/set/${e}`,{webhook:n},{headers:{apikey:t}})).data;function one(){return{createWebhook:Ye(sne,{invalidateKeys:[["webhook","fetchWebhook"]]})}}const ane=_.object({enabled:_.boolean(),url:_.string().url("Invalid URL format"),events:_.array(_.string()),base64:_.boolean(),byEvents:_.boolean()});function ine(){const{t:e}=ze(),{instance:t}=nt(),[n,r]=v.useState(!1),{createWebhook:s}=one(),{data:o}=rne({instanceName:t==null?void 0:t.name,token:t==null?void 0:t.token}),a=sn({resolver:on(ane),defaultValues:{enabled:!1,url:"",events:[],base64:!1,byEvents:!1}});v.useEffect(()=>{o&&a.reset({enabled:o.enabled,url:o.url,events:o.events,base64:o.webhookBase64,byEvents:o.webhookByEvents})},[o]);const l=async p=>{var f,h,g;if(t){r(!0);try{const m={enabled:p.enabled,url:p.url,events:p.events,base64:p.base64,byEvents:p.byEvents};await s({instanceName:t.name,token:t.token,data:m}),X.success(e("webhook.toast.success"))}catch(m){console.error(e("webhook.toast.error"),m),X.error(`Error: ${(g=(h=(f=m==null?void 0:m.response)==null?void 0:f.data)==null?void 0:h.response)==null?void 0:g.message}`)}finally{r(!1)}}},c=["APPLICATION_STARTUP","QRCODE_UPDATED","MESSAGES_SET","MESSAGES_UPSERT","MESSAGES_UPDATE","MESSAGES_DELETE","SEND_MESSAGE","CONTACTS_SET","CONTACTS_UPSERT","CONTACTS_UPDATE","PRESENCE_UPDATE","CHATS_SET","CHATS_UPSERT","CHATS_UPDATE","CHATS_DELETE","GROUPS_UPSERT","GROUP_UPDATE","GROUP_PARTICIPANTS_UPDATE","CONNECTION_UPDATE","REMOVE_INSTANCE","LOGOUT_INSTANCE","LABELS_EDIT","LABELS_ASSOCIATION","CALL","TYPEBOT_START","TYPEBOT_CHANGE_STATUS"],i=()=>{a.setValue("events",c)},d=()=>{a.setValue("events",[])};return u.jsx(u.Fragment,{children:u.jsx(Na,{...a,children:u.jsx("form",{onSubmit:a.handleSubmit(l),className:"w-full space-y-6",children:u.jsxs("div",{children:[u.jsx("h3",{className:"mb-1 text-lg font-medium",children:e("webhook.title")}),u.jsx(Ra,{className:"my-4"}),u.jsxs("div",{className:"mx-4 space-y-2 divide-y [&>*]:p-4",children:[u.jsx(ke,{name:"enabled",label:e("webhook.form.enabled.label"),className:"w-full justify-between",helper:e("webhook.form.enabled.description")}),u.jsx(G,{name:"url",label:"URL",children:u.jsx(K,{})}),u.jsx(ke,{name:"byEvents",label:e("webhook.form.byEvents.label"),className:"w-full justify-between",helper:e("webhook.form.byEvents.description")}),u.jsx(ke,{name:"base64",label:e("webhook.form.base64.label"),className:"w-full justify-between",helper:e("webhook.form.base64.description")}),u.jsxs("div",{className:"mb-4 flex justify-between",children:[u.jsx(q,{variant:"outline",type:"button",onClick:i,children:e("button.markAll")}),u.jsx(q,{variant:"outline",type:"button",onClick:d,children:e("button.unMarkAll")})]}),u.jsx(Ia,{control:a.control,name:"events",render:({field:p})=>u.jsxs(_o,{className:"flex flex-col",children:[u.jsx(xr,{className:"my-2 text-lg",children:e("webhook.form.events.label")}),u.jsx(Vs,{children:u.jsx("div",{className:"flex flex-col gap-2 space-y-1 divide-y",children:c.sort((f,h)=>f.localeCompare(h)).map(f=>u.jsxs("div",{className:"flex items-center justify-between gap-3 pt-3",children:[u.jsx(xr,{className:ge("break-all",p.value.includes(f)?"text-foreground":"text-muted-foreground"),children:f}),u.jsx(ju,{checked:p.value.includes(f),onCheckedChange:h=>{h?p.onChange([...p.value,f]):p.onChange(p.value.filter(g=>g!==f))}})]},f))})})]})})]}),u.jsx("div",{className:"mx-4 flex justify-end pt-6",children:u.jsx(q,{type:"submit",disabled:n,children:e(n?"webhook.button.saving":"webhook.button.save")})})]})})})})}const lne=e=>["websocket","fetchWebsocket",JSON.stringify(e)],une=async({instanceName:e,token:t})=>(await he.get(`/websocket/find/${e}`,{headers:{apiKey:t}})).data,cne=e=>{const{instanceName:t,token:n,...r}=e;return lt({...r,queryKey:lne({instanceName:t,token:n}),queryFn:()=>une({instanceName:t,token:n}),enabled:!!t})},dne=async({instanceName:e,token:t,data:n})=>(await he.post(`/websocket/set/${e}`,{websocket:n},{headers:{apikey:t}})).data;function fne(){return{createWebsocket:Ye(dne,{invalidateKeys:[["websocket","fetchWebsocket"]]})}}const pne=_.object({enabled:_.boolean(),events:_.array(_.string())});function hne(){const{t:e}=ze(),{instance:t}=nt(),[n,r]=v.useState(!1),{createWebsocket:s}=fne(),{data:o}=cne({instanceName:t==null?void 0:t.name,token:t==null?void 0:t.token}),a=sn({resolver:on(pne),defaultValues:{enabled:!1,events:[]}});v.useEffect(()=>{o&&a.reset({enabled:o.enabled,events:o.events})},[o]);const l=async p=>{var f,h,g;if(t){r(!0);try{const m={enabled:p.enabled,events:p.events};await s({instanceName:t.name,token:t.token,data:m}),X.success(e("websocket.toast.success"))}catch(m){console.error(e("websocket.toast.error"),m),X.error(`Error: ${(g=(h=(f=m==null?void 0:m.response)==null?void 0:f.data)==null?void 0:h.response)==null?void 0:g.message}`)}finally{r(!1)}}},c=["APPLICATION_STARTUP","QRCODE_UPDATED","MESSAGES_SET","MESSAGES_UPSERT","MESSAGES_UPDATE","MESSAGES_DELETE","SEND_MESSAGE","CONTACTS_SET","CONTACTS_UPSERT","CONTACTS_UPDATE","PRESENCE_UPDATE","CHATS_SET","CHATS_UPSERT","CHATS_UPDATE","CHATS_DELETE","GROUPS_UPSERT","GROUP_UPDATE","GROUP_PARTICIPANTS_UPDATE","CONNECTION_UPDATE","REMOVE_INSTANCE","LOGOUT_INSTANCE","LABELS_EDIT","LABELS_ASSOCIATION","CALL","TYPEBOT_START","TYPEBOT_CHANGE_STATUS"],i=()=>{a.setValue("events",c)},d=()=>{a.setValue("events",[])};return u.jsx(u.Fragment,{children:u.jsx(Na,{...a,children:u.jsx("form",{onSubmit:a.handleSubmit(l),className:"w-full space-y-6",children:u.jsxs("div",{children:[u.jsx("h3",{className:"mb-1 text-lg font-medium",children:e("websocket.title")}),u.jsx(Ra,{className:"my-4"}),u.jsxs("div",{className:"mx-4 space-y-2 divide-y [&>*]:p-4",children:[u.jsx(ke,{name:"enabled",label:e("websocket.form.enabled.label"),className:"w-full justify-between",helper:e("websocket.form.enabled.description")}),u.jsxs("div",{className:"mb-4 flex justify-between",children:[u.jsx(q,{variant:"outline",type:"button",onClick:i,children:e("button.markAll")}),u.jsx(q,{variant:"outline",type:"button",onClick:d,children:e("button.unMarkAll")})]}),u.jsx(Ia,{control:a.control,name:"events",render:({field:p})=>u.jsxs(_o,{className:"flex flex-col",children:[u.jsx(xr,{className:"my-2 text-lg",children:e("websocket.form.events.label")}),u.jsx(Vs,{children:u.jsx("div",{className:"flex flex-col gap-2 space-y-1 divide-y",children:c.sort((f,h)=>f.localeCompare(h)).map(f=>u.jsxs("div",{className:"flex items-center justify-between gap-3 pt-3",children:[u.jsx(xr,{className:ge("break-all",p.value.includes(f)?"text-foreground":"text-muted-foreground"),children:f}),u.jsx(ju,{checked:p.value.includes(f),onCheckedChange:h=>{h?p.onChange([...p.value,f]):p.onChange(p.value.filter(g=>g!==f))}})]},f))})})]})})]}),u.jsx("div",{className:"mx-4 flex justify-end pt-6",children:u.jsx(q,{type:"submit",disabled:n,children:e(n?"websocket.button.saving":"websocket.button.save")})})]})})})})}const gne=async({url:e,token:t})=>{try{const{data:n}=await zt.post(`${e}/verify-creds`,{},{headers:{apikey:t}});return P_({facebookAppId:n.facebookAppId,facebookConfigId:n.facebookConfigId,facebookUserToken:n.facebookUserToken}),n}catch{return null}},mne=_.object({serverUrl:_.string({required_error:"serverUrl is required"}).url("URL inválida"),apiKey:_.string({required_error:"ApiKey is required"})});function vne(){const{t:e}=ze(),t=An(),n=sn({resolver:on(mne),defaultValues:{serverUrl:window.location.protocol+"//"+window.location.host,apiKey:""}}),r=async s=>{const o=await nj({url:s.serverUrl});if(!o||!o.version){M_(),n.setError("serverUrl",{type:"manual",message:e("login.message.invalidServer")});return}if(!await gne({token:s.apiKey,url:s.serverUrl})){n.setError("apiKey",{type:"manual",message:e("login.message.invalidCredentials")});return}P_({version:o.version,clientName:o.clientName,url:s.serverUrl,token:s.apiKey}),t("/manager/")};return u.jsxs("div",{className:"flex min-h-screen flex-col",children:[u.jsx("div",{className:"flex items-center justify-center pt-2",children:u.jsx("img",{className:"h-10",src:"/assets/images/evolution-logo.png",alt:"logo"})}),u.jsx("div",{className:"flex flex-1 items-center justify-center p-8",children:u.jsxs(Ja,{className:"b-none w-[350px] shadow-none",children:[u.jsxs(Qa,{children:[u.jsx(jc,{className:"text-center",children:e("login.title")}),u.jsx(JP,{className:"text-center",children:e("login.description")})]}),u.jsx(Na,{...n,children:u.jsxs("form",{onSubmit:n.handleSubmit(r),children:[u.jsx(Za,{children:u.jsxs("div",{className:"grid w-full items-center gap-4",children:[u.jsx(G,{required:!0,name:"serverUrl",label:e("login.form.serverUrl"),children:u.jsx(K,{})}),u.jsx(G,{required:!0,name:"apiKey",label:e("login.form.apiKey"),children:u.jsx(K,{type:"password"})})]})}),u.jsx(kg,{className:"flex justify-center",children:u.jsx(q,{className:"w-full",type:"submit",children:e("login.button.login")})})]})})]})}),u.jsx(Ax,{})]})}const yne=OL([{path:"/manager/login",element:u.jsx(l$,{children:u.jsx(vne,{})})},{path:"/manager/",element:u.jsx(Gt,{children:u.jsx(SV,{children:u.jsx(GQ,{})})})},{path:"/manager/instance/:instanceId/dashboard",element:u.jsx(Gt,{children:u.jsx(Xt,{children:u.jsx(SY,{})})})},{path:"/manager/instance/:instanceId/chat",element:u.jsx(Gt,{children:u.jsx(Xt,{children:u.jsx(Q1,{})})})},{path:"/manager/instance/:instanceId/chat/:remoteJid",element:u.jsx(Gt,{children:u.jsx(Xt,{children:u.jsx(Q1,{})})})},{path:"/manager/instance/:instanceId/settings",element:u.jsx(Gt,{children:u.jsx(Xt,{children:u.jsx(kte,{})})})},{path:"/manager/instance/:instanceId/openai",element:u.jsx(Gt,{children:u.jsx(Xt,{children:u.jsx(oE,{})})})},{path:"/manager/instance/:instanceId/openai/:botId",element:u.jsx(Gt,{children:u.jsx(Xt,{children:u.jsx(oE,{})})})},{path:"/manager/instance/:instanceId/webhook",element:u.jsx(Gt,{children:u.jsx(Xt,{children:u.jsx(ine,{})})})},{path:"/manager/instance/:instanceId/websocket",element:u.jsx(Gt,{children:u.jsx(Xt,{children:u.jsx(hne,{})})})},{path:"/manager/instance/:instanceId/rabbitmq",element:u.jsx(Gt,{children:u.jsx(Xt,{children:u.jsx(wte,{})})})},{path:"/manager/instance/:instanceId/sqs",element:u.jsx(Gt,{children:u.jsx(Xt,{children:u.jsx(Nte,{})})})},{path:"/manager/instance/:instanceId/chatwoot",element:u.jsx(Gt,{children:u.jsx(Xt,{children:u.jsx(HZ,{})})})},{path:"/manager/instance/:instanceId/typebot",element:u.jsx(Gt,{children:u.jsx(Xt,{children:u.jsx(aE,{})})})},{path:"/manager/instance/:instanceId/typebot/:typebotId",element:u.jsx(Gt,{children:u.jsx(Xt,{children:u.jsx(aE,{})})})},{path:"/manager/instance/:instanceId/dify",element:u.jsx(Gt,{children:u.jsx(Xt,{children:u.jsx(nE,{})})})},{path:"/manager/instance/:instanceId/dify/:difyId",element:u.jsx(Gt,{children:u.jsx(Xt,{children:u.jsx(nE,{})})})},{path:"/manager/instance/:instanceId/evolutionBot",element:u.jsx(Gt,{children:u.jsx(Xt,{children:u.jsx(rE,{})})})},{path:"/manager/instance/:instanceId/evolutionBot/:evolutionBotId",element:u.jsx(Gt,{children:u.jsx(Xt,{children:u.jsx(rE,{})})})},{path:"/manager/instance/:instanceId/flowise",element:u.jsx(Gt,{children:u.jsx(Xt,{children:u.jsx(sE,{})})})},{path:"/manager/instance/:instanceId/flowise/:flowiseId",element:u.jsx(Gt,{children:u.jsx(Xt,{children:u.jsx(sE,{})})})},{path:"/manager/instance/:instanceId/proxy",element:u.jsx(Gt,{children:u.jsx(Xt,{children:u.jsx(hte,{})})})}]),bne={type:"logger",log(e){this.output("log",e)},warn(e){this.output("warn",e)},error(e){this.output("error",e)},output(e,t){console&&console[e]&&console[e].apply(console,t)}};class jh{constructor(t){let n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};this.init(t,n)}init(t){let n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};this.prefix=n.prefix||"i18next:",this.logger=t||bne,this.options=n,this.debug=n.debug}log(){for(var t=arguments.length,n=new Array(t),r=0;r{this.observers[r]||(this.observers[r]=new Map);const s=this.observers[r].get(n)||0;this.observers[r].set(n,s+1)}),this}off(t,n){if(this.observers[t]){if(!n){delete this.observers[t];return}this.observers[t].delete(n)}}emit(t){for(var n=arguments.length,r=new Array(n>1?n-1:0),s=1;s{let[l,c]=a;for(let i=0;i{let[l,c]=a;for(let i=0;i{let e,t;const n=new Promise((r,s)=>{e=r,t=s});return n.resolve=e,n.reject=t,n},iE=e=>e==null?"":""+e,xne=(e,t,n)=>{e.forEach(r=>{t[r]&&(n[r]=t[r])})},wne=/###/g,lE=e=>e&&e.indexOf("###")>-1?e.replace(wne,"."):e,uE=e=>!e||typeof e=="string",Ic=(e,t,n)=>{const r=typeof t!="string"?t:t.split(".");let s=0;for(;s{const{obj:r,k:s}=Ic(e,t,Object);if(r!==void 0||t.length===1){r[s]=n;return}let o=t[t.length-1],a=t.slice(0,t.length-1),l=Ic(e,a,Object);for(;l.obj===void 0&&a.length;)o=`${a[a.length-1]}.${o}`,a=a.slice(0,a.length-1),l=Ic(e,a,Object),l&&l.obj&&typeof l.obj[`${l.k}.${o}`]<"u"&&(l.obj=void 0);l.obj[`${l.k}.${o}`]=n},Sne=(e,t,n,r)=>{const{obj:s,k:o}=Ic(e,t,Object);s[o]=s[o]||[],s[o].push(n)},Rh=(e,t)=>{const{obj:n,k:r}=Ic(e,t);if(n)return n[r]},Cne=(e,t,n)=>{const r=Rh(e,n);return r!==void 0?r:Rh(t,n)},BI=(e,t,n)=>{for(const r in t)r!=="__proto__"&&r!=="constructor"&&(r in e?typeof e[r]=="string"||e[r]instanceof String||typeof t[r]=="string"||t[r]instanceof String?n&&(e[r]=t[r]):BI(e[r],t[r],n):e[r]=t[r]);return e},Xi=e=>e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&");var Ene={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"};const Tne=e=>typeof e=="string"?e.replace(/[&<>"'\/]/g,t=>Ene[t]):e;class kne{constructor(t){this.capacity=t,this.regExpMap=new Map,this.regExpQueue=[]}getRegExp(t){const n=this.regExpMap.get(t);if(n!==void 0)return n;const r=new RegExp(t);return this.regExpQueue.length===this.capacity&&this.regExpMap.delete(this.regExpQueue.shift()),this.regExpMap.set(t,r),this.regExpQueue.push(t),r}}const _ne=[" ",",","?","!",";"],jne=new kne(20),Rne=(e,t,n)=>{t=t||"",n=n||"";const r=_ne.filter(a=>t.indexOf(a)<0&&n.indexOf(a)<0);if(r.length===0)return!0;const s=jne.getRegExp(`(${r.map(a=>a==="?"?"\\?":a).join("|")})`);let o=!s.test(e);if(!o){const a=e.indexOf(n);a>0&&!s.test(e.substring(0,a))&&(o=!0)}return o},_b=function(e,t){let n=arguments.length>2&&arguments[2]!==void 0?arguments[2]:".";if(!e)return;if(e[t])return e[t];const r=t.split(n);let s=e;for(let o=0;o-1&&ce&&e.indexOf("_")>0?e.replace("_","-"):e;class dE extends nm{constructor(t){let n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{ns:["translation"],defaultNS:"translation"};super(),this.data=t||{},this.options=n,this.options.keySeparator===void 0&&(this.options.keySeparator="."),this.options.ignoreJSONStructure===void 0&&(this.options.ignoreJSONStructure=!0)}addNamespaces(t){this.options.ns.indexOf(t)<0&&this.options.ns.push(t)}removeNamespaces(t){const n=this.options.ns.indexOf(t);n>-1&&this.options.ns.splice(n,1)}getResource(t,n,r){let s=arguments.length>3&&arguments[3]!==void 0?arguments[3]:{};const o=s.keySeparator!==void 0?s.keySeparator:this.options.keySeparator,a=s.ignoreJSONStructure!==void 0?s.ignoreJSONStructure:this.options.ignoreJSONStructure;let l;t.indexOf(".")>-1?l=t.split("."):(l=[t,n],r&&(Array.isArray(r)?l.push(...r):typeof r=="string"&&o?l.push(...r.split(o)):l.push(r)));const c=Rh(this.data,l);return!c&&!n&&!r&&t.indexOf(".")>-1&&(t=l[0],n=l[1],r=l.slice(2).join(".")),c||!a||typeof r!="string"?c:_b(this.data&&this.data[t]&&this.data[t][n],r,o)}addResource(t,n,r,s){let o=arguments.length>4&&arguments[4]!==void 0?arguments[4]:{silent:!1};const a=o.keySeparator!==void 0?o.keySeparator:this.options.keySeparator;let l=[t,n];r&&(l=l.concat(a?r.split(a):r)),t.indexOf(".")>-1&&(l=t.split("."),s=n,n=l[1]),this.addNamespaces(n),cE(this.data,l,s),o.silent||this.emit("added",t,n,r,s)}addResources(t,n,r){let s=arguments.length>3&&arguments[3]!==void 0?arguments[3]:{silent:!1};for(const o in r)(typeof r[o]=="string"||Array.isArray(r[o]))&&this.addResource(t,n,o,r[o],{silent:!0});s.silent||this.emit("added",t,n,r)}addResourceBundle(t,n,r,s,o){let a=arguments.length>5&&arguments[5]!==void 0?arguments[5]:{silent:!1,skipCopy:!1},l=[t,n];t.indexOf(".")>-1&&(l=t.split("."),s=r,r=n,n=l[1]),this.addNamespaces(n);let c=Rh(this.data,l)||{};a.skipCopy||(r=JSON.parse(JSON.stringify(r))),s?BI(c,r,o):c={...c,...r},cE(this.data,l,c),a.silent||this.emit("added",t,n,r)}removeResourceBundle(t,n){this.hasResourceBundle(t,n)&&delete this.data[t][n],this.removeNamespaces(n),this.emit("removed",t,n)}hasResourceBundle(t,n){return this.getResource(t,n)!==void 0}getResourceBundle(t,n){return n||(n=this.options.defaultNS),this.options.compatibilityAPI==="v1"?{...this.getResource(t,n)}:this.getResource(t,n)}getDataByLanguage(t){return this.data[t]}hasLanguageSomeTranslations(t){const n=this.getDataByLanguage(t);return!!(n&&Object.keys(n)||[]).find(s=>n[s]&&Object.keys(n[s]).length>0)}toJSON(){return this.data}}var zI={processors:{},addPostProcessor(e){this.processors[e.name]=e},handle(e,t,n,r,s){return e.forEach(o=>{this.processors[o]&&(t=this.processors[o].process(t,n,r,s))}),t}};const fE={};class Mh extends nm{constructor(t){let n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};super(),xne(["resourceStore","languageUtils","pluralResolver","interpolator","backendConnector","i18nFormat","utils"],t,this),this.options=n,this.options.keySeparator===void 0&&(this.options.keySeparator="."),this.logger=Is.create("translator")}changeLanguage(t){t&&(this.language=t)}exists(t){let n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{interpolation:{}};if(t==null)return!1;const r=this.resolve(t,n);return r&&r.res!==void 0}extractFromKey(t,n){let r=n.nsSeparator!==void 0?n.nsSeparator:this.options.nsSeparator;r===void 0&&(r=":");const s=n.keySeparator!==void 0?n.keySeparator:this.options.keySeparator;let o=n.ns||this.options.defaultNS||[];const a=r&&t.indexOf(r)>-1,l=!this.options.userDefinedKeySeparator&&!n.keySeparator&&!this.options.userDefinedNsSeparator&&!n.nsSeparator&&!Rne(t,r,s);if(a&&!l){const c=t.match(this.interpolator.nestingRegexp);if(c&&c.length>0)return{key:t,namespaces:o};const i=t.split(r);(r!==s||r===s&&this.options.ns.indexOf(i[0])>-1)&&(o=i.shift()),t=i.join(s)}return typeof o=="string"&&(o=[o]),{key:t,namespaces:o}}translate(t,n,r){if(typeof n!="object"&&this.options.overloadTranslationOptionHandler&&(n=this.options.overloadTranslationOptionHandler(arguments)),typeof n=="object"&&(n={...n}),n||(n={}),t==null)return"";Array.isArray(t)||(t=[String(t)]);const s=n.returnDetails!==void 0?n.returnDetails:this.options.returnDetails,o=n.keySeparator!==void 0?n.keySeparator:this.options.keySeparator,{key:a,namespaces:l}=this.extractFromKey(t[t.length-1],n),c=l[l.length-1],i=n.lng||this.language,d=n.appendNamespaceToCIMode||this.options.appendNamespaceToCIMode;if(i&&i.toLowerCase()==="cimode"){if(d){const S=n.nsSeparator||this.options.nsSeparator;return s?{res:`${c}${S}${a}`,usedKey:a,exactUsedKey:a,usedLng:i,usedNS:c,usedParams:this.getUsedParamsDetails(n)}:`${c}${S}${a}`}return s?{res:a,usedKey:a,exactUsedKey:a,usedLng:i,usedNS:c,usedParams:this.getUsedParamsDetails(n)}:a}const p=this.resolve(t,n);let f=p&&p.res;const h=p&&p.usedKey||a,g=p&&p.exactUsedKey||a,m=Object.prototype.toString.apply(f),x=["[object Number]","[object Function]","[object RegExp]"],b=n.joinArrays!==void 0?n.joinArrays:this.options.joinArrays,y=!this.i18nFormat||this.i18nFormat.handleAsObject;if(y&&f&&(typeof f!="string"&&typeof f!="boolean"&&typeof f!="number")&&x.indexOf(m)<0&&!(typeof b=="string"&&Array.isArray(f))){if(!n.returnObjects&&!this.options.returnObjects){this.options.returnedObjectHandler||this.logger.warn("accessing an object - but returnObjects options is not enabled!");const S=this.options.returnedObjectHandler?this.options.returnedObjectHandler(h,f,{...n,ns:l}):`key '${a} (${this.language})' returned an object instead of string.`;return s?(p.res=S,p.usedParams=this.getUsedParamsDetails(n),p):S}if(o){const S=Array.isArray(f),E=S?[]:{},C=S?g:h;for(const k in f)if(Object.prototype.hasOwnProperty.call(f,k)){const T=`${C}${o}${k}`;E[k]=this.translate(T,{...n,joinArrays:!1,ns:l}),E[k]===T&&(E[k]=f[k])}f=E}}else if(y&&typeof b=="string"&&Array.isArray(f))f=f.join(b),f&&(f=this.extendTranslation(f,t,n,r));else{let S=!1,E=!1;const C=n.count!==void 0&&typeof n.count!="string",k=Mh.hasDefaultValue(n),T=C?this.pluralResolver.getSuffix(i,n.count,n):"",P=n.ordinal&&C?this.pluralResolver.getSuffix(i,n.count,{ordinal:!1}):"",N=C&&!n.ordinal&&n.count===0&&this.pluralResolver.shouldUseIntlApi(),U=N&&n[`defaultValue${this.options.pluralSeparator}zero`]||n[`defaultValue${T}`]||n[`defaultValue${P}`]||n.defaultValue;!this.isValidLookup(f)&&k&&(S=!0,f=U),this.isValidLookup(f)||(E=!0,f=a);const Z=(n.missingKeyNoValueFallbackToKey||this.options.missingKeyNoValueFallbackToKey)&&E?void 0:f,V=k&&U!==f&&this.options.updateMissing;if(E||S||V){if(this.logger.log(V?"updateKey":"missingKey",i,c,a,V?U:f),o){const F=this.resolve(a,{...n,keySeparator:!1});F&&F.res&&this.logger.warn("Seems the loaded translations were in flat JSON format instead of nested. Either set keySeparator: false on init or make sure your translations are published in nested format.")}let Q=[];const ee=this.languageUtils.getFallbackCodes(this.options.fallbackLng,n.lng||this.language);if(this.options.saveMissingTo==="fallback"&&ee&&ee[0])for(let F=0;F{const de=k&&Y!==f?Y:Z;this.options.missingKeyHandler?this.options.missingKeyHandler(F,c,A,de,V,n):this.backendConnector&&this.backendConnector.saveMissing&&this.backendConnector.saveMissing(F,c,A,de,V,n),this.emit("missingKey",F,c,A,f)};this.options.saveMissing&&(this.options.saveMissingPlurals&&C?Q.forEach(F=>{const A=this.pluralResolver.getSuffixes(F,n);N&&n[`defaultValue${this.options.pluralSeparator}zero`]&&A.indexOf(`${this.options.pluralSeparator}zero`)<0&&A.push(`${this.options.pluralSeparator}zero`),A.forEach(Y=>{W([F],a+Y,n[`defaultValue${Y}`]||U)})}):W(Q,a,U))}f=this.extendTranslation(f,t,n,p,r),E&&f===a&&this.options.appendNamespaceToMissingKey&&(f=`${c}:${a}`),(E||S)&&this.options.parseMissingKeyHandler&&(this.options.compatibilityAPI!=="v1"?f=this.options.parseMissingKeyHandler(this.options.appendNamespaceToMissingKey?`${c}:${a}`:a,S?f:void 0):f=this.options.parseMissingKeyHandler(f))}return s?(p.res=f,p.usedParams=this.getUsedParamsDetails(n),p):f}extendTranslation(t,n,r,s,o){var a=this;if(this.i18nFormat&&this.i18nFormat.parse)t=this.i18nFormat.parse(t,{...this.options.interpolation.defaultVariables,...r},r.lng||this.language||s.usedLng,s.usedNS,s.usedKey,{resolved:s});else if(!r.skipInterpolation){r.interpolation&&this.interpolator.init({...r,interpolation:{...this.options.interpolation,...r.interpolation}});const i=typeof t=="string"&&(r&&r.interpolation&&r.interpolation.skipOnVariables!==void 0?r.interpolation.skipOnVariables:this.options.interpolation.skipOnVariables);let d;if(i){const f=t.match(this.interpolator.nestingRegexp);d=f&&f.length}let p=r.replace&&typeof r.replace!="string"?r.replace:r;if(this.options.interpolation.defaultVariables&&(p={...this.options.interpolation.defaultVariables,...p}),t=this.interpolator.interpolate(t,p,r.lng||this.language||s.usedLng,r),i){const f=t.match(this.interpolator.nestingRegexp),h=f&&f.length;d1&&arguments[1]!==void 0?arguments[1]:{},r,s,o,a,l;return typeof t=="string"&&(t=[t]),t.forEach(c=>{if(this.isValidLookup(r))return;const i=this.extractFromKey(c,n),d=i.key;s=d;let p=i.namespaces;this.options.fallbackNS&&(p=p.concat(this.options.fallbackNS));const f=n.count!==void 0&&typeof n.count!="string",h=f&&!n.ordinal&&n.count===0&&this.pluralResolver.shouldUseIntlApi(),g=n.context!==void 0&&(typeof n.context=="string"||typeof n.context=="number")&&n.context!=="",m=n.lngs?n.lngs:this.languageUtils.toResolveHierarchy(n.lng||this.language,n.fallbackLng);p.forEach(x=>{this.isValidLookup(r)||(l=x,!fE[`${m[0]}-${x}`]&&this.utils&&this.utils.hasLoadedNamespace&&!this.utils.hasLoadedNamespace(l)&&(fE[`${m[0]}-${x}`]=!0,this.logger.warn(`key "${s}" for languages "${m.join(", ")}" won't get resolved as namespace "${l}" was not yet loaded`,"This means something IS WRONG in your setup. You access the t function before i18next.init / i18next.loadNamespace / i18next.changeLanguage was done. Wait for the callback or Promise to resolve before accessing it!!!")),m.forEach(b=>{if(this.isValidLookup(r))return;a=b;const y=[d];if(this.i18nFormat&&this.i18nFormat.addLookupKeys)this.i18nFormat.addLookupKeys(y,d,b,x,n);else{let S;f&&(S=this.pluralResolver.getSuffix(b,n.count,n));const E=`${this.options.pluralSeparator}zero`,C=`${this.options.pluralSeparator}ordinal${this.options.pluralSeparator}`;if(f&&(y.push(d+S),n.ordinal&&S.indexOf(C)===0&&y.push(d+S.replace(C,this.options.pluralSeparator)),h&&y.push(d+E)),g){const k=`${d}${this.options.contextSeparator}${n.context}`;y.push(k),f&&(y.push(k+S),n.ordinal&&S.indexOf(C)===0&&y.push(k+S.replace(C,this.options.pluralSeparator)),h&&y.push(k+E))}}let w;for(;w=y.pop();)this.isValidLookup(r)||(o=w,r=this.getResource(b,x,w,n))}))})}),{res:r,usedKey:s,exactUsedKey:o,usedLng:a,usedNS:l}}isValidLookup(t){return t!==void 0&&!(!this.options.returnNull&&t===null)&&!(!this.options.returnEmptyString&&t==="")}getResource(t,n,r){let s=arguments.length>3&&arguments[3]!==void 0?arguments[3]:{};return this.i18nFormat&&this.i18nFormat.getResource?this.i18nFormat.getResource(t,n,r,s):this.resourceStore.getResource(t,n,r,s)}getUsedParamsDetails(){let t=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};const n=["defaultValue","ordinal","context","replace","lng","lngs","fallbackLng","ns","keySeparator","nsSeparator","returnObjects","returnDetails","joinArrays","postProcess","interpolation"],r=t.replace&&typeof t.replace!="string";let s=r?t.replace:t;if(r&&typeof t.count<"u"&&(s.count=t.count),this.options.interpolation.defaultVariables&&(s={...this.options.interpolation.defaultVariables,...s}),!r){s={...s};for(const o of n)delete s[o]}return s}static hasDefaultValue(t){const n="defaultValue";for(const r in t)if(Object.prototype.hasOwnProperty.call(t,r)&&n===r.substring(0,n.length)&&t[r]!==void 0)return!0;return!1}}const Cv=e=>e.charAt(0).toUpperCase()+e.slice(1);class pE{constructor(t){this.options=t,this.supportedLngs=this.options.supportedLngs||!1,this.logger=Is.create("languageUtils")}getScriptPartFromCode(t){if(t=Ph(t),!t||t.indexOf("-")<0)return null;const n=t.split("-");return n.length===2||(n.pop(),n[n.length-1].toLowerCase()==="x")?null:this.formatLanguageCode(n.join("-"))}getLanguagePartFromCode(t){if(t=Ph(t),!t||t.indexOf("-")<0)return t;const n=t.split("-");return this.formatLanguageCode(n[0])}formatLanguageCode(t){if(typeof t=="string"&&t.indexOf("-")>-1){const n=["hans","hant","latn","cyrl","cans","mong","arab"];let r=t.split("-");return this.options.lowerCaseLng?r=r.map(s=>s.toLowerCase()):r.length===2?(r[0]=r[0].toLowerCase(),r[1]=r[1].toUpperCase(),n.indexOf(r[1].toLowerCase())>-1&&(r[1]=Cv(r[1].toLowerCase()))):r.length===3&&(r[0]=r[0].toLowerCase(),r[1].length===2&&(r[1]=r[1].toUpperCase()),r[0]!=="sgn"&&r[2].length===2&&(r[2]=r[2].toUpperCase()),n.indexOf(r[1].toLowerCase())>-1&&(r[1]=Cv(r[1].toLowerCase())),n.indexOf(r[2].toLowerCase())>-1&&(r[2]=Cv(r[2].toLowerCase()))),r.join("-")}return this.options.cleanCode||this.options.lowerCaseLng?t.toLowerCase():t}isSupportedCode(t){return(this.options.load==="languageOnly"||this.options.nonExplicitSupportedLngs)&&(t=this.getLanguagePartFromCode(t)),!this.supportedLngs||!this.supportedLngs.length||this.supportedLngs.indexOf(t)>-1}getBestMatchFromCodes(t){if(!t)return null;let n;return t.forEach(r=>{if(n)return;const s=this.formatLanguageCode(r);(!this.options.supportedLngs||this.isSupportedCode(s))&&(n=s)}),!n&&this.options.supportedLngs&&t.forEach(r=>{if(n)return;const s=this.getLanguagePartFromCode(r);if(this.isSupportedCode(s))return n=s;n=this.options.supportedLngs.find(o=>{if(o===s)return o;if(!(o.indexOf("-")<0&&s.indexOf("-")<0)&&(o.indexOf("-")>0&&s.indexOf("-")<0&&o.substring(0,o.indexOf("-"))===s||o.indexOf(s)===0&&s.length>1))return o})}),n||(n=this.getFallbackCodes(this.options.fallbackLng)[0]),n}getFallbackCodes(t,n){if(!t)return[];if(typeof t=="function"&&(t=t(n)),typeof t=="string"&&(t=[t]),Array.isArray(t))return t;if(!n)return t.default||[];let r=t[n];return r||(r=t[this.getScriptPartFromCode(n)]),r||(r=t[this.formatLanguageCode(n)]),r||(r=t[this.getLanguagePartFromCode(n)]),r||(r=t.default),r||[]}toResolveHierarchy(t,n){const r=this.getFallbackCodes(n||this.options.fallbackLng||[],t),s=[],o=a=>{a&&(this.isSupportedCode(a)?s.push(a):this.logger.warn(`rejecting language code not found in supportedLngs: ${a}`))};return typeof t=="string"&&(t.indexOf("-")>-1||t.indexOf("_")>-1)?(this.options.load!=="languageOnly"&&o(this.formatLanguageCode(t)),this.options.load!=="languageOnly"&&this.options.load!=="currentOnly"&&o(this.getScriptPartFromCode(t)),this.options.load!=="currentOnly"&&o(this.getLanguagePartFromCode(t))):typeof t=="string"&&o(this.formatLanguageCode(t)),r.forEach(a=>{s.indexOf(a)<0&&o(this.formatLanguageCode(a))}),s}}let Pne=[{lngs:["ach","ak","am","arn","br","fil","gun","ln","mfe","mg","mi","oc","pt","pt-BR","tg","tl","ti","tr","uz","wa"],nr:[1,2],fc:1},{lngs:["af","an","ast","az","bg","bn","ca","da","de","dev","el","en","eo","es","et","eu","fi","fo","fur","fy","gl","gu","ha","hi","hu","hy","ia","it","kk","kn","ku","lb","mai","ml","mn","mr","nah","nap","nb","ne","nl","nn","no","nso","pa","pap","pms","ps","pt-PT","rm","sco","se","si","so","son","sq","sv","sw","ta","te","tk","ur","yo"],nr:[1,2],fc:2},{lngs:["ay","bo","cgg","fa","ht","id","ja","jbo","ka","km","ko","ky","lo","ms","sah","su","th","tt","ug","vi","wo","zh"],nr:[1],fc:3},{lngs:["be","bs","cnr","dz","hr","ru","sr","uk"],nr:[1,2,5],fc:4},{lngs:["ar"],nr:[0,1,2,3,11,100],fc:5},{lngs:["cs","sk"],nr:[1,2,5],fc:6},{lngs:["csb","pl"],nr:[1,2,5],fc:7},{lngs:["cy"],nr:[1,2,3,8],fc:8},{lngs:["fr"],nr:[1,2],fc:9},{lngs:["ga"],nr:[1,2,3,7,11],fc:10},{lngs:["gd"],nr:[1,2,3,20],fc:11},{lngs:["is"],nr:[1,2],fc:12},{lngs:["jv"],nr:[0,1],fc:13},{lngs:["kw"],nr:[1,2,3,4],fc:14},{lngs:["lt"],nr:[1,2,10],fc:15},{lngs:["lv"],nr:[1,2,0],fc:16},{lngs:["mk"],nr:[1,2],fc:17},{lngs:["mnk"],nr:[0,1,2],fc:18},{lngs:["mt"],nr:[1,2,11,20],fc:19},{lngs:["or"],nr:[2,1],fc:2},{lngs:["ro"],nr:[1,2,20],fc:20},{lngs:["sl"],nr:[5,1,2,3],fc:21},{lngs:["he","iw"],nr:[1,2,20,21],fc:22}],Mne={1:e=>+(e>1),2:e=>+(e!=1),3:e=>0,4:e=>e%10==1&&e%100!=11?0:e%10>=2&&e%10<=4&&(e%100<10||e%100>=20)?1:2,5:e=>e==0?0:e==1?1:e==2?2:e%100>=3&&e%100<=10?3:e%100>=11?4:5,6:e=>e==1?0:e>=2&&e<=4?1:2,7:e=>e==1?0:e%10>=2&&e%10<=4&&(e%100<10||e%100>=20)?1:2,8:e=>e==1?0:e==2?1:e!=8&&e!=11?2:3,9:e=>+(e>=2),10:e=>e==1?0:e==2?1:e<7?2:e<11?3:4,11:e=>e==1||e==11?0:e==2||e==12?1:e>2&&e<20?2:3,12:e=>+(e%10!=1||e%100==11),13:e=>+(e!==0),14:e=>e==1?0:e==2?1:e==3?2:3,15:e=>e%10==1&&e%100!=11?0:e%10>=2&&(e%100<10||e%100>=20)?1:2,16:e=>e%10==1&&e%100!=11?0:e!==0?1:2,17:e=>e==1||e%10==1&&e%100!=11?0:1,18:e=>e==0?0:e==1?1:2,19:e=>e==1?0:e==0||e%100>1&&e%100<11?1:e%100>10&&e%100<20?2:3,20:e=>e==1?0:e==0||e%100>0&&e%100<20?1:2,21:e=>e%100==1?1:e%100==2?2:e%100==3||e%100==4?3:0,22:e=>e==1?0:e==2?1:(e<0||e>10)&&e%10==0?2:3};const One=["v1","v2","v3"],Nne=["v4"],hE={zero:0,one:1,two:2,few:3,many:4,other:5},Ine=()=>{const e={};return Pne.forEach(t=>{t.lngs.forEach(n=>{e[n]={numbers:t.nr,plurals:Mne[t.fc]}})}),e};class Dne{constructor(t){let n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};this.languageUtils=t,this.options=n,this.logger=Is.create("pluralResolver"),(!this.options.compatibilityJSON||Nne.includes(this.options.compatibilityJSON))&&(typeof Intl>"u"||!Intl.PluralRules)&&(this.options.compatibilityJSON="v3",this.logger.error("Your environment seems not to be Intl API compatible, use an Intl.PluralRules polyfill. Will fallback to the compatibilityJSON v3 format handling.")),this.rules=Ine(),this.pluralRulesCache={}}addRule(t,n){this.rules[t]=n}clearCache(){this.pluralRulesCache={}}getRule(t){let n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};if(this.shouldUseIntlApi())try{const r=Ph(t==="dev"?"en":t),s=n.ordinal?"ordinal":"cardinal",o=JSON.stringify({cleanedCode:r,type:s});if(o in this.pluralRulesCache)return this.pluralRulesCache[o];const a=new Intl.PluralRules(r,{type:s});return this.pluralRulesCache[o]=a,a}catch{return}return this.rules[t]||this.rules[this.languageUtils.getLanguagePartFromCode(t)]}needsPlural(t){let n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};const r=this.getRule(t,n);return this.shouldUseIntlApi()?r&&r.resolvedOptions().pluralCategories.length>1:r&&r.numbers.length>1}getPluralFormsOfKey(t,n){let r=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{};return this.getSuffixes(t,r).map(s=>`${n}${s}`)}getSuffixes(t){let n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};const r=this.getRule(t,n);return r?this.shouldUseIntlApi()?r.resolvedOptions().pluralCategories.sort((s,o)=>hE[s]-hE[o]).map(s=>`${this.options.prepend}${n.ordinal?`ordinal${this.options.prepend}`:""}${s}`):r.numbers.map(s=>this.getSuffix(t,s,n)):[]}getSuffix(t,n){let r=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{};const s=this.getRule(t,r);return s?this.shouldUseIntlApi()?`${this.options.prepend}${r.ordinal?`ordinal${this.options.prepend}`:""}${s.select(n)}`:this.getSuffixRetroCompatible(s,n):(this.logger.warn(`no plural rule found for: ${t}`),"")}getSuffixRetroCompatible(t,n){const r=t.noAbs?t.plurals(n):t.plurals(Math.abs(n));let s=t.numbers[r];this.options.simplifyPluralSuffix&&t.numbers.length===2&&t.numbers[0]===1&&(s===2?s="plural":s===1&&(s=""));const o=()=>this.options.prepend&&s.toString()?this.options.prepend+s.toString():s.toString();return this.options.compatibilityJSON==="v1"?s===1?"":typeof s=="number"?`_plural_${s.toString()}`:o():this.options.compatibilityJSON==="v2"||this.options.simplifyPluralSuffix&&t.numbers.length===2&&t.numbers[0]===1?o():this.options.prepend&&r.toString()?this.options.prepend+r.toString():r.toString()}shouldUseIntlApi(){return!One.includes(this.options.compatibilityJSON)}}const gE=function(e,t,n){let r=arguments.length>3&&arguments[3]!==void 0?arguments[3]:".",s=arguments.length>4&&arguments[4]!==void 0?arguments[4]:!0,o=Cne(e,t,n);return!o&&s&&typeof n=="string"&&(o=_b(e,n,r),o===void 0&&(o=_b(t,n,r))),o},Ev=e=>e.replace(/\$/g,"$$$$");class Ane{constructor(){let t=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};this.logger=Is.create("interpolator"),this.options=t,this.format=t.interpolation&&t.interpolation.format||(n=>n),this.init(t)}init(){let t=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};t.interpolation||(t.interpolation={escapeValue:!0});const{escape:n,escapeValue:r,useRawValueToEscape:s,prefix:o,prefixEscaped:a,suffix:l,suffixEscaped:c,formatSeparator:i,unescapeSuffix:d,unescapePrefix:p,nestingPrefix:f,nestingPrefixEscaped:h,nestingSuffix:g,nestingSuffixEscaped:m,nestingOptionsSeparator:x,maxReplaces:b,alwaysFormat:y}=t.interpolation;this.escape=n!==void 0?n:Tne,this.escapeValue=r!==void 0?r:!0,this.useRawValueToEscape=s!==void 0?s:!1,this.prefix=o?Xi(o):a||"{{",this.suffix=l?Xi(l):c||"}}",this.formatSeparator=i||",",this.unescapePrefix=d?"":p||"-",this.unescapeSuffix=this.unescapePrefix?"":d||"",this.nestingPrefix=f?Xi(f):h||Xi("$t("),this.nestingSuffix=g?Xi(g):m||Xi(")"),this.nestingOptionsSeparator=x||",",this.maxReplaces=b||1e3,this.alwaysFormat=y!==void 0?y:!1,this.resetRegExp()}reset(){this.options&&this.init(this.options)}resetRegExp(){const t=(n,r)=>n&&n.source===r?(n.lastIndex=0,n):new RegExp(r,"g");this.regexp=t(this.regexp,`${this.prefix}(.+?)${this.suffix}`),this.regexpUnescape=t(this.regexpUnescape,`${this.prefix}${this.unescapePrefix}(.+?)${this.unescapeSuffix}${this.suffix}`),this.nestingRegexp=t(this.nestingRegexp,`${this.nestingPrefix}(.+?)${this.nestingSuffix}`)}interpolate(t,n,r,s){let o,a,l;const c=this.options&&this.options.interpolation&&this.options.interpolation.defaultVariables||{},i=h=>{if(h.indexOf(this.formatSeparator)<0){const b=gE(n,c,h,this.options.keySeparator,this.options.ignoreJSONStructure);return this.alwaysFormat?this.format(b,void 0,r,{...s,...n,interpolationkey:h}):b}const g=h.split(this.formatSeparator),m=g.shift().trim(),x=g.join(this.formatSeparator).trim();return this.format(gE(n,c,m,this.options.keySeparator,this.options.ignoreJSONStructure),x,r,{...s,...n,interpolationkey:m})};this.resetRegExp();const d=s&&s.missingInterpolationHandler||this.options.missingInterpolationHandler,p=s&&s.interpolation&&s.interpolation.skipOnVariables!==void 0?s.interpolation.skipOnVariables:this.options.interpolation.skipOnVariables;return[{regex:this.regexpUnescape,safeValue:h=>Ev(h)},{regex:this.regexp,safeValue:h=>this.escapeValue?Ev(this.escape(h)):Ev(h)}].forEach(h=>{for(l=0;o=h.regex.exec(t);){const g=o[1].trim();if(a=i(g),a===void 0)if(typeof d=="function"){const x=d(t,o,s);a=typeof x=="string"?x:""}else if(s&&Object.prototype.hasOwnProperty.call(s,g))a="";else if(p){a=o[0];continue}else this.logger.warn(`missed to pass in variable ${g} for interpolating ${t}`),a="";else typeof a!="string"&&!this.useRawValueToEscape&&(a=iE(a));const m=h.safeValue(a);if(t=t.replace(o[0],m),p?(h.regex.lastIndex+=a.length,h.regex.lastIndex-=o[0].length):h.regex.lastIndex=0,l++,l>=this.maxReplaces)break}}),t}nest(t,n){let r=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{},s,o,a;const l=(c,i)=>{const d=this.nestingOptionsSeparator;if(c.indexOf(d)<0)return c;const p=c.split(new RegExp(`${d}[ ]*{`));let f=`{${p[1]}`;c=p[0],f=this.interpolate(f,a);const h=f.match(/'/g),g=f.match(/"/g);(h&&h.length%2===0&&!g||g.length%2!==0)&&(f=f.replace(/'/g,'"'));try{a=JSON.parse(f),i&&(a={...i,...a})}catch(m){return this.logger.warn(`failed parsing options string in nesting for key ${c}`,m),`${c}${d}${f}`}return a.defaultValue&&a.defaultValue.indexOf(this.prefix)>-1&&delete a.defaultValue,c};for(;s=this.nestingRegexp.exec(t);){let c=[];a={...r},a=a.replace&&typeof a.replace!="string"?a.replace:a,a.applyPostProcessor=!1,delete a.defaultValue;let i=!1;if(s[0].indexOf(this.formatSeparator)!==-1&&!/{.*}/.test(s[1])){const d=s[1].split(this.formatSeparator).map(p=>p.trim());s[1]=d.shift(),c=d,i=!0}if(o=n(l.call(this,s[1].trim(),a),a),o&&s[0]===t&&typeof o!="string")return o;typeof o!="string"&&(o=iE(o)),o||(this.logger.warn(`missed to resolve ${s[1]} for nesting ${t}`),o=""),i&&(o=c.reduce((d,p)=>this.format(d,p,r.lng,{...r,interpolationkey:s[1].trim()}),o.trim())),t=t.replace(s[0],o),this.regexp.lastIndex=0}return t}}const Fne=e=>{let t=e.toLowerCase().trim();const n={};if(e.indexOf("(")>-1){const r=e.split("(");t=r[0].toLowerCase().trim();const s=r[1].substring(0,r[1].length-1);t==="currency"&&s.indexOf(":")<0?n.currency||(n.currency=s.trim()):t==="relativetime"&&s.indexOf(":")<0?n.range||(n.range=s.trim()):s.split(";").forEach(a=>{if(a){const[l,...c]=a.split(":"),i=c.join(":").trim().replace(/^'+|'+$/g,""),d=l.trim();n[d]||(n[d]=i),i==="false"&&(n[d]=!1),i==="true"&&(n[d]=!0),isNaN(i)||(n[d]=parseInt(i,10))}})}return{formatName:t,formatOptions:n}},el=e=>{const t={};return(n,r,s)=>{let o=s;s&&s.interpolationkey&&s.formatParams&&s.formatParams[s.interpolationkey]&&s[s.interpolationkey]&&(o={...o,[s.interpolationkey]:void 0});const a=r+JSON.stringify(o);let l=t[a];return l||(l=e(Ph(r),s),t[a]=l),l(n)}};class Lne{constructor(){let t=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};this.logger=Is.create("formatter"),this.options=t,this.formats={number:el((n,r)=>{const s=new Intl.NumberFormat(n,{...r});return o=>s.format(o)}),currency:el((n,r)=>{const s=new Intl.NumberFormat(n,{...r,style:"currency"});return o=>s.format(o)}),datetime:el((n,r)=>{const s=new Intl.DateTimeFormat(n,{...r});return o=>s.format(o)}),relativetime:el((n,r)=>{const s=new Intl.RelativeTimeFormat(n,{...r});return o=>s.format(o,r.range||"day")}),list:el((n,r)=>{const s=new Intl.ListFormat(n,{...r});return o=>s.format(o)})},this.init(t)}init(t){const r=(arguments.length>1&&arguments[1]!==void 0?arguments[1]:{interpolation:{}}).interpolation;this.formatSeparator=r.formatSeparator?r.formatSeparator:r.formatSeparator||","}add(t,n){this.formats[t.toLowerCase().trim()]=n}addCached(t,n){this.formats[t.toLowerCase().trim()]=el(n)}format(t,n,r){let s=arguments.length>3&&arguments[3]!==void 0?arguments[3]:{};const o=n.split(this.formatSeparator);if(o.length>1&&o[0].indexOf("(")>1&&o[0].indexOf(")")<0&&o.find(l=>l.indexOf(")")>-1)){const l=o.findIndex(c=>c.indexOf(")")>-1);o[0]=[o[0],...o.splice(1,l)].join(this.formatSeparator)}return o.reduce((l,c)=>{const{formatName:i,formatOptions:d}=Fne(c);if(this.formats[i]){let p=l;try{const f=s&&s.formatParams&&s.formatParams[s.interpolationkey]||{},h=f.locale||f.lng||s.locale||s.lng||r;p=this.formats[i](l,h,{...d,...s,...f})}catch(f){this.logger.warn(f)}return p}else this.logger.warn(`there was no format function for ${i}`);return l},t)}}const $ne=(e,t)=>{e.pending[t]!==void 0&&(delete e.pending[t],e.pendingCount--)};class Bne extends nm{constructor(t,n,r){let s=arguments.length>3&&arguments[3]!==void 0?arguments[3]:{};super(),this.backend=t,this.store=n,this.services=r,this.languageUtils=r.languageUtils,this.options=s,this.logger=Is.create("backendConnector"),this.waitingReads=[],this.maxParallelReads=s.maxParallelReads||10,this.readingCalls=0,this.maxRetries=s.maxRetries>=0?s.maxRetries:5,this.retryTimeout=s.retryTimeout>=1?s.retryTimeout:350,this.state={},this.queue=[],this.backend&&this.backend.init&&this.backend.init(r,s.backend,s)}queueLoad(t,n,r,s){const o={},a={},l={},c={};return t.forEach(i=>{let d=!0;n.forEach(p=>{const f=`${i}|${p}`;!r.reload&&this.store.hasResourceBundle(i,p)?this.state[f]=2:this.state[f]<0||(this.state[f]===1?a[f]===void 0&&(a[f]=!0):(this.state[f]=1,d=!1,a[f]===void 0&&(a[f]=!0),o[f]===void 0&&(o[f]=!0),c[p]===void 0&&(c[p]=!0)))}),d||(l[i]=!0)}),(Object.keys(o).length||Object.keys(a).length)&&this.queue.push({pending:a,pendingCount:Object.keys(a).length,loaded:{},errors:[],callback:s}),{toLoad:Object.keys(o),pending:Object.keys(a),toLoadLanguages:Object.keys(l),toLoadNamespaces:Object.keys(c)}}loaded(t,n,r){const s=t.split("|"),o=s[0],a=s[1];n&&this.emit("failedLoading",o,a,n),!n&&r&&this.store.addResourceBundle(o,a,r,void 0,void 0,{skipCopy:!0}),this.state[t]=n?-1:2,n&&r&&(this.state[t]=0);const l={};this.queue.forEach(c=>{Sne(c.loaded,[o],a),$ne(c,t),n&&c.errors.push(n),c.pendingCount===0&&!c.done&&(Object.keys(c.loaded).forEach(i=>{l[i]||(l[i]={});const d=c.loaded[i];d.length&&d.forEach(p=>{l[i][p]===void 0&&(l[i][p]=!0)})}),c.done=!0,c.errors.length?c.callback(c.errors):c.callback())}),this.emit("loaded",l),this.queue=this.queue.filter(c=>!c.done)}read(t,n,r){let s=arguments.length>3&&arguments[3]!==void 0?arguments[3]:0,o=arguments.length>4&&arguments[4]!==void 0?arguments[4]:this.retryTimeout,a=arguments.length>5?arguments[5]:void 0;if(!t.length)return a(null,{});if(this.readingCalls>=this.maxParallelReads){this.waitingReads.push({lng:t,ns:n,fcName:r,tried:s,wait:o,callback:a});return}this.readingCalls++;const l=(i,d)=>{if(this.readingCalls--,this.waitingReads.length>0){const p=this.waitingReads.shift();this.read(p.lng,p.ns,p.fcName,p.tried,p.wait,p.callback)}if(i&&d&&s{this.read.call(this,t,n,r,s+1,o*2,a)},o);return}a(i,d)},c=this.backend[r].bind(this.backend);if(c.length===2){try{const i=c(t,n);i&&typeof i.then=="function"?i.then(d=>l(null,d)).catch(l):l(null,i)}catch(i){l(i)}return}return c(t,n,l)}prepareLoading(t,n){let r=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{},s=arguments.length>3?arguments[3]:void 0;if(!this.backend)return this.logger.warn("No backend was added via i18next.use. Will not load resources."),s&&s();typeof t=="string"&&(t=this.languageUtils.toResolveHierarchy(t)),typeof n=="string"&&(n=[n]);const o=this.queueLoad(t,n,r,s);if(!o.toLoad.length)return o.pending.length||s(),null;o.toLoad.forEach(a=>{this.loadOne(a)})}load(t,n,r){this.prepareLoading(t,n,{},r)}reload(t,n,r){this.prepareLoading(t,n,{reload:!0},r)}loadOne(t){let n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:"";const r=t.split("|"),s=r[0],o=r[1];this.read(s,o,"read",void 0,void 0,(a,l)=>{a&&this.logger.warn(`${n}loading namespace ${o} for language ${s} failed`,a),!a&&l&&this.logger.log(`${n}loaded namespace ${o} for language ${s}`,l),this.loaded(t,a,l)})}saveMissing(t,n,r,s,o){let a=arguments.length>5&&arguments[5]!==void 0?arguments[5]:{},l=arguments.length>6&&arguments[6]!==void 0?arguments[6]:()=>{};if(this.services.utils&&this.services.utils.hasLoadedNamespace&&!this.services.utils.hasLoadedNamespace(n)){this.logger.warn(`did not save key "${r}" as the namespace "${n}" was not yet loaded`,"This means something IS WRONG in your setup. You access the t function before i18next.init / i18next.loadNamespace / i18next.changeLanguage was done. Wait for the callback or Promise to resolve before accessing it!!!");return}if(!(r==null||r==="")){if(this.backend&&this.backend.create){const c={...a,isUpdate:o},i=this.backend.create.bind(this.backend);if(i.length<6)try{let d;i.length===5?d=i(t,n,r,s,c):d=i(t,n,r,s),d&&typeof d.then=="function"?d.then(p=>l(null,p)).catch(l):l(null,d)}catch(d){l(d)}else i(t,n,r,s,l,c)}!t||!t[0]||this.store.addResource(t[0],n,r,s)}}}const mE=()=>({debug:!1,initImmediate:!0,ns:["translation"],defaultNS:["translation"],fallbackLng:["dev"],fallbackNS:!1,supportedLngs:!1,nonExplicitSupportedLngs:!1,load:"all",preload:!1,simplifyPluralSuffix:!0,keySeparator:".",nsSeparator:":",pluralSeparator:"_",contextSeparator:"_",partialBundledLanguages:!1,saveMissing:!1,updateMissing:!1,saveMissingTo:"fallback",saveMissingPlurals:!0,missingKeyHandler:!1,missingInterpolationHandler:!1,postProcess:!1,postProcessPassResolved:!1,returnNull:!1,returnEmptyString:!0,returnObjects:!1,joinArrays:!1,returnedObjectHandler:!1,parseMissingKeyHandler:!1,appendNamespaceToMissingKey:!1,appendNamespaceToCIMode:!1,overloadTranslationOptionHandler:e=>{let t={};if(typeof e[1]=="object"&&(t=e[1]),typeof e[1]=="string"&&(t.defaultValue=e[1]),typeof e[2]=="string"&&(t.tDescription=e[2]),typeof e[2]=="object"||typeof e[3]=="object"){const n=e[3]||e[2];Object.keys(n).forEach(r=>{t[r]=n[r]})}return t},interpolation:{escapeValue:!0,format:e=>e,prefix:"{{",suffix:"}}",formatSeparator:",",unescapePrefix:"-",nestingPrefix:"$t(",nestingSuffix:")",nestingOptionsSeparator:",",maxReplaces:1e3,skipOnVariables:!0}}),vE=e=>(typeof e.ns=="string"&&(e.ns=[e.ns]),typeof e.fallbackLng=="string"&&(e.fallbackLng=[e.fallbackLng]),typeof e.fallbackNS=="string"&&(e.fallbackNS=[e.fallbackNS]),e.supportedLngs&&e.supportedLngs.indexOf("cimode")<0&&(e.supportedLngs=e.supportedLngs.concat(["cimode"])),e),Qf=()=>{},zne=e=>{Object.getOwnPropertyNames(Object.getPrototypeOf(e)).forEach(n=>{typeof e[n]=="function"&&(e[n]=e[n].bind(e))})};class Pd extends nm{constructor(){let t=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},n=arguments.length>1?arguments[1]:void 0;if(super(),this.options=vE(t),this.services={},this.logger=Is,this.modules={external:[]},zne(this),n&&!this.isInitialized&&!t.isClone){if(!this.options.initImmediate)return this.init(t,n),this;setTimeout(()=>{this.init(t,n)},0)}}init(){var t=this;let n=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},r=arguments.length>1?arguments[1]:void 0;this.isInitializing=!0,typeof n=="function"&&(r=n,n={}),!n.defaultNS&&n.defaultNS!==!1&&n.ns&&(typeof n.ns=="string"?n.defaultNS=n.ns:n.ns.indexOf("translation")<0&&(n.defaultNS=n.ns[0]));const s=mE();this.options={...s,...this.options,...vE(n)},this.options.compatibilityAPI!=="v1"&&(this.options.interpolation={...s.interpolation,...this.options.interpolation}),n.keySeparator!==void 0&&(this.options.userDefinedKeySeparator=n.keySeparator),n.nsSeparator!==void 0&&(this.options.userDefinedNsSeparator=n.nsSeparator);const o=d=>d?typeof d=="function"?new d:d:null;if(!this.options.isClone){this.modules.logger?Is.init(o(this.modules.logger),this.options):Is.init(null,this.options);let d;this.modules.formatter?d=this.modules.formatter:typeof Intl<"u"&&(d=Lne);const p=new pE(this.options);this.store=new dE(this.options.resources,this.options);const f=this.services;f.logger=Is,f.resourceStore=this.store,f.languageUtils=p,f.pluralResolver=new Dne(p,{prepend:this.options.pluralSeparator,compatibilityJSON:this.options.compatibilityJSON,simplifyPluralSuffix:this.options.simplifyPluralSuffix}),d&&(!this.options.interpolation.format||this.options.interpolation.format===s.interpolation.format)&&(f.formatter=o(d),f.formatter.init(f,this.options),this.options.interpolation.format=f.formatter.format.bind(f.formatter)),f.interpolator=new Ane(this.options),f.utils={hasLoadedNamespace:this.hasLoadedNamespace.bind(this)},f.backendConnector=new Bne(o(this.modules.backend),f.resourceStore,f,this.options),f.backendConnector.on("*",function(h){for(var g=arguments.length,m=new Array(g>1?g-1:0),x=1;x1?g-1:0),x=1;x{h.init&&h.init(this)})}if(this.format=this.options.interpolation.format,r||(r=Qf),this.options.fallbackLng&&!this.services.languageDetector&&!this.options.lng){const d=this.services.languageUtils.getFallbackCodes(this.options.fallbackLng);d.length>0&&d[0]!=="dev"&&(this.options.lng=d[0])}!this.services.languageDetector&&!this.options.lng&&this.logger.warn("init: no languageDetector is used and no lng is defined"),["getResource","hasResourceBundle","getResourceBundle","getDataByLanguage"].forEach(d=>{this[d]=function(){return t.store[d](...arguments)}}),["addResource","addResources","addResourceBundle","removeResourceBundle"].forEach(d=>{this[d]=function(){return t.store[d](...arguments),t}});const c=sc(),i=()=>{const d=(p,f)=>{this.isInitializing=!1,this.isInitialized&&!this.initializedStoreOnce&&this.logger.warn("init: i18next is already initialized. You should call init just once!"),this.isInitialized=!0,this.options.isClone||this.logger.log("initialized",this.options),this.emit("initialized",this.options),c.resolve(f),r(p,f)};if(this.languages&&this.options.compatibilityAPI!=="v1"&&!this.isInitialized)return d(null,this.t.bind(this));this.changeLanguage(this.options.lng,d)};return this.options.resources||!this.options.initImmediate?i():setTimeout(i,0),c}loadResources(t){let r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:Qf;const s=typeof t=="string"?t:this.language;if(typeof t=="function"&&(r=t),!this.options.resources||this.options.partialBundledLanguages){if(s&&s.toLowerCase()==="cimode"&&(!this.options.preload||this.options.preload.length===0))return r();const o=[],a=l=>{if(!l||l==="cimode")return;this.services.languageUtils.toResolveHierarchy(l).forEach(i=>{i!=="cimode"&&o.indexOf(i)<0&&o.push(i)})};s?a(s):this.services.languageUtils.getFallbackCodes(this.options.fallbackLng).forEach(c=>a(c)),this.options.preload&&this.options.preload.forEach(l=>a(l)),this.services.backendConnector.load(o,this.options.ns,l=>{!l&&!this.resolvedLanguage&&this.language&&this.setResolvedLanguage(this.language),r(l)})}else r(null)}reloadResources(t,n,r){const s=sc();return typeof t=="function"&&(r=t,t=void 0),typeof n=="function"&&(r=n,n=void 0),t||(t=this.languages),n||(n=this.options.ns),r||(r=Qf),this.services.backendConnector.reload(t,n,o=>{s.resolve(),r(o)}),s}use(t){if(!t)throw new Error("You are passing an undefined module! Please check the object you are passing to i18next.use()");if(!t.type)throw new Error("You are passing a wrong module! Please check the object you are passing to i18next.use()");return t.type==="backend"&&(this.modules.backend=t),(t.type==="logger"||t.log&&t.warn&&t.error)&&(this.modules.logger=t),t.type==="languageDetector"&&(this.modules.languageDetector=t),t.type==="i18nFormat"&&(this.modules.i18nFormat=t),t.type==="postProcessor"&&zI.addPostProcessor(t),t.type==="formatter"&&(this.modules.formatter=t),t.type==="3rdParty"&&this.modules.external.push(t),this}setResolvedLanguage(t){if(!(!t||!this.languages)&&!(["cimode","dev"].indexOf(t)>-1))for(let n=0;n-1)&&this.store.hasLanguageSomeTranslations(r)){this.resolvedLanguage=r;break}}}changeLanguage(t,n){var r=this;this.isLanguageChangingTo=t;const s=sc();this.emit("languageChanging",t);const o=c=>{this.language=c,this.languages=this.services.languageUtils.toResolveHierarchy(c),this.resolvedLanguage=void 0,this.setResolvedLanguage(c)},a=(c,i)=>{i?(o(i),this.translator.changeLanguage(i),this.isLanguageChangingTo=void 0,this.emit("languageChanged",i),this.logger.log("languageChanged",i)):this.isLanguageChangingTo=void 0,s.resolve(function(){return r.t(...arguments)}),n&&n(c,function(){return r.t(...arguments)})},l=c=>{!t&&!c&&this.services.languageDetector&&(c=[]);const i=typeof c=="string"?c:this.services.languageUtils.getBestMatchFromCodes(c);i&&(this.language||o(i),this.translator.language||this.translator.changeLanguage(i),this.services.languageDetector&&this.services.languageDetector.cacheUserLanguage&&this.services.languageDetector.cacheUserLanguage(i)),this.loadResources(i,d=>{a(d,i)})};return!t&&this.services.languageDetector&&!this.services.languageDetector.async?l(this.services.languageDetector.detect()):!t&&this.services.languageDetector&&this.services.languageDetector.async?this.services.languageDetector.detect.length===0?this.services.languageDetector.detect().then(l):this.services.languageDetector.detect(l):l(t),s}getFixedT(t,n,r){var s=this;const o=function(a,l){let c;if(typeof l!="object"){for(var i=arguments.length,d=new Array(i>2?i-2:0),p=2;p`${c.keyPrefix}${f}${g}`):h=c.keyPrefix?`${c.keyPrefix}${f}${a}`:a,s.t(h,c)};return typeof t=="string"?o.lng=t:o.lngs=t,o.ns=n,o.keyPrefix=r,o}t(){return this.translator&&this.translator.translate(...arguments)}exists(){return this.translator&&this.translator.exists(...arguments)}setDefaultNamespace(t){this.options.defaultNS=t}hasLoadedNamespace(t){let n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};if(!this.isInitialized)return this.logger.warn("hasLoadedNamespace: i18next was not initialized",this.languages),!1;if(!this.languages||!this.languages.length)return this.logger.warn("hasLoadedNamespace: i18n.languages were undefined or empty",this.languages),!1;const r=n.lng||this.resolvedLanguage||this.languages[0],s=this.options?this.options.fallbackLng:!1,o=this.languages[this.languages.length-1];if(r.toLowerCase()==="cimode")return!0;const a=(l,c)=>{const i=this.services.backendConnector.state[`${l}|${c}`];return i===-1||i===0||i===2};if(n.precheck){const l=n.precheck(this,a);if(l!==void 0)return l}return!!(this.hasResourceBundle(r,t)||!this.services.backendConnector.backend||this.options.resources&&!this.options.partialBundledLanguages||a(r,t)&&(!s||a(o,t)))}loadNamespaces(t,n){const r=sc();return this.options.ns?(typeof t=="string"&&(t=[t]),t.forEach(s=>{this.options.ns.indexOf(s)<0&&this.options.ns.push(s)}),this.loadResources(s=>{r.resolve(),n&&n(s)}),r):(n&&n(),Promise.resolve())}loadLanguages(t,n){const r=sc();typeof t=="string"&&(t=[t]);const s=this.options.preload||[],o=t.filter(a=>s.indexOf(a)<0&&this.services.languageUtils.isSupportedCode(a));return o.length?(this.options.preload=s.concat(o),this.loadResources(a=>{r.resolve(),n&&n(a)}),r):(n&&n(),Promise.resolve())}dir(t){if(t||(t=this.resolvedLanguage||(this.languages&&this.languages.length>0?this.languages[0]:this.language)),!t)return"rtl";const n=["ar","shu","sqr","ssh","xaa","yhd","yud","aao","abh","abv","acm","acq","acw","acx","acy","adf","ads","aeb","aec","afb","ajp","apc","apd","arb","arq","ars","ary","arz","auz","avl","ayh","ayl","ayn","ayp","bbz","pga","he","iw","ps","pbt","pbu","pst","prp","prd","ug","ur","ydd","yds","yih","ji","yi","hbo","men","xmn","fa","jpr","peo","pes","prs","dv","sam","ckb"],r=this.services&&this.services.languageUtils||new pE(mE());return n.indexOf(r.getLanguagePartFromCode(t))>-1||t.toLowerCase().indexOf("-arab")>1?"rtl":"ltr"}static createInstance(){let t=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},n=arguments.length>1?arguments[1]:void 0;return new Pd(t,n)}cloneInstance(){let t=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:Qf;const r=t.forkResourceStore;r&&delete t.forkResourceStore;const s={...this.options,...t,isClone:!0},o=new Pd(s);return(t.debug!==void 0||t.prefix!==void 0)&&(o.logger=o.logger.clone(t)),["store","services","language"].forEach(l=>{o[l]=this[l]}),o.services={...this.services},o.services.utils={hasLoadedNamespace:o.hasLoadedNamespace.bind(o)},r&&(o.store=new dE(this.store.data,s),o.services.resourceStore=o.store),o.translator=new Mh(o.services,s),o.translator.on("*",function(l){for(var c=arguments.length,i=new Array(c>1?c-1:0),d=1;d:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.75rem * var(--tw-space-x-reverse));margin-left:calc(.75rem * calc(1 - var(--tw-space-x-reverse)))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.375rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.divide-x>:not([hidden])~:not([hidden]){--tw-divide-x-reverse: 0;border-right-width:calc(1px * var(--tw-divide-x-reverse));border-left-width:calc(1px * calc(1 - var(--tw-divide-x-reverse)))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse))}.self-end{align-self:flex-end}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-visible{overflow:visible}.overflow-y-auto{overflow-y:auto}.overflow-x-hidden{overflow-x:hidden}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-ellipsis{text-overflow:ellipsis}.whitespace-nowrap{white-space:nowrap}.text-wrap{text-wrap:wrap}.break-all{word-break:break-all}.rounded-3xl{border-radius:1.5rem}.rounded-\[2px\]{border-radius:2px}.rounded-\[inherit\]{border-radius:inherit}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:var(--radius)}.rounded-md{border-radius:calc(var(--radius) - 2px)}.rounded-sm{border-radius:calc(var(--radius) - 4px)}.rounded-xl{border-radius:.75rem}.border{border-width:1px}.border-2{border-width:2px}.border-\[1\.5px\]{border-width:1.5px}.border-b{border-bottom-width:1px}.border-l{border-left-width:1px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-dashed{border-style:dashed}.border-none{border-style:none}.border-\[--color-border\]{border-color:var(--color-border)}.border-amber-500\/20{border-color:#f59e0b33}.border-black{--tw-border-opacity: 1;border-color:rgb(0 0 0 / var(--tw-border-opacity))}.border-border{border-color:hsl(var(--border))}.border-border\/50{border-color:hsl(var(--border) / .5)}.border-emerald-500\/20{border-color:#10b98133}.border-gray-600\/50{border-color:#4b556380}.border-input{border-color:hsl(var(--input))}.border-muted{border-color:hsl(var(--muted))}.border-red-500\/20{border-color:#ef444433}.border-sky-500\/20{border-color:#0ea5e933}.border-transparent{border-color:transparent}.border-zinc-500\/20{border-color:#71717a33}.border-l-transparent{border-left-color:transparent}.border-t-transparent{border-top-color:transparent}.bg-\[--color-bg\]{background-color:var(--color-bg)}.bg-amber-50\/50{background-color:#fffbeb80}.bg-amber-600{--tw-bg-opacity: 1;background-color:rgb(217 119 6 / var(--tw-bg-opacity))}.bg-background{background-color:hsl(var(--background))}.bg-background\/80{background-color:hsl(var(--background) / .8)}.bg-border{background-color:hsl(var(--border))}.bg-card{background-color:hsl(var(--card))}.bg-destructive{background-color:hsl(var(--destructive))}.bg-emerald-50\/50{background-color:#ecfdf580}.bg-muted{background-color:hsl(var(--muted))}.bg-muted\/50{background-color:hsl(var(--muted) / .5)}.bg-popover{background-color:hsl(var(--popover))}.bg-primary{background-color:hsl(var(--primary))}.bg-primary\/20{background-color:hsl(var(--primary) / .2)}.bg-primary\/30{background-color:hsl(var(--primary) / .3)}.bg-red-50\/50{background-color:#fef2f280}.bg-secondary{background-color:hsl(var(--secondary))}.bg-sky-50\/50{background-color:#f0f9ff80}.bg-transparent{background-color:transparent}.bg-zinc-50\/50{background-color:#fafafa80}.fill-current{fill:currentColor}.p-0{padding:0}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-6{padding:1.5rem}.p-8{padding:2rem}.p-\[1px\]{padding:1px}.px-1{padding-left:.25rem;padding-right:.25rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-8{padding-left:2rem;padding-right:2rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.pb-3{padding-bottom:.75rem}.pl-12{padding-left:3rem}.pl-2{padding-left:.5rem}.pl-3{padding-left:.75rem}.pl-8{padding-left:2rem}.pr-16{padding-right:4rem}.pr-2{padding-right:.5rem}.pr-4{padding-right:1rem}.pt-0{padding-top:0}.pt-2{padding-top:.5rem}.pt-3{padding-top:.75rem}.pt-5{padding-top:1.25rem}.pt-6{padding-top:1.5rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-middle{vertical-align:middle}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.tabular-nums{--tw-numeric-spacing: tabular-nums;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.leading-none{line-height:1}.tracking-tight{letter-spacing:-.025em}.tracking-wide{letter-spacing:.025em}.tracking-widest{letter-spacing:.1em}.text-amber-100{--tw-text-opacity: 1;color:rgb(254 243 199 / var(--tw-text-opacity))}.text-amber-900{--tw-text-opacity: 1;color:rgb(120 53 15 / var(--tw-text-opacity))}.text-card-foreground{color:hsl(var(--card-foreground))}.text-destructive-foreground{color:hsl(var(--destructive-foreground))}.text-emerald-900{--tw-text-opacity: 1;color:rgb(6 78 59 / var(--tw-text-opacity))}.text-foreground{color:hsl(var(--foreground))}.text-gray-500{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity))}.text-muted-foreground{color:hsl(var(--muted-foreground))}.text-muted-foreground\/80{color:hsl(var(--muted-foreground) / .8)}.text-popover-foreground{color:hsl(var(--popover-foreground))}.text-primary{color:hsl(var(--primary))}.text-primary-foreground{color:hsl(var(--primary-foreground))}.text-red-900{--tw-text-opacity: 1;color:rgb(127 29 29 / var(--tw-text-opacity))}.text-rose-600{--tw-text-opacity: 1;color:rgb(225 29 72 / var(--tw-text-opacity))}.text-secondary-foreground{color:hsl(var(--secondary-foreground))}.text-sky-900{--tw-text-opacity: 1;color:rgb(12 74 110 / var(--tw-text-opacity))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.text-zinc-900{--tw-text-opacity: 1;color:rgb(24 24 27 / var(--tw-text-opacity))}.underline-offset-4{text-underline-offset:4px}.caret-transparent{caret-color:transparent}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.opacity-70{opacity:.7}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-none{--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-xl{--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid transparent;outline-offset:2px}.outline{outline-style:solid}.ring-0{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-2{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-muted-foreground{--tw-ring-color: hsl(var(--muted-foreground))}.ring-offset-background{--tw-ring-offset-color: hsl(var(--background))}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur-sm{--tw-backdrop-blur: blur(4px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-200{transition-duration:.2s}@keyframes enter{0%{opacity:var(--tw-enter-opacity, 1);transform:translate3d(var(--tw-enter-translate-x, 0),var(--tw-enter-translate-y, 0),0) scale3d(var(--tw-enter-scale, 1),var(--tw-enter-scale, 1),var(--tw-enter-scale, 1)) rotate(var(--tw-enter-rotate, 0))}}@keyframes exit{to{opacity:var(--tw-exit-opacity, 1);transform:translate3d(var(--tw-exit-translate-x, 0),var(--tw-exit-translate-y, 0),0) scale3d(var(--tw-exit-scale, 1),var(--tw-exit-scale, 1),var(--tw-exit-scale, 1)) rotate(var(--tw-exit-rotate, 0))}}.duration-200{animation-duration:.2s}.paused{animation-play-state:paused}.file\:border-0::file-selector-button{border-width:0px}.file\:bg-transparent::file-selector-button{background-color:transparent}.file\:text-sm::file-selector-button{font-size:.875rem;line-height:1.25rem}.file\:font-medium::file-selector-button{font-weight:500}.placeholder\:text-muted-foreground::-moz-placeholder{color:hsl(var(--muted-foreground))}.placeholder\:text-muted-foreground::placeholder{color:hsl(var(--muted-foreground))}.after\:absolute:after{content:var(--tw-content);position:absolute}.after\:inset-y-0:after{content:var(--tw-content);top:0;bottom:0}.after\:left-1\/2:after{content:var(--tw-content);left:50%}.after\:w-1:after{content:var(--tw-content);width:.25rem}.after\:-translate-x-1\/2:after{content:var(--tw-content);--tw-translate-x: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.after\:bg-border:after{content:var(--tw-content);background-color:hsl(var(--border))}.hover\:bg-accent:hover{background-color:hsl(var(--accent))}.hover\:bg-amber-600\/80:hover{background-color:#d97706cc}.hover\:bg-amber-600\/90:hover{background-color:#d97706e6}.hover\:bg-destructive\/80:hover{background-color:hsl(var(--destructive) / .8)}.hover\:bg-destructive\/90:hover{background-color:hsl(var(--destructive) / .9)}.hover\:bg-muted\/50:hover{background-color:hsl(var(--muted) / .5)}.hover\:bg-primary\/80:hover{background-color:hsl(var(--primary) / .8)}.hover\:bg-primary\/90:hover{background-color:hsl(var(--primary) / .9)}.hover\:bg-secondary\/80:hover{background-color:hsl(var(--secondary) / .8)}.hover\:bg-transparent:hover{background-color:transparent}.hover\:stroke-destructive:hover{stroke:hsl(var(--destructive))}.hover\:text-accent-foreground:hover{color:hsl(var(--accent-foreground))}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-100:hover{opacity:1}.focus\:bg-accent:focus{background-color:hsl(var(--accent))}.focus\:text-accent-foreground:focus{color:hsl(var(--accent-foreground))}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-2:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-ring:focus{--tw-ring-color: hsl(var(--ring))}.focus\:ring-offset-2:focus{--tw-ring-offset-width: 2px}.focus-visible\:outline-none:focus-visible{outline:2px solid transparent;outline-offset:2px}.focus-visible\:ring-1:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus-visible\:ring-2:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus-visible\:ring-ring:focus-visible{--tw-ring-color: hsl(var(--ring))}.focus-visible\:ring-offset-1:focus-visible{--tw-ring-offset-width: 1px}.focus-visible\:ring-offset-2:focus-visible{--tw-ring-offset-width: 2px}.focus-visible\:ring-offset-background:focus-visible{--tw-ring-offset-color: hsl(var(--background))}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}.peer:disabled~.peer-disabled\:cursor-not-allowed{cursor:not-allowed}.peer:disabled~.peer-disabled\:opacity-70{opacity:.7}.aria-selected\:bg-accent[aria-selected=true]{background-color:hsl(var(--accent))}.aria-selected\:text-accent-foreground[aria-selected=true]{color:hsl(var(--accent-foreground))}.data-\[disabled\]\:pointer-events-none[data-disabled]{pointer-events:none}.data-\[panel-group-direction\=vertical\]\:h-px[data-panel-group-direction=vertical]{height:1px}.data-\[panel-group-direction\=vertical\]\:w-full[data-panel-group-direction=vertical]{width:100%}.data-\[side\=bottom\]\:translate-y-1[data-side=bottom]{--tw-translate-y: .25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[side\=left\]\:-translate-x-1[data-side=left]{--tw-translate-x: -.25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[side\=right\]\:translate-x-1[data-side=right]{--tw-translate-x: .25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[side\=top\]\:-translate-y-1[data-side=top]{--tw-translate-y: -.25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[state\=checked\]\:translate-x-5[data-state=checked]{--tw-translate-x: 1.25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[state\=unchecked\]\:translate-x-0[data-state=unchecked]{--tw-translate-x: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[panel-group-direction\=vertical\]\:flex-col[data-panel-group-direction=vertical]{flex-direction:column}.data-\[state\=active\]\:bg-background[data-state=active]{background-color:hsl(var(--background))}.data-\[state\=checked\]\:bg-primary[data-state=checked]{background-color:hsl(var(--primary))}.data-\[state\=open\]\:bg-accent[data-state=open]{background-color:hsl(var(--accent))}.data-\[state\=open\]\:bg-muted[data-state=open],.data-\[state\=selected\]\:bg-muted[data-state=selected]{background-color:hsl(var(--muted))}.data-\[state\=unchecked\]\:bg-slate-400[data-state=unchecked]{--tw-bg-opacity: 1;background-color:rgb(148 163 184 / var(--tw-bg-opacity))}.data-\[state\=active\]\:text-foreground[data-state=active]{color:hsl(var(--foreground))}.data-\[state\=open\]\:text-muted-foreground[data-state=open]{color:hsl(var(--muted-foreground))}.data-\[disabled\]\:opacity-50[data-disabled]{opacity:.5}.data-\[state\=active\]\:shadow-sm[data-state=active]{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.data-\[state\=open\]\:animate-in[data-state=open]{animation-name:enter;animation-duration:.15s;--tw-enter-opacity: initial;--tw-enter-scale: initial;--tw-enter-rotate: initial;--tw-enter-translate-x: initial;--tw-enter-translate-y: initial}.data-\[state\=closed\]\:animate-out[data-state=closed]{animation-name:exit;animation-duration:.15s;--tw-exit-opacity: initial;--tw-exit-scale: initial;--tw-exit-rotate: initial;--tw-exit-translate-x: initial;--tw-exit-translate-y: initial}.data-\[state\=closed\]\:fade-out-0[data-state=closed]{--tw-exit-opacity: 0}.data-\[state\=open\]\:fade-in-0[data-state=open]{--tw-enter-opacity: 0}.data-\[state\=closed\]\:zoom-out-95[data-state=closed]{--tw-exit-scale: .95}.data-\[state\=open\]\:zoom-in-95[data-state=open]{--tw-enter-scale: .95}.data-\[side\=bottom\]\:slide-in-from-top-2[data-side=bottom]{--tw-enter-translate-y: -.5rem}.data-\[side\=left\]\:slide-in-from-right-2[data-side=left]{--tw-enter-translate-x: .5rem}.data-\[side\=right\]\:slide-in-from-left-2[data-side=right]{--tw-enter-translate-x: -.5rem}.data-\[side\=top\]\:slide-in-from-bottom-2[data-side=top]{--tw-enter-translate-y: .5rem}.data-\[state\=closed\]\:slide-out-to-left-1\/2[data-state=closed]{--tw-exit-translate-x: -50%}.data-\[state\=closed\]\:slide-out-to-top-\[48\%\][data-state=closed]{--tw-exit-translate-y: -48%}.data-\[state\=open\]\:slide-in-from-left-1\/2[data-state=open]{--tw-enter-translate-x: -50%}.data-\[state\=open\]\:slide-in-from-top-\[48\%\][data-state=open]{--tw-enter-translate-y: -48%}.data-\[panel-group-direction\=vertical\]\:after\:left-0[data-panel-group-direction=vertical]:after{content:var(--tw-content);left:0}.data-\[panel-group-direction\=vertical\]\:after\:h-1[data-panel-group-direction=vertical]:after{content:var(--tw-content);height:.25rem}.data-\[panel-group-direction\=vertical\]\:after\:w-full[data-panel-group-direction=vertical]:after{content:var(--tw-content);width:100%}.data-\[panel-group-direction\=vertical\]\:after\:-translate-y-1\/2[data-panel-group-direction=vertical]:after{content:var(--tw-content);--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[panel-group-direction\=vertical\]\:after\:translate-x-0[data-panel-group-direction=vertical]:after{content:var(--tw-content);--tw-translate-x: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.dark\:-rotate-90:is(.dark *){--tw-rotate: -90deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.dark\:rotate-0:is(.dark *){--tw-rotate: 0deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.dark\:scale-0:is(.dark *){--tw-scale-x: 0;--tw-scale-y: 0;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.dark\:scale-100:is(.dark *){--tw-scale-x: 1;--tw-scale-y: 1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.dark\:border-amber-500\/30:is(.dark *){border-color:#f59e0b4d}.dark\:border-emerald-500\/30:is(.dark *){border-color:#10b9814d}.dark\:border-red-500\/30:is(.dark *){border-color:#ef44444d}.dark\:border-sky-500\/30:is(.dark *){border-color:#0ea5e94d}.dark\:border-zinc-500\/30:is(.dark *){border-color:#71717a4d}.dark\:bg-amber-500\/10:is(.dark *){background-color:#f59e0b1a}.dark\:bg-emerald-500\/10:is(.dark *){background-color:#10b9811a}.dark\:bg-red-500\/10:is(.dark *){background-color:#ef44441a}.dark\:bg-sky-500\/10:is(.dark *){background-color:#0ea5e91a}.dark\:bg-zinc-500\/10:is(.dark *){background-color:#71717a1a}.dark\:text-amber-200:is(.dark *){--tw-text-opacity: 1;color:rgb(253 230 138 / var(--tw-text-opacity))}.dark\:text-emerald-200:is(.dark *){--tw-text-opacity: 1;color:rgb(167 243 208 / var(--tw-text-opacity))}.dark\:text-red-200:is(.dark *){--tw-text-opacity: 1;color:rgb(254 202 202 / var(--tw-text-opacity))}.dark\:text-sky-200:is(.dark *){--tw-text-opacity: 1;color:rgb(186 230 253 / var(--tw-text-opacity))}.dark\:text-zinc-300:is(.dark *){--tw-text-opacity: 1;color:rgb(212 212 216 / var(--tw-text-opacity))}@media (min-width: 640px){.sm\:m-4{margin:1rem}.sm\:inline{display:inline}.sm\:max-h-\[600px\]{max-height:600px}.sm\:max-w-\[650px\]{max-width:650px}.sm\:max-w-\[740px\]{max-width:740px}.sm\:max-w-\[950px\]{max-width:950px}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-\[10rem_1fr_10rem\]{grid-template-columns:10rem 1fr 10rem}.sm\:flex-row{flex-direction:row}.sm\:justify-end{justify-content:flex-end}.sm\:space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.5rem * var(--tw-space-x-reverse));margin-left:calc(.5rem * calc(1 - var(--tw-space-x-reverse)))}.sm\:rounded-lg{border-radius:var(--radius)}.sm\:text-left{text-align:left}}@media (min-width: 768px){.md\:inline{display:inline}.md\:flex{display:flex}.md\:w-64{width:16rem}.md\:w-full{width:100%}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:flex-row{flex-direction:row}.md\:gap-8{gap:2rem}}@media (min-width: 1024px){.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@media (min-width: 1280px){.xl\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}.\[\&\:has\(\[role\=checkbox\]\)\]\:pr-0:has([role=checkbox]){padding-right:0}.\[\&\>\*\]\:p-4>*{padding:1rem}.\[\&\>\*\]\:px-4>*{padding-left:1rem;padding-right:1rem}.\[\&\>\*\]\:py-2>*{padding-top:.5rem;padding-bottom:.5rem}.\[\&\>div\[style\]\]\:\!block>div[style]{display:block!important}.\[\&\>div\[style\]\]\:h-full>div[style]{height:100%}.\[\&\>span\]\:line-clamp-1>span{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:1}.\[\&\>svg\+div\]\:translate-y-\[-3px\]>svg+div{--tw-translate-y: -3px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.\[\&\>svg\]\:absolute>svg{position:absolute}.\[\&\>svg\]\:left-4>svg{left:1rem}.\[\&\>svg\]\:top-4>svg{top:1rem}.\[\&\>svg\]\:h-2\.5>svg{height:.625rem}.\[\&\>svg\]\:h-3>svg{height:.75rem}.\[\&\>svg\]\:w-2\.5>svg{width:.625rem}.\[\&\>svg\]\:w-3>svg{width:.75rem}.\[\&\>svg\]\:fill-rose-600>svg{fill:#e11d48}.\[\&\>svg\]\:text-amber-500>svg{--tw-text-opacity: 1;color:rgb(245 158 11 / var(--tw-text-opacity))}.\[\&\>svg\]\:text-emerald-600>svg{--tw-text-opacity: 1;color:rgb(5 150 105 / var(--tw-text-opacity))}.\[\&\>svg\]\:text-foreground>svg{color:hsl(var(--foreground))}.\[\&\>svg\]\:text-muted-foreground>svg{color:hsl(var(--muted-foreground))}.\[\&\>svg\]\:text-red-600>svg{--tw-text-opacity: 1;color:rgb(220 38 38 / var(--tw-text-opacity))}.\[\&\>svg\]\:text-sky-500>svg{--tw-text-opacity: 1;color:rgb(14 165 233 / var(--tw-text-opacity))}.\[\&\>svg\]\:text-zinc-400>svg{--tw-text-opacity: 1;color:rgb(161 161 170 / var(--tw-text-opacity))}.hover\:\[\&\>svg\]\:fill-rose-700>svg:hover{fill:#be123c}.dark\:\[\&\>svg\]\:text-emerald-400\/80>svg:is(.dark *){color:#34d399cc}.dark\:\[\&\>svg\]\:text-red-400\/80>svg:is(.dark *){color:#f87171cc}.dark\:\[\&\>svg\]\:text-zinc-300>svg:is(.dark *){--tw-text-opacity: 1;color:rgb(212 212 216 / var(--tw-text-opacity))}.\[\&\>svg\~\*\]\:pl-7>svg~*{padding-left:1.75rem}.\[\&\>tr\]\:last\:border-b-0:last-child>tr{border-bottom-width:0px}.\[\&\[data-panel-group-direction\=vertical\]\>div\]\:rotate-90[data-panel-group-direction=vertical]>div{--tw-rotate: 90deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.\[\&_\.recharts-cartesian-axis-tick_text\]\:fill-muted-foreground .recharts-cartesian-axis-tick text{fill:hsl(var(--muted-foreground))}.\[\&_\.recharts-cartesian-grid_line\[stroke\=\'\#ccc\'\]\]\:stroke-border\/50 .recharts-cartesian-grid line[stroke="#ccc"]{stroke:hsl(var(--border) / .5)}.\[\&_\.recharts-curve\.recharts-tooltip-cursor\]\:stroke-border .recharts-curve.recharts-tooltip-cursor{stroke:hsl(var(--border))}.\[\&_\.recharts-dot\[stroke\=\'\#fff\'\]\]\:stroke-transparent .recharts-dot[stroke="#fff"]{stroke:transparent}.\[\&_\.recharts-layer\]\:outline-none .recharts-layer{outline:2px solid transparent;outline-offset:2px}.\[\&_\.recharts-polar-grid_\[stroke\=\'\#ccc\'\]\]\:stroke-border .recharts-polar-grid [stroke="#ccc"]{stroke:hsl(var(--border))}.\[\&_\.recharts-radial-bar-background-sector\]\:fill-muted .recharts-radial-bar-background-sector,.\[\&_\.recharts-rectangle\.recharts-tooltip-cursor\]\:fill-muted .recharts-rectangle.recharts-tooltip-cursor{fill:hsl(var(--muted))}.\[\&_\.recharts-reference-line_\[stroke\=\'\#ccc\'\]\]\:stroke-border .recharts-reference-line [stroke="#ccc"]{stroke:hsl(var(--border))}.\[\&_\.recharts-sector\[stroke\=\'\#fff\'\]\]\:stroke-transparent .recharts-sector[stroke="#fff"]{stroke:transparent}.\[\&_\.recharts-sector\]\:outline-none .recharts-sector,.\[\&_\.recharts-surface\]\:outline-none .recharts-surface{outline:2px solid transparent;outline-offset:2px}.\[\&_\[cmdk-group-heading\]\]\:px-2 [cmdk-group-heading]{padding-left:.5rem;padding-right:.5rem}.\[\&_\[cmdk-group-heading\]\]\:py-1\.5 [cmdk-group-heading]{padding-top:.375rem;padding-bottom:.375rem}.\[\&_\[cmdk-group-heading\]\]\:text-xs [cmdk-group-heading]{font-size:.75rem;line-height:1rem}.\[\&_\[cmdk-group-heading\]\]\:font-medium [cmdk-group-heading]{font-weight:500}.\[\&_\[cmdk-group-heading\]\]\:text-muted-foreground [cmdk-group-heading]{color:hsl(var(--muted-foreground))}.\[\&_\[cmdk-group\]\:not\(\[hidden\]\)_\~\[cmdk-group\]\]\:pt-0 [cmdk-group]:not([hidden])~[cmdk-group]{padding-top:0}.\[\&_\[cmdk-group\]\]\:px-2 [cmdk-group]{padding-left:.5rem;padding-right:.5rem}.\[\&_\[cmdk-input-wrapper\]_svg\]\:h-5 [cmdk-input-wrapper] svg{height:1.25rem}.\[\&_\[cmdk-input-wrapper\]_svg\]\:w-5 [cmdk-input-wrapper] svg{width:1.25rem}.\[\&_\[cmdk-input\]\]\:h-12 [cmdk-input]{height:3rem}.\[\&_\[cmdk-item\]\]\:px-2 [cmdk-item]{padding-left:.5rem;padding-right:.5rem}.\[\&_\[cmdk-item\]\]\:py-3 [cmdk-item]{padding-top:.75rem;padding-bottom:.75rem}.\[\&_\[cmdk-item\]_svg\]\:h-5 [cmdk-item] svg{height:1.25rem}.\[\&_\[cmdk-item\]_svg\]\:w-5 [cmdk-item] svg{width:1.25rem}.\[\&_p\]\:leading-relaxed p{line-height:1.625}.\[\&_strong\]\:text-foreground strong{color:hsl(var(--foreground))}.\[\&_tr\:last-child\]\:border-0 tr:last-child{border-width:0px}.\[\&_tr\]\:border-b tr{border-bottom-width:1px}:root{--toastify-color-light: #fff;--toastify-color-dark: #121212;--toastify-color-info: #3498db;--toastify-color-success: #07bc0c;--toastify-color-warning: #f1c40f;--toastify-color-error: #e74c3c;--toastify-color-transparent: rgba(255, 255, 255, .7);--toastify-icon-color-info: var(--toastify-color-info);--toastify-icon-color-success: var(--toastify-color-success);--toastify-icon-color-warning: var(--toastify-color-warning);--toastify-icon-color-error: var(--toastify-color-error);--toastify-toast-width: 320px;--toastify-toast-offset: 16px;--toastify-toast-top: max(var(--toastify-toast-offset), env(safe-area-inset-top));--toastify-toast-right: max(var(--toastify-toast-offset), env(safe-area-inset-right));--toastify-toast-left: max(var(--toastify-toast-offset), env(safe-area-inset-left));--toastify-toast-bottom: max(var(--toastify-toast-offset), env(safe-area-inset-bottom));--toastify-toast-background: #fff;--toastify-toast-min-height: 64px;--toastify-toast-max-height: 800px;--toastify-toast-bd-radius: 6px;--toastify-font-family: sans-serif;--toastify-z-index: 9999;--toastify-text-color-light: #757575;--toastify-text-color-dark: #fff;--toastify-text-color-info: #fff;--toastify-text-color-success: #fff;--toastify-text-color-warning: #fff;--toastify-text-color-error: #fff;--toastify-spinner-color: #616161;--toastify-spinner-color-empty-area: #e0e0e0;--toastify-color-progress-light: linear-gradient( to right, #4cd964, #5ac8fa, #007aff, #34aadc, #5856d6, #ff2d55 );--toastify-color-progress-dark: #bb86fc;--toastify-color-progress-info: var(--toastify-color-info);--toastify-color-progress-success: var(--toastify-color-success);--toastify-color-progress-warning: var(--toastify-color-warning);--toastify-color-progress-error: var(--toastify-color-error);--toastify-color-progress-bgo: .2}.Toastify__toast-container{z-index:var(--toastify-z-index);-webkit-transform:translate3d(0,0,var(--toastify-z-index));position:fixed;padding:4px;width:var(--toastify-toast-width);box-sizing:border-box;color:#fff}.Toastify__toast-container--top-left{top:var(--toastify-toast-top);left:var(--toastify-toast-left)}.Toastify__toast-container--top-center{top:var(--toastify-toast-top);left:50%;transform:translate(-50%)}.Toastify__toast-container--top-right{top:var(--toastify-toast-top);right:var(--toastify-toast-right)}.Toastify__toast-container--bottom-left{bottom:var(--toastify-toast-bottom);left:var(--toastify-toast-left)}.Toastify__toast-container--bottom-center{bottom:var(--toastify-toast-bottom);left:50%;transform:translate(-50%)}.Toastify__toast-container--bottom-right{bottom:var(--toastify-toast-bottom);right:var(--toastify-toast-right)}@media only screen and (max-width : 480px){.Toastify__toast-container{width:100vw;padding:0;left:env(safe-area-inset-left);margin:0}.Toastify__toast-container--top-left,.Toastify__toast-container--top-center,.Toastify__toast-container--top-right{top:env(safe-area-inset-top);transform:translate(0)}.Toastify__toast-container--bottom-left,.Toastify__toast-container--bottom-center,.Toastify__toast-container--bottom-right{bottom:env(safe-area-inset-bottom);transform:translate(0)}.Toastify__toast-container--rtl{right:env(safe-area-inset-right);left:initial}}.Toastify__toast{--y: 0;position:relative;touch-action:none;min-height:var(--toastify-toast-min-height);box-sizing:border-box;margin-bottom:1rem;padding:8px;border-radius:var(--toastify-toast-bd-radius);box-shadow:0 4px 12px #0000001a;display:flex;justify-content:space-between;max-height:var(--toastify-toast-max-height);font-family:var(--toastify-font-family);cursor:default;direction:ltr;z-index:0;overflow:hidden}.Toastify__toast--stacked{position:absolute;width:100%;transform:translate3d(0,var(--y),0) scale(var(--s));transition:transform .3s}.Toastify__toast--stacked[data-collapsed] .Toastify__toast-body,.Toastify__toast--stacked[data-collapsed] .Toastify__close-button{transition:opacity .1s}.Toastify__toast--stacked[data-collapsed=false]{overflow:visible}.Toastify__toast--stacked[data-collapsed=true]:not(:last-child)>*{opacity:0}.Toastify__toast--stacked:after{content:"";position:absolute;left:0;right:0;height:calc(var(--g) * 1px);bottom:100%}.Toastify__toast--stacked[data-pos=top]{top:0}.Toastify__toast--stacked[data-pos=bot]{bottom:0}.Toastify__toast--stacked[data-pos=bot].Toastify__toast--stacked:before{transform-origin:top}.Toastify__toast--stacked[data-pos=top].Toastify__toast--stacked:before{transform-origin:bottom}.Toastify__toast--stacked:before{content:"";position:absolute;left:0;right:0;bottom:0;height:100%;transform:scaleY(3);z-index:-1}.Toastify__toast--rtl{direction:rtl}.Toastify__toast--close-on-click{cursor:pointer}.Toastify__toast-body{margin:auto 0;flex:1 1 auto;padding:6px;display:flex;align-items:center}.Toastify__toast-body>div:last-child{word-break:break-word;flex:1}.Toastify__toast-icon{margin-inline-end:10px;width:20px;flex-shrink:0;display:flex}.Toastify--animate{animation-fill-mode:both;animation-duration:.5s}.Toastify--animate-icon{animation-fill-mode:both;animation-duration:.3s}@media only screen and (max-width : 480px){.Toastify__toast{margin-bottom:0;border-radius:0}}.Toastify__toast-theme--dark{background:var(--toastify-color-dark);color:var(--toastify-text-color-dark)}.Toastify__toast-theme--light,.Toastify__toast-theme--colored.Toastify__toast--default{background:var(--toastify-color-light);color:var(--toastify-text-color-light)}.Toastify__toast-theme--colored.Toastify__toast--info{color:var(--toastify-text-color-info);background:var(--toastify-color-info)}.Toastify__toast-theme--colored.Toastify__toast--success{color:var(--toastify-text-color-success);background:var(--toastify-color-success)}.Toastify__toast-theme--colored.Toastify__toast--warning{color:var(--toastify-text-color-warning);background:var(--toastify-color-warning)}.Toastify__toast-theme--colored.Toastify__toast--error{color:var(--toastify-text-color-error);background:var(--toastify-color-error)}.Toastify__progress-bar-theme--light{background:var(--toastify-color-progress-light)}.Toastify__progress-bar-theme--dark{background:var(--toastify-color-progress-dark)}.Toastify__progress-bar--info{background:var(--toastify-color-progress-info)}.Toastify__progress-bar--success{background:var(--toastify-color-progress-success)}.Toastify__progress-bar--warning{background:var(--toastify-color-progress-warning)}.Toastify__progress-bar--error{background:var(--toastify-color-progress-error)}.Toastify__progress-bar-theme--colored.Toastify__progress-bar--info,.Toastify__progress-bar-theme--colored.Toastify__progress-bar--success,.Toastify__progress-bar-theme--colored.Toastify__progress-bar--warning,.Toastify__progress-bar-theme--colored.Toastify__progress-bar--error{background:var(--toastify-color-transparent)}.Toastify__close-button{color:#fff;background:transparent;outline:none;border:none;padding:0;cursor:pointer;opacity:.7;transition:.3s ease;align-self:flex-start;z-index:1}.Toastify__close-button--light{color:#000;opacity:.3}.Toastify__close-button>svg{fill:currentColor;height:16px;width:14px}.Toastify__close-button:hover,.Toastify__close-button:focus{opacity:1}@keyframes Toastify__trackProgress{0%{transform:scaleX(1)}to{transform:scaleX(0)}}.Toastify__progress-bar{position:absolute;bottom:0;left:0;width:100%;height:100%;z-index:var(--toastify-z-index);opacity:.7;transform-origin:left;border-bottom-left-radius:var(--toastify-toast-bd-radius)}.Toastify__progress-bar--animated{animation:Toastify__trackProgress linear 1 forwards}.Toastify__progress-bar--controlled{transition:transform .2s}.Toastify__progress-bar--rtl{right:0;left:initial;transform-origin:right;border-bottom-left-radius:initial;border-bottom-right-radius:var(--toastify-toast-bd-radius)}.Toastify__progress-bar--wrp{position:absolute;bottom:0;left:0;width:100%;height:5px;border-bottom-left-radius:var(--toastify-toast-bd-radius)}.Toastify__progress-bar--wrp[data-hidden=true]{opacity:0}.Toastify__progress-bar--bg{opacity:var(--toastify-color-progress-bgo);width:100%;height:100%}.Toastify__spinner{width:20px;height:20px;box-sizing:border-box;border:2px solid;border-radius:100%;border-color:var(--toastify-spinner-color-empty-area);border-right-color:var(--toastify-spinner-color);animation:Toastify__spin .65s linear infinite}@keyframes Toastify__bounceInRight{0%,60%,75%,90%,to{animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;transform:translate3d(3000px,0,0)}60%{opacity:1;transform:translate3d(-25px,0,0)}75%{transform:translate3d(10px,0,0)}90%{transform:translate3d(-5px,0,0)}to{transform:none}}@keyframes Toastify__bounceOutRight{20%{opacity:1;transform:translate3d(-20px,var(--y),0)}to{opacity:0;transform:translate3d(2000px,var(--y),0)}}@keyframes Toastify__bounceInLeft{0%,60%,75%,90%,to{animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;transform:translate3d(-3000px,0,0)}60%{opacity:1;transform:translate3d(25px,0,0)}75%{transform:translate3d(-10px,0,0)}90%{transform:translate3d(5px,0,0)}to{transform:none}}@keyframes Toastify__bounceOutLeft{20%{opacity:1;transform:translate3d(20px,var(--y),0)}to{opacity:0;transform:translate3d(-2000px,var(--y),0)}}@keyframes Toastify__bounceInUp{0%,60%,75%,90%,to{animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;transform:translate3d(0,3000px,0)}60%{opacity:1;transform:translate3d(0,-20px,0)}75%{transform:translate3d(0,10px,0)}90%{transform:translate3d(0,-5px,0)}to{transform:translateZ(0)}}@keyframes Toastify__bounceOutUp{20%{transform:translate3d(0,calc(var(--y) - 10px),0)}40%,45%{opacity:1;transform:translate3d(0,calc(var(--y) + 20px),0)}to{opacity:0;transform:translate3d(0,-2000px,0)}}@keyframes Toastify__bounceInDown{0%,60%,75%,90%,to{animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;transform:translate3d(0,-3000px,0)}60%{opacity:1;transform:translate3d(0,25px,0)}75%{transform:translate3d(0,-10px,0)}90%{transform:translate3d(0,5px,0)}to{transform:none}}@keyframes Toastify__bounceOutDown{20%{transform:translate3d(0,calc(var(--y) - 10px),0)}40%,45%{opacity:1;transform:translate3d(0,calc(var(--y) + 20px),0)}to{opacity:0;transform:translate3d(0,2000px,0)}}.Toastify__bounce-enter--top-left,.Toastify__bounce-enter--bottom-left{animation-name:Toastify__bounceInLeft}.Toastify__bounce-enter--top-right,.Toastify__bounce-enter--bottom-right{animation-name:Toastify__bounceInRight}.Toastify__bounce-enter--top-center{animation-name:Toastify__bounceInDown}.Toastify__bounce-enter--bottom-center{animation-name:Toastify__bounceInUp}.Toastify__bounce-exit--top-left,.Toastify__bounce-exit--bottom-left{animation-name:Toastify__bounceOutLeft}.Toastify__bounce-exit--top-right,.Toastify__bounce-exit--bottom-right{animation-name:Toastify__bounceOutRight}.Toastify__bounce-exit--top-center{animation-name:Toastify__bounceOutUp}.Toastify__bounce-exit--bottom-center{animation-name:Toastify__bounceOutDown}@keyframes Toastify__zoomIn{0%{opacity:0;transform:scale3d(.3,.3,.3)}50%{opacity:1}}@keyframes Toastify__zoomOut{0%{opacity:1}50%{opacity:0;transform:translate3d(0,var(--y),0) scale3d(.3,.3,.3)}to{opacity:0}}.Toastify__zoom-enter{animation-name:Toastify__zoomIn}.Toastify__zoom-exit{animation-name:Toastify__zoomOut}@keyframes Toastify__flipIn{0%{transform:perspective(400px) rotateX(90deg);animation-timing-function:ease-in;opacity:0}40%{transform:perspective(400px) rotateX(-20deg);animation-timing-function:ease-in}60%{transform:perspective(400px) rotateX(10deg);opacity:1}80%{transform:perspective(400px) rotateX(-5deg)}to{transform:perspective(400px)}}@keyframes Toastify__flipOut{0%{transform:translate3d(0,var(--y),0) perspective(400px)}30%{transform:translate3d(0,var(--y),0) perspective(400px) rotateX(-20deg);opacity:1}to{transform:translate3d(0,var(--y),0) perspective(400px) rotateX(90deg);opacity:0}}.Toastify__flip-enter{animation-name:Toastify__flipIn}.Toastify__flip-exit{animation-name:Toastify__flipOut}@keyframes Toastify__slideInRight{0%{transform:translate3d(110%,0,0);visibility:visible}to{transform:translate3d(0,var(--y),0)}}@keyframes Toastify__slideInLeft{0%{transform:translate3d(-110%,0,0);visibility:visible}to{transform:translate3d(0,var(--y),0)}}@keyframes Toastify__slideInUp{0%{transform:translate3d(0,110%,0);visibility:visible}to{transform:translate3d(0,var(--y),0)}}@keyframes Toastify__slideInDown{0%{transform:translate3d(0,-110%,0);visibility:visible}to{transform:translate3d(0,var(--y),0)}}@keyframes Toastify__slideOutRight{0%{transform:translate3d(0,var(--y),0)}to{visibility:hidden;transform:translate3d(110%,var(--y),0)}}@keyframes Toastify__slideOutLeft{0%{transform:translate3d(0,var(--y),0)}to{visibility:hidden;transform:translate3d(-110%,var(--y),0)}}@keyframes Toastify__slideOutDown{0%{transform:translate3d(0,var(--y),0)}to{visibility:hidden;transform:translate3d(0,500px,0)}}@keyframes Toastify__slideOutUp{0%{transform:translate3d(0,var(--y),0)}to{visibility:hidden;transform:translate3d(0,-500px,0)}}.Toastify__slide-enter--top-left,.Toastify__slide-enter--bottom-left{animation-name:Toastify__slideInLeft}.Toastify__slide-enter--top-right,.Toastify__slide-enter--bottom-right{animation-name:Toastify__slideInRight}.Toastify__slide-enter--top-center{animation-name:Toastify__slideInDown}.Toastify__slide-enter--bottom-center{animation-name:Toastify__slideInUp}.Toastify__slide-exit--top-left,.Toastify__slide-exit--bottom-left{animation-name:Toastify__slideOutLeft;animation-timing-function:ease-in;animation-duration:.3s}.Toastify__slide-exit--top-right,.Toastify__slide-exit--bottom-right{animation-name:Toastify__slideOutRight;animation-timing-function:ease-in;animation-duration:.3s}.Toastify__slide-exit--top-center{animation-name:Toastify__slideOutUp;animation-timing-function:ease-in;animation-duration:.3s}.Toastify__slide-exit--bottom-center{animation-name:Toastify__slideOutDown;animation-timing-function:ease-in;animation-duration:.3s}@keyframes Toastify__spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.tabs-chat{background-color:transparent;width:100%;border-radius:0}.chat-item{display:flex;padding:10px;cursor:pointer;background-color:hsl(var(--background))}.chat-item:hover,.chat-item.active{background-color:#2f2f2f}.bubble{border-radius:16px;padding:12px;word-wrap:break-word}.bubble-right .bubble{background-color:#0a0a0a;text-align:right;max-width:100%}.bubble-left .bubble{background-color:#1b1b1b;max-width:100%}.bubble-right{align-self:flex-end;display:flex;justify-content:flex-end;width:80%}.bubble-left{align-self:flex-start;display:flex;justify-content:flex-start;width:80%}.input-message textarea{background-color:#2f2f2f;padding-left:48px}.input-message textarea:focus{outline:none;border:none;box-shadow:none}.message-container{flex:1;overflow-y:auto;max-height:calc(100vh - 110px);padding-top:50px} diff --git a/manager/dist/index.html b/manager/dist/index.html new file mode 100644 index 00000000..0a85ca22 --- /dev/null +++ b/manager/dist/index.html @@ -0,0 +1,14 @@ + + + + + + + Evolution Manager + + + + +
+ + diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..83bd4d16 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,12243 @@ +{ + "name": "evolution-api", + "version": "2.2.3", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "evolution-api", + "version": "2.2.3", + "license": "Apache-2.0", + "dependencies": { + "@adiwajshing/keyed-db": "^0.2.4", + "@aws-sdk/client-sqs": "^3.723.0", + "@ffmpeg-installer/ffmpeg": "^1.1.0", + "@figuro/chatwoot-sdk": "^1.1.16", + "@hapi/boom": "^10.0.1", + "@paralleldrive/cuid2": "^2.2.2", + "@prisma/client": "^6.1.0", + "@sentry/node": "^8.47.0", + "amqplib": "^0.10.5", + "axios": "^1.7.9", + "baileys": "github:EvolutionAPI/Baileys", + "class-validator": "^0.14.1", + "compression": "^1.7.5", + "cors": "^2.8.5", + "dayjs": "^1.11.13", + "dotenv": "^16.4.7", + "eventemitter2": "^6.4.9", + "express": "^4.21.2", + "express-async-errors": "^3.1.1", + "fluent-ffmpeg": "^2.1.3", + "form-data": "^4.0.1", + "https-proxy-agent": "^7.0.6", + "i18next": "^23.7.19", + "jimp": "^0.16.13", + "json-schema": "^0.4.0", + "jsonschema": "^1.4.1", + "link-preview-js": "^3.0.13", + "long": "^5.2.3", + "mediainfo.js": "^0.3.4", + "mime": "^4.0.0", + "mime-types": "^2.1.35", + "minio": "^8.0.3", + "multer": "^1.4.5-lts.1", + "node-cache": "^5.1.2", + "node-cron": "^3.0.3", + "openai": "^4.77.3", + "pg": "^8.13.1", + "pino": "^8.11.0", + "prisma": "^6.1.0", + "pusher": "^5.2.0", + "qrcode": "^1.5.4", + "qrcode-terminal": "^0.12.0", + "redis": "^4.7.0", + "sharp": "^0.32.6", + "socket.io": "^4.8.1", + "socket.io-client": "^4.8.1", + "tsup": "^8.3.5" + }, + "devDependencies": { + "@types/compression": "^1.7.5", + "@types/cors": "^2.8.17", + "@types/express": "^4.17.18", + "@types/json-schema": "^7.0.15", + "@types/mime": "^4.0.0", + "@types/mime-types": "^2.1.4", + "@types/node": "^22.10.5", + "@types/node-cron": "^3.0.11", + "@types/qrcode": "^1.5.5", + "@types/qrcode-terminal": "^0.12.2", + "@types/uuid": "^10.0.0", + "@typescript-eslint/eslint-plugin": "^6.21.0", + "@typescript-eslint/parser": "^6.21.0", + "eslint": "^8.45.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-import": "^2.31.0", + "eslint-plugin-prettier": "^5.2.1", + "eslint-plugin-simple-import-sort": "^10.0.0", + "prettier": "^3.4.2", + "ts-node-dev": "^2.0.0", + "tsconfig-paths": "^4.2.0", + "typescript": "^5.7.2" + } + }, + "node_modules/@acuminous/bitsyntax": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@acuminous/bitsyntax/-/bitsyntax-0.1.2.tgz", + "integrity": "sha512-29lUK80d1muEQqiUsSo+3A0yP6CdspgC95EnKBMi22Xlwt79i/En4Vr67+cXhU+cZjbti3TgGGC5wy1stIywVQ==", + "dependencies": { + "buffer-more-ints": "~1.0.0", + "debug": "^4.3.4", + "safe-buffer": "~5.1.2" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/@adiwajshing/keyed-db": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@adiwajshing/keyed-db/-/keyed-db-0.2.4.tgz", + "integrity": "sha512-yprSnAtj80/VKuDqRcFFLDYltoNV8tChNwFfIgcf6PGD4sjzWIBgs08pRuTqGH5mk5wgL6PBRSsMCZqtZwzFEw==" + }, + "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-sqs": { + "version": "3.738.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sqs/-/client-sqs-3.738.0.tgz", + "integrity": "sha512-wGxZNV0m0NM+IXub61vkwoq3KD88joG45aYpS4+2ADnZLxnUe/Md1AH+ZMznIv5ZAppCXso7S0Tis3LLK85IGw==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.734.0", + "@aws-sdk/credential-provider-node": "3.738.0", + "@aws-sdk/middleware-host-header": "3.734.0", + "@aws-sdk/middleware-logger": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.734.0", + "@aws-sdk/middleware-sdk-sqs": "3.734.0", + "@aws-sdk/middleware-user-agent": "3.734.0", + "@aws-sdk/region-config-resolver": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@aws-sdk/util-endpoints": "3.734.0", + "@aws-sdk/util-user-agent-browser": "3.734.0", + "@aws-sdk/util-user-agent-node": "3.734.0", + "@smithy/config-resolver": "^4.0.1", + "@smithy/core": "^3.1.1", + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/hash-node": "^4.0.1", + "@smithy/invalid-dependency": "^4.0.1", + "@smithy/md5-js": "^4.0.1", + "@smithy/middleware-content-length": "^4.0.1", + "@smithy/middleware-endpoint": "^4.0.2", + "@smithy/middleware-retry": "^4.0.3", + "@smithy/middleware-serde": "^4.0.1", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/node-http-handler": "^4.0.2", + "@smithy/protocol-http": "^5.0.1", + "@smithy/smithy-client": "^4.1.2", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.3", + "@smithy/util-defaults-mode-node": "^4.0.3", + "@smithy/util-endpoints": "^3.0.1", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-retry": "^4.0.1", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sso": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.734.0.tgz", + "integrity": "sha512-oerepp0mut9VlgTwnG5Ds/lb0C0b2/rQ+hL/rF6q+HGKPfGsCuPvFx1GtwGKCXd49ase88/jVgrhcA9OQbz3kg==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.734.0", + "@aws-sdk/middleware-host-header": "3.734.0", + "@aws-sdk/middleware-logger": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.734.0", + "@aws-sdk/middleware-user-agent": "3.734.0", + "@aws-sdk/region-config-resolver": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@aws-sdk/util-endpoints": "3.734.0", + "@aws-sdk/util-user-agent-browser": "3.734.0", + "@aws-sdk/util-user-agent-node": "3.734.0", + "@smithy/config-resolver": "^4.0.1", + "@smithy/core": "^3.1.1", + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/hash-node": "^4.0.1", + "@smithy/invalid-dependency": "^4.0.1", + "@smithy/middleware-content-length": "^4.0.1", + "@smithy/middleware-endpoint": "^4.0.2", + "@smithy/middleware-retry": "^4.0.3", + "@smithy/middleware-serde": "^4.0.1", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/node-http-handler": "^4.0.2", + "@smithy/protocol-http": "^5.0.1", + "@smithy/smithy-client": "^4.1.2", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.3", + "@smithy/util-defaults-mode-node": "^4.0.3", + "@smithy/util-endpoints": "^3.0.1", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-retry": "^4.0.1", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/core": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.734.0.tgz", + "integrity": "sha512-SxnDqf3vobdm50OLyAKfqZetv6zzwnSqwIwd3jrbopxxHKqNIM/I0xcYjD6Tn+mPig+u7iRKb9q3QnEooFTlmg==", + "dependencies": { + "@aws-sdk/types": "3.734.0", + "@smithy/core": "^3.1.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/property-provider": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/signature-v4": "^5.0.1", + "@smithy/smithy-client": "^4.1.2", + "@smithy/types": "^4.1.0", + "@smithy/util-middleware": "^4.0.1", + "fast-xml-parser": "4.4.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.734.0.tgz", + "integrity": "sha512-gtRkzYTGafnm1FPpiNO8VBmJrYMoxhDlGPYDVcijzx3DlF8dhWnowuSBCxLSi+MJMx5hvwrX2A+e/q0QAeHqmw==", + "dependencies": { + "@aws-sdk/core": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@smithy/property-provider": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.734.0.tgz", + "integrity": "sha512-JFSL6xhONsq+hKM8xroIPhM5/FOhiQ1cov0lZxhzZWj6Ai3UAjucy3zyIFDr9MgP1KfCYNdvyaUq9/o+HWvEDg==", + "dependencies": { + "@aws-sdk/core": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/node-http-handler": "^4.0.2", + "@smithy/property-provider": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/smithy-client": "^4.1.2", + "@smithy/types": "^4.1.0", + "@smithy/util-stream": "^4.0.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.734.0.tgz", + "integrity": "sha512-HEyaM/hWI7dNmb4NhdlcDLcgJvrilk8G4DQX6qz0i4pBZGC2l4iffuqP8K6ZQjUfz5/6894PzeFuhTORAMd+cg==", + "dependencies": { + "@aws-sdk/core": "3.734.0", + "@aws-sdk/credential-provider-env": "3.734.0", + "@aws-sdk/credential-provider-http": "3.734.0", + "@aws-sdk/credential-provider-process": "3.734.0", + "@aws-sdk/credential-provider-sso": "3.734.0", + "@aws-sdk/credential-provider-web-identity": "3.734.0", + "@aws-sdk/nested-clients": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@smithy/credential-provider-imds": "^4.0.1", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.738.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.738.0.tgz", + "integrity": "sha512-3MuREsazwBxghKb2sQQHvie+uuK4dX4/ckFYiSoffzJQd0YHxaGxf8cr4NOSCQCUesWu8D3Y0SzlnHGboVSkpA==", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.734.0", + "@aws-sdk/credential-provider-http": "3.734.0", + "@aws-sdk/credential-provider-ini": "3.734.0", + "@aws-sdk/credential-provider-process": "3.734.0", + "@aws-sdk/credential-provider-sso": "3.734.0", + "@aws-sdk/credential-provider-web-identity": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@smithy/credential-provider-imds": "^4.0.1", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.734.0.tgz", + "integrity": "sha512-zvjsUo+bkYn2vjT+EtLWu3eD6me+uun+Hws1IyWej/fKFAqiBPwyeyCgU7qjkiPQSXqk1U9+/HG9IQ6Iiz+eBw==", + "dependencies": { + "@aws-sdk/core": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.734.0.tgz", + "integrity": "sha512-cCwwcgUBJOsV/ddyh1OGb4gKYWEaTeTsqaAK19hiNINfYV/DO9r4RMlnWAo84sSBfJuj9shUNsxzyoe6K7R92Q==", + "dependencies": { + "@aws-sdk/client-sso": "3.734.0", + "@aws-sdk/core": "3.734.0", + "@aws-sdk/token-providers": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.734.0.tgz", + "integrity": "sha512-t4OSOerc+ppK541/Iyn1AS40+2vT/qE+MFMotFkhCgCJbApeRF2ozEdnDN6tGmnl4ybcUuxnp9JWLjwDVlR/4g==", + "dependencies": { + "@aws-sdk/core": "3.734.0", + "@aws-sdk/nested-clients": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@smithy/property-provider": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-host-header": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.734.0.tgz", + "integrity": "sha512-LW7RRgSOHHBzWZnigNsDIzu3AiwtjeI2X66v+Wn1P1u+eXssy1+up4ZY/h+t2sU4LU36UvEf+jrZti9c6vRnFw==", + "dependencies": { + "@aws-sdk/types": "3.734.0", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-logger": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.734.0.tgz", + "integrity": "sha512-mUMFITpJUW3LcKvFok176eI5zXAUomVtahb9IQBwLzkqFYOrMJvWAvoV4yuxrJ8TlQBG8gyEnkb9SnhZvjg67w==", + "dependencies": { + "@aws-sdk/types": "3.734.0", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.734.0.tgz", + "integrity": "sha512-CUat2d9ITsFc2XsmeiRQO96iWpxSKYFjxvj27Hc7vo87YUHRnfMfnc8jw1EpxEwMcvBD7LsRa6vDNky6AjcrFA==", + "dependencies": { + "@aws-sdk/types": "3.734.0", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-sqs": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sqs/-/middleware-sdk-sqs-3.734.0.tgz", + "integrity": "sha512-WetobEBbOFt4WutMYNnhkqNG8FDU9ZTLQ7gY0tGdhUKzHo0h/k9TPRZc8WUeKqacZ7gMWMNOjY251izockqWsQ==", + "dependencies": { + "@aws-sdk/types": "3.734.0", + "@smithy/smithy-client": "^4.1.2", + "@smithy/types": "^4.1.0", + "@smithy/util-hex-encoding": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.734.0.tgz", + "integrity": "sha512-MFVzLWRkfFz02GqGPjqSOteLe5kPfElUrXZft1eElnqulqs6RJfVSpOV7mO90gu293tNAeggMWAVSGRPKIYVMg==", + "dependencies": { + "@aws-sdk/core": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@aws-sdk/util-endpoints": "3.734.0", + "@smithy/core": "^3.1.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.734.0.tgz", + "integrity": "sha512-iph2XUy8UzIfdJFWo1r0Zng9uWj3253yvW9gljhtu+y/LNmNvSnJxQk1f3D2BC5WmcoPZqTS3UsycT3mLPSzWA==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.734.0", + "@aws-sdk/middleware-host-header": "3.734.0", + "@aws-sdk/middleware-logger": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.734.0", + "@aws-sdk/middleware-user-agent": "3.734.0", + "@aws-sdk/region-config-resolver": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@aws-sdk/util-endpoints": "3.734.0", + "@aws-sdk/util-user-agent-browser": "3.734.0", + "@aws-sdk/util-user-agent-node": "3.734.0", + "@smithy/config-resolver": "^4.0.1", + "@smithy/core": "^3.1.1", + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/hash-node": "^4.0.1", + "@smithy/invalid-dependency": "^4.0.1", + "@smithy/middleware-content-length": "^4.0.1", + "@smithy/middleware-endpoint": "^4.0.2", + "@smithy/middleware-retry": "^4.0.3", + "@smithy/middleware-serde": "^4.0.1", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/node-http-handler": "^4.0.2", + "@smithy/protocol-http": "^5.0.1", + "@smithy/smithy-client": "^4.1.2", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.3", + "@smithy/util-defaults-mode-node": "^4.0.3", + "@smithy/util-endpoints": "^3.0.1", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-retry": "^4.0.1", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/region-config-resolver": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.734.0.tgz", + "integrity": "sha512-Lvj1kPRC5IuJBr9DyJ9T9/plkh+EfKLy+12s/mykOy1JaKHDpvj+XGy2YO6YgYVOb8JFtaqloid+5COtje4JTQ==", + "dependencies": { + "@aws-sdk/types": "3.734.0", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-config-provider": "^4.0.0", + "@smithy/util-middleware": "^4.0.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/token-providers": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.734.0.tgz", + "integrity": "sha512-2U6yWKrjWjZO8Y5SHQxkFvMVWHQWbS0ufqfAIBROqmIZNubOL7jXCiVdEFekz6MZ9LF2tvYGnOW4jX8OKDGfIw==", + "dependencies": { + "@aws-sdk/nested-clients": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/types": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.734.0.tgz", + "integrity": "sha512-o11tSPTT70nAkGV1fN9wm/hAIiLPyWX6SuGf+9JyTp7S/rC2cFWhR26MvA69nplcjNaXVzB0f+QFrLXXjOqCrg==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/util-endpoints": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.734.0.tgz", + "integrity": "sha512-w2+/E88NUbqql6uCVAsmMxDQKu7vsKV0KqhlQb0lL+RCq4zy07yXYptVNs13qrnuTfyX7uPXkXrlugvK9R1Ucg==", + "dependencies": { + "@aws-sdk/types": "3.734.0", + "@smithy/types": "^4.1.0", + "@smithy/util-endpoints": "^3.0.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/util-locate-window": { + "version": "3.723.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.723.0.tgz", + "integrity": "sha512-Yf2CS10BqK688DRsrKI/EO6B8ff5J86NXe4C+VCysK7UOgN0l1zOTeTukZ3H8Q9tYYX3oaF1961o8vRkFm7Nmw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.734.0.tgz", + "integrity": "sha512-xQTCus6Q9LwUuALW+S76OL0jcWtMOVu14q+GoLnWPUM7QeUw963oQcLhF7oq0CtaLLKyl4GOUfcwc773Zmwwng==", + "dependencies": { + "@aws-sdk/types": "3.734.0", + "@smithy/types": "^4.1.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.734.0.tgz", + "integrity": "sha512-c6Iinh+RVQKs6jYUFQ64htOU2HUXFQ3TVx+8Tu3EDF19+9vzWi9UukhIMH9rqyyEXIAkk9XL7avt8y2Uyw2dGA==", + "dependencies": { + "@aws-sdk/middleware-user-agent": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "node_modules/@babel/runtime": { + "version": "7.26.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.7.tgz", + "integrity": "sha512-AOPI3D+a8dXnja+iwsUqGRjr1BbZIe771sXdapOtYI531gSqpi92vXivKcq2asu/DFpdl1ceFAKZyRzK2PCVcQ==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "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==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz", + "integrity": "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.2.tgz", + "integrity": "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz", + "integrity": "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.2.tgz", + "integrity": "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz", + "integrity": "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz", + "integrity": "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz", + "integrity": "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz", + "integrity": "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz", + "integrity": "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz", + "integrity": "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz", + "integrity": "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz", + "integrity": "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==", + "cpu": [ + "loong64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz", + "integrity": "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==", + "cpu": [ + "mips64el" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz", + "integrity": "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz", + "integrity": "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz", + "integrity": "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz", + "integrity": "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz", + "integrity": "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz", + "integrity": "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz", + "integrity": "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz", + "integrity": "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz", + "integrity": "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz", + "integrity": "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz", + "integrity": "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz", + "integrity": "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eshaz/web-worker": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@eshaz/web-worker/-/web-worker-1.2.2.tgz", + "integrity": "sha512-WxXiHFmD9u/owrzempiDlBB1ZYqiLnm9s6aPc8AlFQalq2tKmqdmMr9GXOupDgzXtqnBipj8Un0gkIm7Sjf8mw==" + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", + "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "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==", + "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/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@ffmpeg-installer/darwin-arm64": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@ffmpeg-installer/darwin-arm64/-/darwin-arm64-4.1.5.tgz", + "integrity": "sha512-hYqTiP63mXz7wSQfuqfFwfLOfwwFChUedeCVKkBtl/cliaTM7/ePI9bVzfZ2c+dWu3TqCwLDRWNSJ5pqZl8otA==", + "cpu": [ + "arm64" + ], + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@ffmpeg-installer/darwin-x64": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@ffmpeg-installer/darwin-x64/-/darwin-x64-4.1.0.tgz", + "integrity": "sha512-Z4EyG3cIFjdhlY8wI9aLUXuH8nVt7E9SlMVZtWvSPnm2sm37/yC2CwjUzyCQbJbySnef1tQwGG2Sx+uWhd9IAw==", + "cpu": [ + "x64" + ], + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@ffmpeg-installer/ffmpeg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@ffmpeg-installer/ffmpeg/-/ffmpeg-1.1.0.tgz", + "integrity": "sha512-Uq4rmwkdGxIa9A6Bd/VqqYbT7zqh1GrT5/rFwCwKM70b42W5gIjWeVETq6SdcL0zXqDtY081Ws/iJWhr1+xvQg==", + "optionalDependencies": { + "@ffmpeg-installer/darwin-arm64": "4.1.5", + "@ffmpeg-installer/darwin-x64": "4.1.0", + "@ffmpeg-installer/linux-arm": "4.1.3", + "@ffmpeg-installer/linux-arm64": "4.1.4", + "@ffmpeg-installer/linux-ia32": "4.1.0", + "@ffmpeg-installer/linux-x64": "4.1.0", + "@ffmpeg-installer/win32-ia32": "4.1.0", + "@ffmpeg-installer/win32-x64": "4.1.0" + } + }, + "node_modules/@ffmpeg-installer/linux-arm": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@ffmpeg-installer/linux-arm/-/linux-arm-4.1.3.tgz", + "integrity": "sha512-NDf5V6l8AfzZ8WzUGZ5mV8O/xMzRag2ETR6+TlGIsMHp81agx51cqpPItXPib/nAZYmo55Bl2L6/WOMI3A5YRg==", + "cpu": [ + "arm" + ], + "hasInstallScript": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@ffmpeg-installer/linux-arm64": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@ffmpeg-installer/linux-arm64/-/linux-arm64-4.1.4.tgz", + "integrity": "sha512-dljEqAOD0oIM6O6DxBW9US/FkvqvQwgJ2lGHOwHDDwu/pX8+V0YsDL1xqHbj1DMX/+nP9rxw7G7gcUvGspSoKg==", + "cpu": [ + "arm64" + ], + "hasInstallScript": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@ffmpeg-installer/linux-ia32": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@ffmpeg-installer/linux-ia32/-/linux-ia32-4.1.0.tgz", + "integrity": "sha512-0LWyFQnPf+Ij9GQGD034hS6A90URNu9HCtQ5cTqo5MxOEc7Rd8gLXrJvn++UmxhU0J5RyRE9KRYstdCVUjkNOQ==", + "cpu": [ + "ia32" + ], + "hasInstallScript": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@ffmpeg-installer/linux-x64": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@ffmpeg-installer/linux-x64/-/linux-x64-4.1.0.tgz", + "integrity": "sha512-Y5BWhGLU/WpQjOArNIgXD3z5mxxdV8c41C+U15nsE5yF8tVcdCGet5zPs5Zy3Ta6bU7haGpIzryutqCGQA/W8A==", + "cpu": [ + "x64" + ], + "hasInstallScript": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@ffmpeg-installer/win32-ia32": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@ffmpeg-installer/win32-ia32/-/win32-ia32-4.1.0.tgz", + "integrity": "sha512-FV2D7RlaZv/lrtdhaQ4oETwoFUsUjlUiasiZLDxhEUPdNDWcH1OU9K1xTvqz+OXLdsmYelUDuBS/zkMOTtlUAw==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@ffmpeg-installer/win32-x64": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@ffmpeg-installer/win32-x64/-/win32-x64-4.1.0.tgz", + "integrity": "sha512-Drt5u2vzDnIONf4ZEkKtFlbvwj6rI3kxw1Ck9fpudmtgaZIHD4ucsWB2lCZBXRxJgXR+2IMSti+4rtM4C4rXgg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@figuro/chatwoot-sdk": { + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/@figuro/chatwoot-sdk/-/chatwoot-sdk-1.1.16.tgz", + "integrity": "sha512-u3wGCAt0Y2KXuEi+tIssaP/x0mFFwD99d2cXsysmBsFA0Bus0LGjEVjD/pJ2RGLvG+M/kxzqDGsLkSgzLjcP0w==", + "dependencies": { + "axios": "^0.27.2" + } + }, + "node_modules/@figuro/chatwoot-sdk/node_modules/axios": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", + "dependencies": { + "follow-redirects": "^1.14.9", + "form-data": "^4.0.0" + } + }, + "node_modules/@hapi/boom": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@hapi/boom/-/boom-10.0.1.tgz", + "integrity": "sha512-ERcCZaEjdH3OgSJlyjVk8pHIFeus91CjKP3v+MpgBNp5IvGzP2l/bRiD78nqYcKPaZdbKkK5vDBVPd2ohHBlsA==", + "dependencies": { + "@hapi/hoek": "^11.0.2" + } + }, + "node_modules/@hapi/hoek": { + "version": "11.0.7", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-11.0.7.tgz", + "integrity": "sha512-HV5undWkKzcB4RZUusqOpcgxOaq6VOAH7zhhIr2g3G8NF/MlFO75SjOr2NfuSx0Mh40+1FqCkagKLJRykUWoFQ==" + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "deprecated": "Use @eslint/config-array instead", + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/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==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "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==", + "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" + }, + "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.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/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/@isaacs/cliui/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/@isaacs/cliui/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/@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/cliui/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/@jimp/bmp": { + "version": "0.16.13", + "resolved": "https://registry.npmjs.org/@jimp/bmp/-/bmp-0.16.13.tgz", + "integrity": "sha512-9edAxu7N2FX7vzkdl5Jo1BbACfycUtBQX+XBMcHA2bk62P8R0otgkHg798frgAk/WxQIzwxqOH6wMiCwrlAzdQ==", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.16.13", + "bmp-js": "^0.1.0" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/core": { + "version": "0.16.13", + "resolved": "https://registry.npmjs.org/@jimp/core/-/core-0.16.13.tgz", + "integrity": "sha512-qXpA1tzTnlkTku9yqtuRtS/wVntvE6f3m3GNxdTdtmc+O+Wcg9Xo2ABPMh7Nc0AHbMKzwvwgB2JnjZmlmJEObg==", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.16.13", + "any-base": "^1.1.0", + "buffer": "^5.2.0", + "exif-parser": "^0.1.12", + "file-type": "^16.5.4", + "load-bmfont": "^1.3.1", + "mkdirp": "^0.5.1", + "phin": "^2.9.1", + "pixelmatch": "^4.0.2", + "tinycolor2": "^1.4.1" + } + }, + "node_modules/@jimp/custom": { + "version": "0.16.13", + "resolved": "https://registry.npmjs.org/@jimp/custom/-/custom-0.16.13.tgz", + "integrity": "sha512-LTATglVUPGkPf15zX1wTMlZ0+AU7cGEGF6ekVF1crA8eHUWsGjrYTB+Ht4E3HTrCok8weQG+K01rJndCp/l4XA==", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/core": "^0.16.13" + } + }, + "node_modules/@jimp/gif": { + "version": "0.16.13", + "resolved": "https://registry.npmjs.org/@jimp/gif/-/gif-0.16.13.tgz", + "integrity": "sha512-yFAMZGv3o+YcjXilMWWwS/bv1iSqykFahFMSO169uVMtfQVfa90kt4/kDwrXNR6Q9i6VHpFiGZMlF2UnHClBvg==", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.16.13", + "gifwrap": "^0.9.2", + "omggif": "^1.0.9" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/jpeg": { + "version": "0.16.13", + "resolved": "https://registry.npmjs.org/@jimp/jpeg/-/jpeg-0.16.13.tgz", + "integrity": "sha512-BJHlDxzTlCqP2ThqP8J0eDrbBfod7npWCbJAcfkKqdQuFk0zBPaZ6KKaQKyKxmWJ87Z6ohANZoMKEbtvrwz1AA==", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.16.13", + "jpeg-js": "^0.4.2" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-blit": { + "version": "0.16.13", + "resolved": "https://registry.npmjs.org/@jimp/plugin-blit/-/plugin-blit-0.16.13.tgz", + "integrity": "sha512-8Z1k96ZFxlhK2bgrY1JNWNwvaBeI/bciLM0yDOni2+aZwfIIiC7Y6PeWHTAvjHNjphz+XCt01WQmOYWCn0ML6g==", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.16.13" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-blur": { + "version": "0.16.13", + "resolved": "https://registry.npmjs.org/@jimp/plugin-blur/-/plugin-blur-0.16.13.tgz", + "integrity": "sha512-PvLrfa8vkej3qinlebyhLpksJgCF5aiysDMSVhOZqwH5nQLLtDE9WYbnsofGw4r0VVpyw3H/ANCIzYTyCtP9Cg==", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.16.13" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-circle": { + "version": "0.16.13", + "resolved": "https://registry.npmjs.org/@jimp/plugin-circle/-/plugin-circle-0.16.13.tgz", + "integrity": "sha512-RNave7EFgZrb5V5EpdvJGAEHMnDAJuwv05hKscNfIYxf0kR3KhViBTDy+MoTnMlIvaKFULfwIgaZWzyhuINMzA==", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.16.13" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-color": { + "version": "0.16.13", + "resolved": "https://registry.npmjs.org/@jimp/plugin-color/-/plugin-color-0.16.13.tgz", + "integrity": "sha512-xW+9BtEvoIkkH/Wde9ql4nAFbYLkVINhpgAE7VcBUsuuB34WUbcBl/taOuUYQrPEFQJ4jfXiAJZ2H/rvKjCVnQ==", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.16.13", + "tinycolor2": "^1.4.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-contain": { + "version": "0.16.13", + "resolved": "https://registry.npmjs.org/@jimp/plugin-contain/-/plugin-contain-0.16.13.tgz", + "integrity": "sha512-QayTXw4tXMwU6q6acNTQrTTFTXpNRBe+MgTGMDU0lk+23PjlFCO/9sacflelG8lsp7vNHhAxFeHptDMAksEYzg==", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.16.13" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-blit": ">=0.3.5", + "@jimp/plugin-resize": ">=0.3.5", + "@jimp/plugin-scale": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-cover": { + "version": "0.16.13", + "resolved": "https://registry.npmjs.org/@jimp/plugin-cover/-/plugin-cover-0.16.13.tgz", + "integrity": "sha512-BSsP71GTNaqWRcvkbWuIVH+zK7b3TSNebbhDkFK0fVaUTzHuKMS/mgY4hDZIEVt7Rf5FjadAYtsujHN9w0iSYA==", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.16.13" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-crop": ">=0.3.5", + "@jimp/plugin-resize": ">=0.3.5", + "@jimp/plugin-scale": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-crop": { + "version": "0.16.13", + "resolved": "https://registry.npmjs.org/@jimp/plugin-crop/-/plugin-crop-0.16.13.tgz", + "integrity": "sha512-WEl2tPVYwzYL8OKme6Go2xqiWgKsgxlMwyHabdAU4tXaRwOCnOI7v4021gCcBb9zn/oWwguHuKHmK30Fw2Z/PA==", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.16.13" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-displace": { + "version": "0.16.13", + "resolved": "https://registry.npmjs.org/@jimp/plugin-displace/-/plugin-displace-0.16.13.tgz", + "integrity": "sha512-qt9WKq8vWrcjySa9DyQ0x/RBMHQeiVjdVSY1SJsMjssPUf0pS74qorcuAkGi89biN3YoGUgPkpqECnAWnYwgGA==", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.16.13" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-dither": { + "version": "0.16.13", + "resolved": "https://registry.npmjs.org/@jimp/plugin-dither/-/plugin-dither-0.16.13.tgz", + "integrity": "sha512-5/N3yJggbWQTlGZHQYJPmQXEwR52qaXjEzkp1yRBbtdaekXE3BG/suo0fqeoV/csf8ooI78sJzYmIrxNoWVtgQ==", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.16.13" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-fisheye": { + "version": "0.16.13", + "resolved": "https://registry.npmjs.org/@jimp/plugin-fisheye/-/plugin-fisheye-0.16.13.tgz", + "integrity": "sha512-2rZmTdFbT/cF9lEZIkXCYO0TsT114Q27AX5IAo0Sju6jVQbvIk1dFUTnwLDadTo8wkJlFzGqMQ24Cs8cHWOliA==", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.16.13" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-flip": { + "version": "0.16.13", + "resolved": "https://registry.npmjs.org/@jimp/plugin-flip/-/plugin-flip-0.16.13.tgz", + "integrity": "sha512-EmcgAA74FTc5u7Z+hUO/sRjWwfPPLuOQP5O64x5g4j0T12Bd29IgsYZxoutZo/rb3579+JNa/3wsSEmyVv1EpA==", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.16.13" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-rotate": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-gaussian": { + "version": "0.16.13", + "resolved": "https://registry.npmjs.org/@jimp/plugin-gaussian/-/plugin-gaussian-0.16.13.tgz", + "integrity": "sha512-A1XKfGQD0iDdIiKqFYi8nZMv4dDVYdxbrmgR7y/CzUHhSYdcmoljLIIsZZM3Iks/Wa353W3vtvkWLuDbQbch1w==", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.16.13" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-invert": { + "version": "0.16.13", + "resolved": "https://registry.npmjs.org/@jimp/plugin-invert/-/plugin-invert-0.16.13.tgz", + "integrity": "sha512-xFMrIn7czEZbdbMzZWuaZFnlLGJDVJ82y5vlsKsXRTG2kcxRsMPXvZRWHV57nSs1YFsNqXSbrC8B98n0E32njQ==", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.16.13" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-mask": { + "version": "0.16.13", + "resolved": "https://registry.npmjs.org/@jimp/plugin-mask/-/plugin-mask-0.16.13.tgz", + "integrity": "sha512-wLRYKVBXql2GAYgt6FkTnCfE+q5NomM7Dlh0oIPGAoMBWDyTx0eYutRK6PlUrRK2yMHuroAJCglICTbxqGzowQ==", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.16.13" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-normalize": { + "version": "0.16.13", + "resolved": "https://registry.npmjs.org/@jimp/plugin-normalize/-/plugin-normalize-0.16.13.tgz", + "integrity": "sha512-3tfad0n9soRna4IfW9NzQdQ2Z3ijkmo21DREHbE6CGcMIxOSvfRdSvf1qQPApxjTSo8LTU4MCi/fidx/NZ0GqQ==", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.16.13" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-print": { + "version": "0.16.13", + "resolved": "https://registry.npmjs.org/@jimp/plugin-print/-/plugin-print-0.16.13.tgz", + "integrity": "sha512-0m6i3p01PGRkGAK9r53hDYrkyMq+tlhLOIbsSTmZyh6HLshUKlTB7eXskF5OpVd5ZUHoltlNc6R+ggvKIzxRFw==", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.16.13", + "load-bmfont": "^1.4.0" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-blit": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-resize": { + "version": "0.16.13", + "resolved": "https://registry.npmjs.org/@jimp/plugin-resize/-/plugin-resize-0.16.13.tgz", + "integrity": "sha512-qoqtN8LDknm3fJm9nuPygJv30O3vGhSBD2TxrsCnhtOsxKAqVPJtFVdGd/qVuZ8nqQANQmTlfqTiK9mVWQ7MiQ==", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.16.13" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-rotate": { + "version": "0.16.13", + "resolved": "https://registry.npmjs.org/@jimp/plugin-rotate/-/plugin-rotate-0.16.13.tgz", + "integrity": "sha512-Ev+Jjmj1nHYw897z9C3R9dYsPv7S2/nxdgfFb/h8hOwK0Ovd1k/+yYS46A0uj/JCKK0pQk8wOslYBkPwdnLorw==", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.16.13" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-blit": ">=0.3.5", + "@jimp/plugin-crop": ">=0.3.5", + "@jimp/plugin-resize": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-scale": { + "version": "0.16.13", + "resolved": "https://registry.npmjs.org/@jimp/plugin-scale/-/plugin-scale-0.16.13.tgz", + "integrity": "sha512-05POQaEJVucjTiSGMoH68ZiELc7QqpIpuQlZ2JBbhCV+WCbPFUBcGSmE7w4Jd0E2GvCho/NoMODLwgcVGQA97A==", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.16.13" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-resize": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-shadow": { + "version": "0.16.13", + "resolved": "https://registry.npmjs.org/@jimp/plugin-shadow/-/plugin-shadow-0.16.13.tgz", + "integrity": "sha512-nmu5VSZ9hsB1JchTKhnnCY+paRBnwzSyK5fhkhtQHHoFD5ArBQ/5wU8y6tCr7k/GQhhGq1OrixsECeMjPoc8Zw==", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.16.13" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-blur": ">=0.3.5", + "@jimp/plugin-resize": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-threshold": { + "version": "0.16.13", + "resolved": "https://registry.npmjs.org/@jimp/plugin-threshold/-/plugin-threshold-0.16.13.tgz", + "integrity": "sha512-+3zArBH0OE3Rhjm4HyAokMsZlIq5gpQec33CncyoSwxtRBM2WAhUVmCUKuBo+Lr/2/4ISoY4BWpHKhMLDix6cA==", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.16.13" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-color": ">=0.8.0", + "@jimp/plugin-resize": ">=0.8.0" + } + }, + "node_modules/@jimp/plugins": { + "version": "0.16.13", + "resolved": "https://registry.npmjs.org/@jimp/plugins/-/plugins-0.16.13.tgz", + "integrity": "sha512-CJLdqODEhEVs4MgWCxpWL5l95sCBlkuSLz65cxEm56X5akIsn4LOlwnKoSEZioYcZUBvHhCheH67AyPTudfnQQ==", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/plugin-blit": "^0.16.13", + "@jimp/plugin-blur": "^0.16.13", + "@jimp/plugin-circle": "^0.16.13", + "@jimp/plugin-color": "^0.16.13", + "@jimp/plugin-contain": "^0.16.13", + "@jimp/plugin-cover": "^0.16.13", + "@jimp/plugin-crop": "^0.16.13", + "@jimp/plugin-displace": "^0.16.13", + "@jimp/plugin-dither": "^0.16.13", + "@jimp/plugin-fisheye": "^0.16.13", + "@jimp/plugin-flip": "^0.16.13", + "@jimp/plugin-gaussian": "^0.16.13", + "@jimp/plugin-invert": "^0.16.13", + "@jimp/plugin-mask": "^0.16.13", + "@jimp/plugin-normalize": "^0.16.13", + "@jimp/plugin-print": "^0.16.13", + "@jimp/plugin-resize": "^0.16.13", + "@jimp/plugin-rotate": "^0.16.13", + "@jimp/plugin-scale": "^0.16.13", + "@jimp/plugin-shadow": "^0.16.13", + "@jimp/plugin-threshold": "^0.16.13", + "timm": "^1.6.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/png": { + "version": "0.16.13", + "resolved": "https://registry.npmjs.org/@jimp/png/-/png-0.16.13.tgz", + "integrity": "sha512-8cGqINvbWJf1G0Her9zbq9I80roEX0A+U45xFby3tDWfzn+Zz8XKDF1Nv9VUwVx0N3zpcG1RPs9hfheG4Cq2kg==", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/utils": "^0.16.13", + "pngjs": "^3.3.3" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/tiff": { + "version": "0.16.13", + "resolved": "https://registry.npmjs.org/@jimp/tiff/-/tiff-0.16.13.tgz", + "integrity": "sha512-oJY8d9u95SwW00VPHuCNxPap6Q1+E/xM5QThb9Hu+P6EGuu6lIeLaNBMmFZyblwFbwrH+WBOZlvIzDhi4Dm/6Q==", + "dependencies": { + "@babel/runtime": "^7.7.2", + "utif": "^2.0.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/types": { + "version": "0.16.13", + "resolved": "https://registry.npmjs.org/@jimp/types/-/types-0.16.13.tgz", + "integrity": "sha512-mC0yVNUobFDjoYLg4hoUwzMKgNlxynzwt3cDXzumGvRJ7Kb8qQGOWJQjQFo5OxmGExqzPphkirdbBF88RVLBCg==", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/bmp": "^0.16.13", + "@jimp/gif": "^0.16.13", + "@jimp/jpeg": "^0.16.13", + "@jimp/png": "^0.16.13", + "@jimp/tiff": "^0.16.13", + "timm": "^1.6.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/utils": { + "version": "0.16.13", + "resolved": "https://registry.npmjs.org/@jimp/utils/-/utils-0.16.13.tgz", + "integrity": "sha512-VyCpkZzFTHXtKgVO35iKN0sYR10psGpV6SkcSeV4oF7eSYlR8Bl6aQLCzVeFjvESF7mxTmIiI3/XrMobVrtxDA==", + "dependencies": { + "@babel/runtime": "^7.7.2", + "regenerator-runtime": "^0.13.3" + } + }, + "node_modules/@jimp/utils/node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "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/gen-mapping/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/@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.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@noble/hashes": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.1.tgz", + "integrity": "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "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/@opentelemetry/api": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", + "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/api-logs": { + "version": "0.56.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.56.0.tgz", + "integrity": "sha512-Wr39+94UNNG3Ei9nv3pHd4AJ63gq5nSemMRpCd8fPwDL9rN3vK26lzxfH27mw16XzOSO+TpyQwBAMaLxaPWG0g==", + "dependencies": { + "@opentelemetry/api": "^1.3.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/context-async-hooks": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-1.30.1.tgz", + "integrity": "sha512-s5vvxXPVdjqS3kTLKMeBMvop9hbWkwzBpu+mUO2M7sZtlkyDJGwFe33wRKnbaYDo8ExRVBIIdwIGrqpxHuKttA==", + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/core": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.30.1.tgz", + "integrity": "sha512-OOCM2C/QIURhJMuKaekP3TRBxBKxG/TWWA0TL2J6nXUtDnuCtccy49LUJF8xPFXMX+0LMcxFpCo8M9cGY1W6rQ==", + "dependencies": { + "@opentelemetry/semantic-conventions": "1.28.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/instrumentation": { + "version": "0.56.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.56.0.tgz", + "integrity": "sha512-2KkGBKE+FPXU1F0zKww+stnlUxUTlBvLCiWdP63Z9sqXYeNI/ziNzsxAp4LAdUcTQmXjw1IWgvm5CAb/BHy99w==", + "dependencies": { + "@opentelemetry/api-logs": "0.56.0", + "@types/shimmer": "^1.2.0", + "import-in-the-middle": "^1.8.1", + "require-in-the-middle": "^7.1.1", + "semver": "^7.5.2", + "shimmer": "^1.2.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-amqplib": { + "version": "0.45.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-amqplib/-/instrumentation-amqplib-0.45.0.tgz", + "integrity": "sha512-SlKLsOS65NGMIBG1Lh/hLrMDU9WzTUF25apnV6ZmWZB1bBmUwan7qrwwrTu1cL5LzJWCXOdZPuTaxP7pC9qxnQ==", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.56.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-connect": { + "version": "0.42.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-connect/-/instrumentation-connect-0.42.0.tgz", + "integrity": "sha512-bOoYHBmbnq/jFaLHmXJ55VQ6jrH5fHDMAPjFM0d3JvR0dvIqW7anEoNC33QqYGFYUfVJ50S0d/eoyF61ALqQuA==", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.56.0", + "@opentelemetry/semantic-conventions": "^1.27.0", + "@types/connect": "3.4.36" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-dataloader": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-dataloader/-/instrumentation-dataloader-0.15.0.tgz", + "integrity": "sha512-5fP35A2jUPk4SerVcduEkpbRAIoqa2PaP5rWumn01T1uSbavXNccAr3Xvx1N6xFtZxXpLJq4FYqGFnMgDWgVng==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.56.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-express": { + "version": "0.46.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-express/-/instrumentation-express-0.46.0.tgz", + "integrity": "sha512-BCEClDj/HPq/1xYRAlOr6z+OUnbp2eFp18DSrgyQz4IT9pkdYk8eWHnMi9oZSqlC6J5mQzkFmaW5RrKb1GLQhg==", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.56.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-fastify": { + "version": "0.43.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-fastify/-/instrumentation-fastify-0.43.0.tgz", + "integrity": "sha512-Lmdsg7tYiV+K3/NKVAQfnnLNGmakUOFdB0PhoTh2aXuSyCmyNnnDvhn2MsArAPTZ68wnD5Llh5HtmiuTkf+DyQ==", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.56.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-fs": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-fs/-/instrumentation-fs-0.18.0.tgz", + "integrity": "sha512-kC40y6CEMONm8/MWwoF5GHWIC7gOdF+g3sgsjfwJaUkgD6bdWV+FgG0XApqSbTQndICKzw3RonVk8i7s6mHqhA==", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.56.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-generic-pool": { + "version": "0.42.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-generic-pool/-/instrumentation-generic-pool-0.42.0.tgz", + "integrity": "sha512-J4QxqiQ1imtB9ogzsOnHra0g3dmmLAx4JCeoK3o0rFes1OirljNHnO8Hsj4s1jAir8WmWvnEEQO1y8yk6j2tog==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.56.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-graphql": { + "version": "0.46.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-graphql/-/instrumentation-graphql-0.46.0.tgz", + "integrity": "sha512-tplk0YWINSECcK89PGM7IVtOYenXyoOuhOQlN0X0YrcDUfMS4tZMKkVc0vyhNWYYrexnUHwNry2YNBNugSpjlQ==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.56.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-hapi": { + "version": "0.44.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-hapi/-/instrumentation-hapi-0.44.0.tgz", + "integrity": "sha512-4HdNIMNXWK1O6nsaQOrACo83QWEVoyNODTdVDbUqtqXiv2peDfD0RAPhSQlSGWLPw3S4d9UoOmrV7s2HYj6T2A==", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.56.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-http": { + "version": "0.56.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-http/-/instrumentation-http-0.56.0.tgz", + "integrity": "sha512-/bWHBUAq8VoATnH9iLk5w8CE9+gj+RgYSUphe7hry472n6fYl7+4PvuScoQMdmSUTprKq/gyr2kOWL6zrC7FkQ==", + "dependencies": { + "@opentelemetry/core": "1.29.0", + "@opentelemetry/instrumentation": "0.56.0", + "@opentelemetry/semantic-conventions": "1.28.0", + "forwarded-parse": "2.1.2", + "semver": "^7.5.2" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-http/node_modules/@opentelemetry/core": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.29.0.tgz", + "integrity": "sha512-gmT7vAreXl0DTHD2rVZcw3+l2g84+5XiHIqdBUxXbExymPCvSsGOpiwMmn8nkiJur28STV31wnhIDrzWDPzjfA==", + "dependencies": { + "@opentelemetry/semantic-conventions": "1.28.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/instrumentation-ioredis": { + "version": "0.46.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-ioredis/-/instrumentation-ioredis-0.46.0.tgz", + "integrity": "sha512-sOdsq8oGi29V58p1AkefHvuB3l2ymP1IbxRIX3y4lZesQWKL8fLhBmy8xYjINSQ5gHzWul2yoz7pe7boxhZcqQ==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.56.0", + "@opentelemetry/redis-common": "^0.36.2", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-kafkajs": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-kafkajs/-/instrumentation-kafkajs-0.6.0.tgz", + "integrity": "sha512-MGQrzqEUAl0tacKJUFpuNHJesyTi51oUzSVizn7FdvJplkRIdS11FukyZBZJEscofSEdk7Ycmg+kNMLi5QHUFg==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.56.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-knex": { + "version": "0.43.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-knex/-/instrumentation-knex-0.43.0.tgz", + "integrity": "sha512-mOp0TRQNFFSBj5am0WF67fRO7UZMUmsF3/7HSDja9g3H4pnj+4YNvWWyZn4+q0rGrPtywminAXe0rxtgaGYIqg==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.56.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-koa": { + "version": "0.46.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-koa/-/instrumentation-koa-0.46.0.tgz", + "integrity": "sha512-RcWXMQdJQANnPUaXbHY5G0Fg6gmleZ/ZtZeSsekWPaZmQq12FGk0L1UwodIgs31OlYfviAZ4yTeytoSUkgo5vQ==", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.56.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-lru-memoizer": { + "version": "0.43.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-lru-memoizer/-/instrumentation-lru-memoizer-0.43.0.tgz", + "integrity": "sha512-fZc+1eJUV+tFxaB3zkbupiA8SL3vhDUq89HbDNg1asweYrEb9OlHIB+Ot14ZiHUc1qCmmWmZHbPTwa56mVVwzg==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.56.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-mongodb": { + "version": "0.50.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mongodb/-/instrumentation-mongodb-0.50.0.tgz", + "integrity": "sha512-DtwJMjYFXFT5auAvv8aGrBj1h3ciA/dXQom11rxL7B1+Oy3FopSpanvwYxJ+z0qmBrQ1/iMuWELitYqU4LnlkQ==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.56.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-mongoose": { + "version": "0.45.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mongoose/-/instrumentation-mongoose-0.45.0.tgz", + "integrity": "sha512-zHgNh+A01C5baI2mb5dAGyMC7DWmUpOfwpV8axtC0Hd5Uzqv+oqKgKbVDIVhOaDkPxjgVJwYF9YQZl2pw2qxIA==", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.56.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-mysql": { + "version": "0.44.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mysql/-/instrumentation-mysql-0.44.0.tgz", + "integrity": "sha512-al7jbXvT/uT1KV8gdNDzaWd5/WXf+mrjrsF0/NtbnqLa0UUFGgQnoK3cyborgny7I+KxWhL8h7YPTf6Zq4nKsg==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.56.0", + "@opentelemetry/semantic-conventions": "^1.27.0", + "@types/mysql": "2.15.26" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-mysql2": { + "version": "0.44.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mysql2/-/instrumentation-mysql2-0.44.0.tgz", + "integrity": "sha512-e9QY4AGsjGFwmfHd6kBa4yPaQZjAq2FuxMb0BbKlXCAjG+jwqw+sr9xWdJGR60jMsTq52hx3mAlE3dUJ9BipxQ==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.56.0", + "@opentelemetry/semantic-conventions": "^1.27.0", + "@opentelemetry/sql-common": "^0.40.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-nestjs-core": { + "version": "0.43.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-nestjs-core/-/instrumentation-nestjs-core-0.43.0.tgz", + "integrity": "sha512-NEo4RU7HTjiaXk3curqXUvCb9alRiFWxQY//+hvDXwWLlADX2vB6QEmVCeEZrKO+6I/tBrI4vNdAnbCY9ldZVg==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.56.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-pg": { + "version": "0.49.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-pg/-/instrumentation-pg-0.49.0.tgz", + "integrity": "sha512-3alvNNjPXVdAPdY1G7nGRVINbDxRK02+KAugDiEpzw0jFQfU8IzFkSWA4jyU4/GbMxKvHD+XIOEfSjpieSodKw==", + "dependencies": { + "@opentelemetry/core": "^1.26.0", + "@opentelemetry/instrumentation": "^0.56.0", + "@opentelemetry/semantic-conventions": "1.27.0", + "@opentelemetry/sql-common": "^0.40.1", + "@types/pg": "8.6.1", + "@types/pg-pool": "2.0.6" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-pg/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.27.0.tgz", + "integrity": "sha512-sAay1RrB+ONOem0OZanAR1ZI/k7yDpnOQSQmTMuGImUQb2y8EbSaCJ94FQluM74xoU03vlb2d2U90hZluL6nQg==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/instrumentation-redis-4": { + "version": "0.45.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-redis-4/-/instrumentation-redis-4-0.45.0.tgz", + "integrity": "sha512-Sjgym1xn3mdxPRH5CNZtoz+bFd3E3NlGIu7FoYr4YrQouCc9PbnmoBcmSkEdDy5LYgzNildPgsjx9l0EKNjKTQ==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.56.0", + "@opentelemetry/redis-common": "^0.36.2", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-tedious": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-tedious/-/instrumentation-tedious-0.17.0.tgz", + "integrity": "sha512-yRBz2409an03uVd1Q2jWMt3SqwZqRFyKoWYYX3hBAtPDazJ4w5L+1VOij71TKwgZxZZNdDBXImTQjii+VeuzLg==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.56.0", + "@opentelemetry/semantic-conventions": "^1.27.0", + "@types/tedious": "^4.0.14" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-undici": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-undici/-/instrumentation-undici-0.9.0.tgz", + "integrity": "sha512-lxc3cpUZ28CqbrWcUHxGW/ObDpMOYbuxF/ZOzeFZq54P9uJ2Cpa8gcrC9F716mtuiMaekwk8D6n34vg/JtkkxQ==", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.56.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.7.0" + } + }, + "node_modules/@opentelemetry/redis-common": { + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/redis-common/-/redis-common-0.36.2.tgz", + "integrity": "sha512-faYX1N0gpLhej/6nyp6bgRjzAKXn5GOEMYY7YhciSfCoITAktLUtQ36d24QEWNA1/WA1y6qQunCe0OhHRkVl9g==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/resources": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.30.1.tgz", + "integrity": "sha512-5UxZqiAgLYGFjS4s9qm5mBVo433u+dSPUFWVWXmLAD4wB65oMCoXaJP1KJa9DIYYMeHu3z4BZcStG3LC593cWA==", + "dependencies": { + "@opentelemetry/core": "1.30.1", + "@opentelemetry/semantic-conventions": "1.28.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-base": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.30.1.tgz", + "integrity": "sha512-jVPgBbH1gCy2Lb7X0AVQ8XAfgg0pJ4nvl8/IiQA6nxOsPvS+0zMJaFSs2ltXe0J6C8dqjcnpyqINDJmU30+uOg==", + "dependencies": { + "@opentelemetry/core": "1.30.1", + "@opentelemetry/resources": "1.30.1", + "@opentelemetry/semantic-conventions": "1.28.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/semantic-conventions": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.28.0.tgz", + "integrity": "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/sql-common": { + "version": "0.40.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sql-common/-/sql-common-0.40.1.tgz", + "integrity": "sha512-nSDlnHSqzC3pXn/wZEZVLuAuJ1MYMXPBwtv2qAbCa3847SaHItdE7SzUq/Jtb0KZmh1zfAbNi3AAMjztTT4Ugg==", + "dependencies": { + "@opentelemetry/core": "^1.1.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0" + } + }, + "node_modules/@paralleldrive/cuid2": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.2.2.tgz", + "integrity": "sha512-ZOBkgDwEdoYVlSeRbYYXs0S9MejQofiVYoTbKzy/6GQa39/q5tQU2IX46+shYnUkpEl3wc+J6wRlar7r2EK2xA==", + "dependencies": { + "@noble/hashes": "^1.1.5" + } + }, + "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/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/@prisma/client": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.3.0.tgz", + "integrity": "sha512-BY3Fi28PUSk447Bpv22LhZp4HgNPo7NsEN+EteM1CLDnLjig5863jpW+3c3HHLFmml+nB/eJv1CjSriFZ8z7Cg==", + "hasInstallScript": true, + "engines": { + "node": ">=18.18" + }, + "peerDependencies": { + "prisma": "*", + "typescript": ">=5.1.0" + }, + "peerDependenciesMeta": { + "prisma": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/@prisma/debug": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.3.0.tgz", + "integrity": "sha512-m1lQv//0Rc5RG8TBpNUuLCxC35Ghi5XfpPmL83Gh04/GICHD2J5H2ndMlaljrUNaQDF9dOxIuFAYP1rE9wkXkg==" + }, + "node_modules/@prisma/engines": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.3.0.tgz", + "integrity": "sha512-RXqYhlZb9sx/xkUfYIZuEPn7sT0WgTxNOuEYQ7AGw3IMpP9QGVEDVsluc/GcNkM8NTJszeqk8AplJzI9lm7Jxw==", + "hasInstallScript": true, + "dependencies": { + "@prisma/debug": "6.3.0", + "@prisma/engines-version": "6.3.0-17.acc0b9dd43eb689cbd20c9470515d719db10d0b0", + "@prisma/fetch-engine": "6.3.0", + "@prisma/get-platform": "6.3.0" + } + }, + "node_modules/@prisma/engines-version": { + "version": "6.3.0-17.acc0b9dd43eb689cbd20c9470515d719db10d0b0", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.3.0-17.acc0b9dd43eb689cbd20c9470515d719db10d0b0.tgz", + "integrity": "sha512-R/ZcMuaWZT2UBmgX3Ko6PAV3f8//ZzsjRIG1eKqp3f2rqEqVtCv+mtzuH2rBPUC9ujJ5kCb9wwpxeyCkLcHVyA==" + }, + "node_modules/@prisma/fetch-engine": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.3.0.tgz", + "integrity": "sha512-GBy0iT4f1mH31ePzfcpVSUa7JLRTeq4914FG2vR3LqDwRweSm4ja1o5flGDz+eVIa/BNYfkBvRRxv4D6ve6Eew==", + "dependencies": { + "@prisma/debug": "6.3.0", + "@prisma/engines-version": "6.3.0-17.acc0b9dd43eb689cbd20c9470515d719db10d0b0", + "@prisma/get-platform": "6.3.0" + } + }, + "node_modules/@prisma/get-platform": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.3.0.tgz", + "integrity": "sha512-V8zZ1d0xfyi6FjpNP4AcYuwSpGcdmu35OXWnTPm8IW594PYALzKXHwIa9+o0f+Lo9AecFWrwrwaoYe56UNfTtQ==", + "dependencies": { + "@prisma/debug": "6.3.0" + } + }, + "node_modules/@prisma/instrumentation": { + "version": "5.22.0", + "resolved": "https://registry.npmjs.org/@prisma/instrumentation/-/instrumentation-5.22.0.tgz", + "integrity": "sha512-LxccF392NN37ISGxIurUljZSh1YWnphO34V5a0+T7FVQG2u9bhAXRTJpgmQ3483woVhkraQZFF7cbRrpbw/F4Q==", + "dependencies": { + "@opentelemetry/api": "^1.8", + "@opentelemetry/instrumentation": "^0.49 || ^0.50 || ^0.51 || ^0.52.0 || ^0.53.0", + "@opentelemetry/sdk-trace-base": "^1.22" + } + }, + "node_modules/@prisma/instrumentation/node_modules/@opentelemetry/api-logs": { + "version": "0.53.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.53.0.tgz", + "integrity": "sha512-8HArjKx+RaAI8uEIgcORbZIPklyh1YLjPSBus8hjRmvLi6DeFzgOcdZ7KwPabKj8mXF8dX0hyfAyGfycz0DbFw==", + "dependencies": { + "@opentelemetry/api": "^1.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@prisma/instrumentation/node_modules/@opentelemetry/instrumentation": { + "version": "0.53.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.53.0.tgz", + "integrity": "sha512-DMwg0hy4wzf7K73JJtl95m/e0boSoWhH07rfvHvYzQtBD3Bmv0Wc1x733vyZBqmFm8OjJD0/pfiUg1W3JjFX0A==", + "dependencies": { + "@opentelemetry/api-logs": "0.53.0", + "@types/shimmer": "^1.2.0", + "import-in-the-middle": "^1.8.1", + "require-in-the-middle": "^7.1.1", + "semver": "^7.5.2", + "shimmer": "^1.2.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "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/@redis/bloom": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz", + "integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@redis/client": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.6.0.tgz", + "integrity": "sha512-aR0uffYI700OEEH4gYnitAnv3vzVGXCFvYfdpu/CJKvk4pHfLPEy/JSZyrpQ+15WhXe1yJRXLtfQ84s4mEXnPg==", + "dependencies": { + "cluster-key-slot": "1.1.2", + "generic-pool": "3.9.0", + "yallist": "4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@redis/graph": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.1.tgz", + "integrity": "sha512-FEMTcTHZozZciLRl6GiiIB4zGm5z5F3F6a6FZCyrfxdKOhFlGkiAqlexWMBzCi4DcRoyiOsuLfW+cjlGWyExOw==", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@redis/json": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.7.tgz", + "integrity": "sha512-6UyXfjVaTBTJtKNG4/9Z8PSpKE6XgSyEb8iwaqDcy+uKrd/DGYHTWkUdnQDyzm727V7p21WUMhsqz5oy65kPcQ==", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@redis/search": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.2.0.tgz", + "integrity": "sha512-tYoDBbtqOVigEDMAcTGsRlMycIIjwMCgD8eR2t0NANeQmgK/lvxNAvYyb6bZDD4frHRhIHkJu2TBRvB0ERkOmw==", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@redis/time-series": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.1.0.tgz", + "integrity": "sha512-c1Q99M5ljsIuc4YdaCwfUEXsofakb9c8+Zse2qxTadu8TalLXuAESzLvFAvNVbkmSlvlzIQOLpBCmWI9wTOt+g==", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.32.1.tgz", + "integrity": "sha512-/pqA4DmqyCm8u5YIDzIdlLcEmuvxb0v8fZdFhVMszSpDTgbQKdw3/mB3eMUHIbubtJ6F9j+LtmyCnHTEqIHyzA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.32.1.tgz", + "integrity": "sha512-If3PDskT77q7zgqVqYuj7WG3WC08G1kwXGVFi9Jr8nY6eHucREHkfpX79c0ACAjLj3QIWKPJR7w4i+f5EdLH5Q==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.32.1.tgz", + "integrity": "sha512-zCpKHioQ9KgZToFp5Wvz6zaWbMzYQ2LJHQ+QixDKq52KKrF65ueu6Af4hLlLWHjX1Wf/0G5kSJM9PySW9IrvHA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.32.1.tgz", + "integrity": "sha512-sFvF+t2+TyUo/ZQqUcifrJIgznx58oFZbdHS9TvHq3xhPVL9nOp+yZ6LKrO9GWTP+6DbFtoyLDbjTpR62Mbr3Q==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.32.1.tgz", + "integrity": "sha512-NbOa+7InvMWRcY9RG+B6kKIMD/FsnQPH0MWUvDlQB1iXnF/UcKSudCXZtv4lW+C276g3w5AxPbfry5rSYvyeYA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.32.1.tgz", + "integrity": "sha512-JRBRmwvHPXR881j2xjry8HZ86wIPK2CcDw0EXchE1UgU0ubWp9nvlT7cZYKc6bkypBt745b4bglf3+xJ7hXWWw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.32.1.tgz", + "integrity": "sha512-PKvszb+9o/vVdUzCCjL0sKHukEQV39tD3fepXxYrHE3sTKrRdCydI7uldRLbjLmDA3TFDmh418XH19NOsDRH8g==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.32.1.tgz", + "integrity": "sha512-9WHEMV6Y89eL606ReYowXuGF1Yb2vwfKWKdD1A5h+OYnPZSJvxbEjxTRKPgi7tkP2DSnW0YLab1ooy+i/FQp/Q==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.32.1.tgz", + "integrity": "sha512-tZWc9iEt5fGJ1CL2LRPw8OttkCBDs+D8D3oEM8mH8S1ICZCtFJhD7DZ3XMGM8kpqHvhGUTvNUYVDnmkj4BDXnw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.32.1.tgz", + "integrity": "sha512-FTYc2YoTWUsBz5GTTgGkRYYJ5NGJIi/rCY4oK/I8aKowx1ToXeoVVbIE4LGAjsauvlhjfl0MYacxClLld1VrOw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.32.1.tgz", + "integrity": "sha512-F51qLdOtpS6P1zJVRzYM0v6MrBNypyPEN1GfMiz0gPu9jN8ScGaEFIZQwteSsGKg799oR5EaP7+B2jHgL+d+Kw==", + "cpu": [ + "loong64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.32.1.tgz", + "integrity": "sha512-wO0WkfSppfX4YFm5KhdCCpnpGbtgQNj/tgvYzrVYFKDpven8w2N6Gg5nB6w+wAMO3AIfSTWeTjfVe+uZ23zAlg==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.32.1.tgz", + "integrity": "sha512-iWswS9cIXfJO1MFYtI/4jjlrGb/V58oMu4dYJIKnR5UIwbkzR0PJ09O0PDZT0oJ3LYWXBSWahNf/Mjo6i1E5/g==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.32.1.tgz", + "integrity": "sha512-RKt8NI9tebzmEthMnfVgG3i/XeECkMPS+ibVZjZ6mNekpbbUmkNWuIN2yHsb/mBPyZke4nlI4YqIdFPgKuoyQQ==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.32.1.tgz", + "integrity": "sha512-WQFLZ9c42ECqEjwg/GHHsouij3pzLXkFdz0UxHa/0OM12LzvX7DzedlY0SIEly2v18YZLRhCRoHZDxbBSWoGYg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.32.1.tgz", + "integrity": "sha512-BLoiyHDOWoS3uccNSADMza6V6vCNiphi94tQlVIL5de+r6r/CCQuNnerf+1g2mnk2b6edp5dk0nhdZ7aEjOBsA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.32.1.tgz", + "integrity": "sha512-w2l3UnlgYTNNU+Z6wOR8YdaioqfEnwPjIsJ66KxKAf0p+AuL2FHeTX6qvM+p/Ue3XPBVNyVSfCrfZiQh7vZHLQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.32.1.tgz", + "integrity": "sha512-Am9H+TGLomPGkBnaPWie4F3x+yQ2rr4Bk2jpwy+iV+Gel9jLAu/KqT8k3X4jxFPW6Zf8OMnehyutsd+eHoq1WQ==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.32.1.tgz", + "integrity": "sha512-ar80GhdZb4DgmW3myIS9nRFYcpJRSME8iqWgzH2i44u+IdrzmiXVxeFnExQ5v4JYUSpg94bWjevMG8JHf1Da5Q==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", + "dev": true + }, + "node_modules/@sentry/core": { + "version": "8.52.1", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-8.52.1.tgz", + "integrity": "sha512-FG0P9I03xk4jBI4O7NBkw8uqLGH9/RWOSFoRH3eYvUTyBLhkk9IaCFbAAGBNZhojky8T7gqYwnuRbFNlrAiuSA==", + "engines": { + "node": ">=14.18" + } + }, + "node_modules/@sentry/node": { + "version": "8.52.1", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-8.52.1.tgz", + "integrity": "sha512-we9fIfn5Q0c6U4VPrXhNtJ7uz5HkTlnOQV7hP/GG09tmKa6hrL20tkhCosObl3XZ/qlIbD/GQMv4WmhOgNzgkQ==", + "dependencies": { + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/context-async-hooks": "^1.29.0", + "@opentelemetry/core": "^1.29.0", + "@opentelemetry/instrumentation": "^0.56.0", + "@opentelemetry/instrumentation-amqplib": "^0.45.0", + "@opentelemetry/instrumentation-connect": "0.42.0", + "@opentelemetry/instrumentation-dataloader": "0.15.0", + "@opentelemetry/instrumentation-express": "0.46.0", + "@opentelemetry/instrumentation-fastify": "0.43.0", + "@opentelemetry/instrumentation-fs": "0.18.0", + "@opentelemetry/instrumentation-generic-pool": "0.42.0", + "@opentelemetry/instrumentation-graphql": "0.46.0", + "@opentelemetry/instrumentation-hapi": "0.44.0", + "@opentelemetry/instrumentation-http": "0.56.0", + "@opentelemetry/instrumentation-ioredis": "0.46.0", + "@opentelemetry/instrumentation-kafkajs": "0.6.0", + "@opentelemetry/instrumentation-knex": "0.43.0", + "@opentelemetry/instrumentation-koa": "0.46.0", + "@opentelemetry/instrumentation-lru-memoizer": "0.43.0", + "@opentelemetry/instrumentation-mongodb": "0.50.0", + "@opentelemetry/instrumentation-mongoose": "0.45.0", + "@opentelemetry/instrumentation-mysql": "0.44.0", + "@opentelemetry/instrumentation-mysql2": "0.44.0", + "@opentelemetry/instrumentation-nestjs-core": "0.43.0", + "@opentelemetry/instrumentation-pg": "0.49.0", + "@opentelemetry/instrumentation-redis-4": "0.45.0", + "@opentelemetry/instrumentation-tedious": "0.17.0", + "@opentelemetry/instrumentation-undici": "0.9.0", + "@opentelemetry/resources": "^1.29.0", + "@opentelemetry/sdk-trace-base": "^1.29.0", + "@opentelemetry/semantic-conventions": "^1.28.0", + "@prisma/instrumentation": "5.22.0", + "@sentry/core": "8.52.1", + "@sentry/opentelemetry": "8.52.1", + "import-in-the-middle": "^1.11.2" + }, + "engines": { + "node": ">=14.18" + } + }, + "node_modules/@sentry/opentelemetry": { + "version": "8.52.1", + "resolved": "https://registry.npmjs.org/@sentry/opentelemetry/-/opentelemetry-8.52.1.tgz", + "integrity": "sha512-xaGm/KlfFi3yxK6PP+IRLnvfnd8Hp3yvJIdp3Mvc2aHW1Dh7zz+VTNNmWFZQmAbWrNqIoqZG2s1tZOeJwMHPpg==", + "dependencies": { + "@sentry/core": "8.52.1" + }, + "engines": { + "node": ">=14.18" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/core": "^1.29.0", + "@opentelemetry/instrumentation": "^0.56.0", + "@opentelemetry/sdk-trace-base": "^1.29.0", + "@opentelemetry/semantic-conventions": "^1.28.0" + } + }, + "node_modules/@smithy/abort-controller": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.1.tgz", + "integrity": "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/config-resolver": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.0.1.tgz", + "integrity": "sha512-Igfg8lKu3dRVkTSEm98QpZUvKEOa71jDX4vKRcvJVyRc3UgN3j7vFMf0s7xLQhYmKa8kyJGQgUJDOV5V3neVlQ==", + "dependencies": { + "@smithy/node-config-provider": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-config-provider": "^4.0.0", + "@smithy/util-middleware": "^4.0.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/core": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.1.2.tgz", + "integrity": "sha512-htwQXkbdF13uwwDevz9BEzL5ABK+1sJpVQXywwGSH973AVOvisHNfpcB8A8761G6XgHoS2kHPqc9DqHJ2gp+/Q==", + "dependencies": { + "@smithy/middleware-serde": "^4.0.2", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-stream": "^4.0.2", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/credential-provider-imds": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.0.1.tgz", + "integrity": "sha512-l/qdInaDq1Zpznpmev/+52QomsJNZ3JkTl5yrTl02V6NBgJOQ4LY0SFw/8zsMwj3tLe8vqiIuwF6nxaEwgf6mg==", + "dependencies": { + "@smithy/node-config-provider": "^4.0.1", + "@smithy/property-provider": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/fetch-http-handler": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.0.1.tgz", + "integrity": "sha512-3aS+fP28urrMW2KTjb6z9iFow6jO8n3MFfineGbndvzGZit3taZhKWtTorf+Gp5RpFDDafeHlhfsGlDCXvUnJA==", + "dependencies": { + "@smithy/protocol-http": "^5.0.1", + "@smithy/querystring-builder": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-base64": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/hash-node": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.0.1.tgz", + "integrity": "sha512-TJ6oZS+3r2Xu4emVse1YPB3Dq3d8RkZDKcPr71Nj/lJsdAP1c7oFzYqEn1IBc915TsgLl2xIJNuxCz+gLbLE0w==", + "dependencies": { + "@smithy/types": "^4.1.0", + "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/invalid-dependency": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.0.1.tgz", + "integrity": "sha512-gdudFPf4QRQ5pzj7HEnu6FhKRi61BfH/Gk5Yf6O0KiSbr1LlVhgjThcvjdu658VE6Nve8vaIWB8/fodmS1rBPQ==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/is-array-buffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.0.0.tgz", + "integrity": "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/md5-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/md5-js/-/md5-js-4.0.1.tgz", + "integrity": "sha512-HLZ647L27APi6zXkZlzSFZIjpo8po45YiyjMGJZM3gyDY8n7dPGdmxIIljLm4gPt/7rRvutLTTkYJpZVfG5r+A==", + "dependencies": { + "@smithy/types": "^4.1.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-content-length": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.0.1.tgz", + "integrity": "sha512-OGXo7w5EkB5pPiac7KNzVtfCW2vKBTZNuCctn++TTSOMpe6RZO/n6WEC1AxJINn3+vWLKW49uad3lo/u0WJ9oQ==", + "dependencies": { + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-endpoint": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.0.3.tgz", + "integrity": "sha512-YdbmWhQF5kIxZjWqPIgboVfi8i5XgiYMM7GGKFMTvBei4XjNQfNv8sukT50ITvgnWKKKpOtp0C0h7qixLgb77Q==", + "dependencies": { + "@smithy/core": "^3.1.2", + "@smithy/middleware-serde": "^4.0.2", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-middleware": "^4.0.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-retry": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.0.4.tgz", + "integrity": "sha512-wmxyUBGHaYUqul0wZiset4M39SMtDBOtUr2KpDuftKNN74Do9Y36Go6Eqzj9tL0mIPpr31ulB5UUtxcsCeGXsQ==", + "dependencies": { + "@smithy/node-config-provider": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/service-error-classification": "^4.0.1", + "@smithy/smithy-client": "^4.1.3", + "@smithy/types": "^4.1.0", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-retry": "^4.0.1", + "tslib": "^2.6.2", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-serde": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.0.2.tgz", + "integrity": "sha512-Sdr5lOagCn5tt+zKsaW+U2/iwr6bI9p08wOkCp6/eL6iMbgdtc2R5Ety66rf87PeohR0ExI84Txz9GYv5ou3iQ==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-stack": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.0.1.tgz", + "integrity": "sha512-dHwDmrtR/ln8UTHpaIavRSzeIk5+YZTBtLnKwDW3G2t6nAupCiQUvNzNoHBpik63fwUaJPtlnMzXbQrNFWssIA==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/node-config-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.0.1.tgz", + "integrity": "sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ==", + "dependencies": { + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/node-http-handler": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.0.2.tgz", + "integrity": "sha512-X66H9aah9hisLLSnGuzRYba6vckuFtGE+a5DcHLliI/YlqKrGoxhisD5XbX44KyoeRzoNlGr94eTsMVHFAzPOw==", + "dependencies": { + "@smithy/abort-controller": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/querystring-builder": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/property-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.1.tgz", + "integrity": "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/protocol-http": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.0.1.tgz", + "integrity": "sha512-TE4cpj49jJNB/oHyh/cRVEgNZaoPaxd4vteJNB0yGidOCVR0jCw/hjPVsT8Q8FRmj8Bd3bFZt8Dh7xGCT+xMBQ==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/querystring-builder": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.0.1.tgz", + "integrity": "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg==", + "dependencies": { + "@smithy/types": "^4.1.0", + "@smithy/util-uri-escape": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/querystring-parser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.0.1.tgz", + "integrity": "sha512-Ma2XC7VS9aV77+clSFylVUnPZRindhB7BbmYiNOdr+CHt/kZNJoPP0cd3QxCnCFyPXC4eybmyE98phEHkqZ5Jw==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/service-error-classification": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.0.1.tgz", + "integrity": "sha512-3JNjBfOWpj/mYfjXJHB4Txc/7E4LVq32bwzE7m28GN79+M1f76XHflUaSUkhOriprPDzev9cX/M+dEB80DNDKA==", + "dependencies": { + "@smithy/types": "^4.1.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/shared-ini-file-loader": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.1.tgz", + "integrity": "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/signature-v4": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.0.1.tgz", + "integrity": "sha512-nCe6fQ+ppm1bQuw5iKoeJ0MJfz2os7Ic3GBjOkLOPtavbD1ONoyE3ygjBfz2ythFWm4YnRm6OxW+8p/m9uCoIA==", + "dependencies": { + "@smithy/is-array-buffer": "^4.0.0", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-hex-encoding": "^4.0.0", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-uri-escape": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/smithy-client": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.1.3.tgz", + "integrity": "sha512-A2Hz85pu8BJJaYFdX8yb1yocqigyqBzn+OVaVgm+Kwi/DkN8vhN2kbDVEfADo6jXf5hPKquMLGA3UINA64UZ7A==", + "dependencies": { + "@smithy/core": "^3.1.2", + "@smithy/middleware-endpoint": "^4.0.3", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-stream": "^4.0.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/url-parser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.0.1.tgz", + "integrity": "sha512-gPXcIEUtw7VlK8f/QcruNXm7q+T5hhvGu9tl63LsJPZ27exB6dtNwvh2HIi0v7JcXJ5emBxB+CJxwaLEdJfA+g==", + "dependencies": { + "@smithy/querystring-parser": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-base64": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-4.0.0.tgz", + "integrity": "sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg==", + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-body-length-browser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-4.0.0.tgz", + "integrity": "sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-body-length-node": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-4.0.0.tgz", + "integrity": "sha512-q0iDP3VsZzqJyje8xJWEJCNIu3lktUGVoSy1KB0UWym2CL1siV3artm+u1DFYTLejpsrdGyCSWBdGNjJzfDPjg==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-buffer-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.0.0.tgz", + "integrity": "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug==", + "dependencies": { + "@smithy/is-array-buffer": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-config-provider": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-4.0.0.tgz", + "integrity": "sha512-L1RBVzLyfE8OXH+1hsJ8p+acNUSirQnWQ6/EgpchV88G6zGBTDPdXiiExei6Z1wR2RxYvxY/XLw6AMNCCt8H3w==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.0.4.tgz", + "integrity": "sha512-Ej1bV5sbrIfH++KnWxjjzFNq9nyP3RIUq2c9Iqq7SmMO/idUR24sqvKH2LUQFTSPy/K7G4sB2m8n7YYlEAfZaw==", + "dependencies": { + "@smithy/property-provider": "^4.0.1", + "@smithy/smithy-client": "^4.1.3", + "@smithy/types": "^4.1.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.0.4.tgz", + "integrity": "sha512-HE1I7gxa6yP7ZgXPCFfZSDmVmMtY7SHqzFF55gM/GPegzZKaQWZZ+nYn9C2Cc3JltCMyWe63VPR3tSFDEvuGjw==", + "dependencies": { + "@smithy/config-resolver": "^4.0.1", + "@smithy/credential-provider-imds": "^4.0.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/property-provider": "^4.0.1", + "@smithy/smithy-client": "^4.1.3", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-endpoints": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.0.1.tgz", + "integrity": "sha512-zVdUENQpdtn9jbpD9SCFK4+aSiavRb9BxEtw9ZGUR1TYo6bBHbIoi7VkrFQ0/RwZlzx0wRBaRmPclj8iAoJCLA==", + "dependencies": { + "@smithy/node-config-provider": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-hex-encoding": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.0.0.tgz", + "integrity": "sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-middleware": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.0.1.tgz", + "integrity": "sha512-HiLAvlcqhbzhuiOa0Lyct5IIlyIz0PQO5dnMlmQ/ubYM46dPInB+3yQGkfxsk6Q24Y0n3/JmcA1v5iEhmOF5mA==", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-retry": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.0.1.tgz", + "integrity": "sha512-WmRHqNVwn3kI3rKk1LsKcVgPBG6iLTBGC1iYOV3GQegwJ3E8yjzHytPt26VNzOWr1qu0xE03nK0Ug8S7T7oufw==", + "dependencies": { + "@smithy/service-error-classification": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-stream": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.0.2.tgz", + "integrity": "sha512-0eZ4G5fRzIoewtHtwaYyl8g2C+osYOT4KClXgfdNEDAgkbe2TYPqcnw4GAWabqkZCax2ihRGPe9LZnsPdIUIHA==", + "dependencies": { + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/node-http-handler": "^4.0.2", + "@smithy/types": "^4.1.0", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-hex-encoding": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-uri-escape": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-4.0.0.tgz", + "integrity": "sha512-77yfbCbQMtgtTylO9itEAdpPXSog3ZxMe09AEhm0dU0NLTalV70ghDZFR+Nfi1C60jnJoh/Re4090/DuZh2Omg==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-utf8": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.0.0.tgz", + "integrity": "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==", + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==" + }, + "node_modules/@thi.ng/bitstream": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/@thi.ng/bitstream/-/bitstream-2.4.11.tgz", + "integrity": "sha512-7tXBVXQiJqVSVZLljnonXZOT9Zn6r7bc9X1GntDnNU/U8kW5DjAQmz0GvJxaIxRpZ+KqU1BvQVCfv3rH6f+TtA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/postspectacular" + }, + { + "type": "patreon", + "url": "https://patreon.com/thing_umbrella" + }, + { + "type": "liberapay", + "url": "https://liberapay.com/thi.ng" + } + ], + "dependencies": { + "@thi.ng/errors": "^2.5.25" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@thi.ng/errors": { + "version": "2.5.25", + "resolved": "https://registry.npmjs.org/@thi.ng/errors/-/errors-2.5.25.tgz", + "integrity": "sha512-PmK56hWGvRWr9Eq0V5xkV4tQvhjPtfvv6urFONP/D0gwFQXj+v6rcDYkAFLzOkbLqa0DYtkgvUsMklF/L53upA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/postspectacular" + }, + { + "type": "patreon", + "url": "https://patreon.com/thing_umbrella" + }, + { + "type": "liberapay", + "url": "https://liberapay.com/thi.ng" + } + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@tokenizer/token": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", + "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==" + }, + "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==", + "dev": true + }, + "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==", + "dev": true + }, + "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==", + "dev": true + }, + "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==", + "dev": true + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/compression": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@types/compression/-/compression-1.7.5.tgz", + "integrity": "sha512-AAQvK5pxMpaT+nDvhHrsBhLSYG5yQdtkaJE1WYieSNY2mVFKAgmU4ks65rkZD5oqnGCFLyQpUr1CqI4DmUMyDg==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.36", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.36.tgz", + "integrity": "sha512-P63Zd/JUGq+PdrM1lv0Wv5SBYeA2+CORvbrXbngriYY0jzLUWfQMQQxOhjONEz/wlHOAxOdY7CY65rgQdTjq2w==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cors": { + "version": "2.8.17", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", + "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==" + }, + "node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz", + "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "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/long": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", + "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" + }, + "node_modules/@types/mime": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-4.0.0.tgz", + "integrity": "sha512-5eEkJZ/BLvTE3vXGKkWlyTSUVZuzj23Wj8PoyOq2lt5I3CYbiLBOPb3XmCW6QcuOibIUE6emHXHt9E/F/rCa6w==", + "deprecated": "This is a stub types definition. mime provides its own type definitions, so you do not need this installed.", + "dev": true, + "dependencies": { + "mime": "*" + } + }, + "node_modules/@types/mime-types": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@types/mime-types/-/mime-types-2.1.4.tgz", + "integrity": "sha512-lfU4b34HOri+kAY5UheuFMWPDOI+OPceBSHZKp69gEyTL/mmJ4cnU6Y/rlme3UL3GyOn6Y42hyIEw0/q8sWx5w==", + "dev": true + }, + "node_modules/@types/mysql": { + "version": "2.15.26", + "resolved": "https://registry.npmjs.org/@types/mysql/-/mysql-2.15.26.tgz", + "integrity": "sha512-DSLCOXhkvfS5WNNPbfn2KdICAmk8lLc+/PNvnPnF7gOdMZCxopXduqv0OQ13y/yA/zXTSikZZqVgybUxOEg6YQ==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "22.12.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.12.0.tgz", + "integrity": "sha512-Fll2FZ1riMjNmlmJOdAyY5pUbkftXslB5DgEzlIuNaiWhXd00FhWxVC/r4yV/4wBb9JfImTu+jiSvXTkJ7F/gA==", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "node_modules/@types/node-cron": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@types/node-cron/-/node-cron-3.0.11.tgz", + "integrity": "sha512-0ikrnug3/IyneSHqCBeslAhlK2aBfYek1fGo4bP4QnZPmiqSGRK+Oy7ZMisLWkesffJvQ1cqAcBnJC+8+nxIAg==", + "dev": true + }, + "node_modules/@types/node-fetch": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.12.tgz", + "integrity": "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==", + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.0" + } + }, + "node_modules/@types/pg": { + "version": "8.6.1", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.6.1.tgz", + "integrity": "sha512-1Kc4oAGzAl7uqUStZCDvaLFqZrW9qWSjXOmBfdgyBP5La7Us6Mg4GBvRlSoaZMhQF/zSj1C8CtKMBkoiT8eL8w==", + "dependencies": { + "@types/node": "*", + "pg-protocol": "*", + "pg-types": "^2.2.0" + } + }, + "node_modules/@types/pg-pool": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/pg-pool/-/pg-pool-2.0.6.tgz", + "integrity": "sha512-TaAUE5rq2VQYxab5Ts7WZhKNmuN78Q6PiFonTDdpbx8a1H0M1vhy3rhiMjl+e2iHmogyMw7jZF4FrE6eJUy5HQ==", + "dependencies": { + "@types/pg": "*" + } + }, + "node_modules/@types/qrcode": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@types/qrcode/-/qrcode-1.5.5.tgz", + "integrity": "sha512-CdfBi/e3Qk+3Z/fXYShipBT13OJ2fDO2Q2w5CIP5anLTLIndQG9z6P1cnm+8zCWSpm5dnxMFd/uREtb0EXuQzg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/qrcode-terminal": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/qrcode-terminal/-/qrcode-terminal-0.12.2.tgz", + "integrity": "sha512-v+RcIEJ+Uhd6ygSQ0u5YYY7ZM+la7GgPbs0V/7l/kFs2uO4S8BcIUEMoP7za4DNIqNnUD5npf0A/7kBhrCKG5Q==", + "dev": true + }, + "node_modules/@types/qs": { + "version": "6.9.18", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.18.tgz", + "integrity": "sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true + }, + "node_modules/@types/semver": { + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", + "dev": true + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/send/node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true + }, + "node_modules/@types/serve-static": { + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "dev": true, + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@types/shimmer": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@types/shimmer/-/shimmer-1.2.0.tgz", + "integrity": "sha512-UE7oxhQLLd9gub6JKIAhDq06T0F6FnztwMNRvYgjeQSBeMc1ZG/tA47EwfduvkuQS8apbkM/lpLpWsaCeYsXVg==" + }, + "node_modules/@types/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ==", + "dev": true + }, + "node_modules/@types/strip-json-comments": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz", + "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==", + "dev": true + }, + "node_modules/@types/tedious": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/@types/tedious/-/tedious-4.0.14.tgz", + "integrity": "sha512-KHPsfX/FoVbUGbyYvk1q9MMQHLPeRZhRJZdO45Q4YjvFkv4hMNghCWTvy7rdKessBsmtz4euWCWAB6/tVpI1Iw==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==", + "dev": true + }, + "node_modules/@types/validator": { + "version": "13.12.2", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.12.2.tgz", + "integrity": "sha512-6SlHBzUW8Jhf3liqrGGXyTJSIFe4nqlJ5A5KaMZ2l/vbM3Wh3KSybots/wfWVzNLK4D1NZluDlSQIbIEPx6oyA==" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", + "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/type-utils": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "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" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", + "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", + "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", + "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", + "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", + "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": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", + "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.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/utils": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", + "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", + "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.21.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.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==" + }, + "node_modules/@wasm-audio-decoders/common": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/@wasm-audio-decoders/common/-/common-9.0.5.tgz", + "integrity": "sha512-b9JNh9sPAvn8PVIizNh9D60WkfQong/u9ea873H47u7zvVDLctxYIp2aZw9CQqXaQdk7JB3MoU5UHiseO40swg==", + "dependencies": { + "@eshaz/web-worker": "1.2.2", + "simple-yenc": "^1.0.4" + } + }, + "node_modules/@wasm-audio-decoders/flac": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@wasm-audio-decoders/flac/-/flac-0.2.5.tgz", + "integrity": "sha512-8M//CgB3PlkWwn47KcwD0tO6DZBA7/AGG0ukHSG0G97UbNEUNINvKDWAKPVWznzHsqeBP6axw+K/38dzng64JA==", + "dependencies": { + "@wasm-audio-decoders/common": "9.0.5", + "codec-parser": "2.5.0" + }, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/eshaz" + } + }, + "node_modules/@wasm-audio-decoders/ogg-vorbis": { + "version": "0.1.16", + "resolved": "https://registry.npmjs.org/@wasm-audio-decoders/ogg-vorbis/-/ogg-vorbis-0.1.16.tgz", + "integrity": "sha512-HcEx4LPZbbzjhs9bTXgMaXLVCSMSo/egY9paJxAnE9tsYbvseAaGtVddLYktl3Qi/G+nW/ZzUXg4144izJjqCw==", + "dependencies": { + "@wasm-audio-decoders/common": "9.0.5", + "codec-parser": "2.5.0" + }, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/eshaz" + } + }, + "node_modules/@whiskeysockets/eslint-config": { + "version": "1.0.0", + "resolved": "git+ssh://git@github.com/whiskeysockets/eslint-config.git#326b55f2842668f4e11f471451c4e39819a0e1bf", + "dependencies": { + "@typescript-eslint/eslint-plugin": "^7.15.0", + "@typescript-eslint/parser": "^7.15.0", + "eslint-plugin-simple-import-sort": "^12.1.1" + }, + "peerDependencies": { + "eslint": "*", + "typescript": ">=4" + } + }, + "node_modules/@whiskeysockets/eslint-config/node_modules/@typescript-eslint/eslint-plugin": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz", + "integrity": "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/type-utils": "7.18.0", + "@typescript-eslint/utils": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@whiskeysockets/eslint-config/node_modules/@typescript-eslint/parser": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz", + "integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==", + "dependencies": { + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@whiskeysockets/eslint-config/node_modules/@typescript-eslint/scope-manager": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", + "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@whiskeysockets/eslint-config/node_modules/@typescript-eslint/type-utils": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz", + "integrity": "sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==", + "dependencies": { + "@typescript-eslint/typescript-estree": "7.18.0", + "@typescript-eslint/utils": "7.18.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@whiskeysockets/eslint-config/node_modules/@typescript-eslint/types": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", + "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@whiskeysockets/eslint-config/node_modules/@typescript-eslint/typescript-estree": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", + "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@whiskeysockets/eslint-config/node_modules/@typescript-eslint/utils": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", + "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/@whiskeysockets/eslint-config/node_modules/@typescript-eslint/visitor-keys": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", + "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@whiskeysockets/eslint-config/node_modules/eslint-plugin-simple-import-sort": { + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-12.1.1.tgz", + "integrity": "sha512-6nuzu4xwQtE3332Uz0to+TxDQYRLTKRESSc2hefVT48Zc8JthmN23Gx9lnYhu0FtkRSL1oxny3kJ2aveVhmOVA==", + "peerDependencies": { + "eslint": ">=5.0.0" + } + }, + "node_modules/@whiskeysockets/eslint-config/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/@zxing/text-encoding": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@zxing/text-encoding/-/text-encoding-0.9.0.tgz", + "integrity": "sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==", + "optional": true + }, + "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/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/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==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "peerDependencies": { + "acorn": "^8" + } + }, + "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==", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", + "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", + "engines": { + "node": ">= 14" + } + }, + "node_modules/agentkeepalive": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", + "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "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/amqplib": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/amqplib/-/amqplib-0.10.5.tgz", + "integrity": "sha512-Dx5zmy0Ur+Q7LPPdhz+jx5IzmJBoHd15tOeAfQ8SuvEtyPJ20hBemhOBA4b1WeORCRa0ENM/kHCzmem1w/zHvQ==", + "dependencies": { + "@acuminous/bitsyntax": "^0.1.2", + "buffer-more-ints": "~1.0.0", + "url-parse": "~1.5.10" + }, + "engines": { + "node": ">=10" + } + }, + "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": "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/any-base": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/any-base/-/any-base-1.1.0.tgz", + "integrity": "sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg==" + }, + "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==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==" + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "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==" + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "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==", + "engines": { + "node": ">=8" + } + }, + "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.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", + "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/async-lock": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/async-lock/-/async-lock-1.4.1.tgz", + "integrity": "sha512-Az2ZTpuytrtqENulXwO3GGv1Bztugx6TT37NIo7imr/Qo0gsYiGtSdBa2B6fsXhTpVZDNfu1Qn3pk531e3q+nQ==" + }, + "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/atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/audio-buffer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/audio-buffer/-/audio-buffer-5.0.0.tgz", + "integrity": "sha512-gsDyj1wwUp8u7NBB+eW6yhLb9ICf+0eBmDX8NGaAS00w8/fLqFdxUlL5Ge/U8kB64DlQhdonxYC59dXy1J7H/w==" + }, + "node_modules/audio-decode": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/audio-decode/-/audio-decode-2.2.2.tgz", + "integrity": "sha512-xyh7z6dpRT+5Ez4ggV2cEkSShkDvvIBBmVPR3kYY7uIBqRO1BGNjofip6JnjBnvezhrU3ypBGZjepyKFDZWnDw==", + "dependencies": { + "@wasm-audio-decoders/flac": "^0.2.4", + "@wasm-audio-decoders/ogg-vorbis": "^0.1.15", + "audio-buffer": "^5.0.0", + "audio-type": "^2.2.1", + "mpg123-decoder": "^1.0.0", + "node-wav": "^0.0.2", + "ogg-opus-decoder": "^1.6.12", + "qoa-format": "^1.0.1" + } + }, + "node_modules/audio-type": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/audio-type/-/audio-type-2.2.1.tgz", + "integrity": "sha512-En9AY6EG1qYqEy5L/quryzbA4akBpJrnBZNxeKTqGHC2xT9Qc4aZ8b7CcbOMFTTc/MGdoNyp+SN4zInZNKxMYA==", + "engines": { + "node": ">=14" + } + }, + "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==", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axios": { + "version": "1.7.9", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", + "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/b4a": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz", + "integrity": "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==" + }, + "node_modules/baileys": { + "version": "6.7.12", + "resolved": "git+ssh://git@github.com/EvolutionAPI/Baileys.git#2c69f65d4b6c4e779d6e3d2c0c32689a5425df95", + "dependencies": { + "@adiwajshing/keyed-db": "^0.2.4", + "@hapi/boom": "^9.1.3", + "@whiskeysockets/eslint-config": "github:whiskeysockets/eslint-config", + "async-lock": "^1.4.1", + "audio-decode": "^2.1.3", + "axios": "^1.6.0", + "cache-manager": "^5.7.6", + "futoin-hkdf": "^1.5.1", + "libphonenumber-js": "^1.10.20", + "libsignal": "github:WhiskeySockets/libsignal-node", + "lodash": "^4.17.21", + "music-metadata": "^7.12.3", + "node-cache": "^5.1.2", + "pino": "^7.0.0", + "protobufjs": "^7.2.4", + "uuid": "^10.0.0", + "ws": "^8.13.0" + }, + "peerDependencies": { + "jimp": "^0.16.1", + "link-preview-js": "^3.0.0", + "qrcode-terminal": "^0.12.0", + "sharp": "^0.32.6" + }, + "peerDependenciesMeta": { + "jimp": { + "optional": true + }, + "link-preview-js": { + "optional": true + }, + "qrcode-terminal": { + "optional": true + }, + "sharp": { + "optional": true + } + } + }, + "node_modules/baileys/node_modules/@hapi/boom": { + "version": "9.1.4", + "resolved": "https://registry.npmjs.org/@hapi/boom/-/boom-9.1.4.tgz", + "integrity": "sha512-Ls1oH8jaN1vNsqcaHVYJrKmgMcKsC1wcp8bujvXrHaAqD2iDYq3HoOwsxwo09Cuda5R5nC0o0IxlrlTuvPuzSw==", + "dependencies": { + "@hapi/hoek": "9.x.x" + } + }, + "node_modules/baileys/node_modules/@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==" + }, + "node_modules/baileys/node_modules/on-exit-leak-free": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-0.2.0.tgz", + "integrity": "sha512-dqaz3u44QbRXQooZLTUKU41ZrzYrcvLISVgbrzbyCMxpmSLJvZ3ZamIJIZ29P6OhZIkNIQKosdeM6t1LYbA9hg==" + }, + "node_modules/baileys/node_modules/pino": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-7.11.0.tgz", + "integrity": "sha512-dMACeu63HtRLmCG8VKdy4cShCPKaYDR4youZqoSWLxl5Gu99HUw8bw75thbPv9Nip+H+QYX8o3ZJbTdVZZ2TVg==", + "dependencies": { + "atomic-sleep": "^1.0.0", + "fast-redact": "^3.0.0", + "on-exit-leak-free": "^0.2.0", + "pino-abstract-transport": "v0.5.0", + "pino-std-serializers": "^4.0.0", + "process-warning": "^1.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.1.0", + "safe-stable-stringify": "^2.1.0", + "sonic-boom": "^2.2.1", + "thread-stream": "^0.15.1" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/baileys/node_modules/pino-abstract-transport": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-0.5.0.tgz", + "integrity": "sha512-+KAgmVeqXYbTtU2FScx1XS3kNyfZ5TrXY07V96QnUSFqo2gAqlvmaxH67Lj7SWazqsMabf+58ctdTcBgnOLUOQ==", + "dependencies": { + "duplexify": "^4.1.2", + "split2": "^4.0.0" + } + }, + "node_modules/baileys/node_modules/pino-std-serializers": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-4.0.0.tgz", + "integrity": "sha512-cK0pekc1Kjy5w9V2/n+8MkZwusa6EyyxfeQCB799CQRhRt/CqYKiWs5adeu8Shve2ZNffvfC/7J64A2PJo1W/Q==" + }, + "node_modules/baileys/node_modules/process-warning": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-1.0.0.tgz", + "integrity": "sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q==" + }, + "node_modules/baileys/node_modules/real-require": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.1.0.tgz", + "integrity": "sha512-r/H9MzAWtrv8aSVjPCMFpDMl5q66GqtmmRkRjpHTsp4zBAa+snZyiQNlMONiUmEJcsnaw0wCauJ2GWODr/aFkg==", + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/baileys/node_modules/sonic-boom": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-2.8.0.tgz", + "integrity": "sha512-kuonw1YOYYNOve5iHdSahXPOK49GqwA+LZhI6Wz/l0rP57iKyXXIHaRagOBHAPmGwJC6od2Z9zgvZ5loSgMlVg==", + "dependencies": { + "atomic-sleep": "^1.0.0" + } + }, + "node_modules/baileys/node_modules/thread-stream": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-0.15.2.tgz", + "integrity": "sha512-UkEhKIg2pD+fjkHQKyJO3yoIvAP3N6RlNFt2dUhcS1FGvCD1cQa1M/PGknCLFIyZdtJOWQjejp7bdNqmN7zwdA==", + "dependencies": { + "real-require": "^0.1.0" + } + }, + "node_modules/baileys/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/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/bare-events": { + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.5.4.tgz", + "integrity": "sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==", + "optional": true + }, + "node_modules/bare-fs": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.0.1.tgz", + "integrity": "sha512-ilQs4fm/l9eMfWY2dY0WCIUplSUp7U0CT1vrqMg1MUdeZl4fypu5UP0XcDBK5WBQPJAKP1b7XEodISmekH/CEg==", + "optional": true, + "dependencies": { + "bare-events": "^2.0.0", + "bare-path": "^3.0.0", + "bare-stream": "^2.0.0" + }, + "engines": { + "bare": ">=1.7.0" + } + }, + "node_modules/bare-os": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.4.0.tgz", + "integrity": "sha512-9Ous7UlnKbe3fMi7Y+qh0DwAup6A1JkYgPnjvMDNOlmnxNRQvQ/7Nst+OnUQKzk0iAT0m9BisbDVp9gCv8+ETA==", + "optional": true, + "engines": { + "bare": ">=1.6.0" + } + }, + "node_modules/bare-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz", + "integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==", + "optional": true, + "dependencies": { + "bare-os": "^3.0.1" + } + }, + "node_modules/bare-stream": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.6.4.tgz", + "integrity": "sha512-G6i3A74FjNq4nVrrSTUz5h3vgXzBJnjmWAVlBWaZETkgu+LgKd7AiyOml3EDJY1AHlIbBHKDXE+TUT53Ff8OaA==", + "optional": true, + "dependencies": { + "streamx": "^2.21.0" + }, + "peerDependencies": { + "bare-buffer": "*", + "bare-events": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + }, + "bare-events": { + "optional": true + } + } + }, + "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/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, + "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==", + "dev": true, + "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==", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/block-stream2": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/block-stream2/-/block-stream2-2.1.0.tgz", + "integrity": "sha512-suhjmLI57Ewpmq00qaygS8UgEq2ly2PCItenIyhMqVjo4t4pGzqMvfgJuX8iWTeSDdfSSqS6j38fL4ToNL7Pfg==", + "dependencies": { + "readable-stream": "^3.4.0" + } + }, + "node_modules/bmp-js": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.1.0.tgz", + "integrity": "sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw==" + }, + "node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "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/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/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/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/browser-or-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/browser-or-node/-/browser-or-node-2.1.1.tgz", + "integrity": "sha512-8CVjaLJGuSKMVTxJ2DpBl5XnlNDiT4cQFeuCJJrvJmts9YrTZDizTX7PjC2s6W4x+MBGZeEY6dGMrF04/6Hgqg==" + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "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/buffer-crc32": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz", + "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/buffer-equal": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-0.0.1.tgz", + "integrity": "sha512-RgSV6InVQ9ODPdLWJ5UAqBqJBOg370Nz6ZQtRzpt6nUjc8v0St97uJ4PYC6NztqIScrAXafKM3mZPMygSe1ggA==", + "engines": { + "node": ">=0.4.0" + } + }, + "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==" + }, + "node_modules/buffer-more-ints": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-more-ints/-/buffer-more-ints-1.0.0.tgz", + "integrity": "sha512-EMetuGFz5SLsT0QTnXzINh4Ksr+oo4i+UGTXEshiGCQWnsgSs7ZhJ8fzlwQ+OzEMs0MpDAMr1hxnblp5a4vcHg==" + }, + "node_modules/bundle-require": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/bundle-require/-/bundle-require-5.1.0.tgz", + "integrity": "sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==", + "dependencies": { + "load-tsconfig": "^0.2.3" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "peerDependencies": { + "esbuild": ">=0.18" + } + }, + "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/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "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==", + "engines": { + "node": ">=8" + } + }, + "node_modules/cache-manager": { + "version": "5.7.6", + "resolved": "https://registry.npmjs.org/cache-manager/-/cache-manager-5.7.6.tgz", + "integrity": "sha512-wBxnBHjDxF1RXpHCBD6HGvKER003Ts7IIm0CHpggliHzN1RZditb7rXoduE1rplc2DEFYKxhLKgFuchXMJje9w==", + "dependencies": { + "eventemitter3": "^5.0.1", + "lodash.clonedeep": "^4.5.0", + "lru-cache": "^10.2.2", + "promise-coalesce": "^1.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz", + "integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz", + "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "get-intrinsic": "^1.2.6" + }, + "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==", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/centra": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/centra/-/centra-2.7.0.tgz", + "integrity": "sha512-PbFMgMSrmgx6uxCdm57RUos9Tc3fclMvhLSATYN39XsDV29B89zZ3KA89jmY0vwSGazyU+uerqwa6t+KaodPcg==", + "dependencies": { + "follow-redirects": "^1.15.6" + } + }, + "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/cheerio": { + "version": "1.0.0-rc.11", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.11.tgz", + "integrity": "sha512-bQwNaDIBKID5ts/DsdhxrjqFXYfLw4ste+wMKqWA8DyKcS4qwsPP4Bk8ZNaTJjvpiX/qW3BT4sU7d6Bh5i+dag==", + "dependencies": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "htmlparser2": "^8.0.1", + "parse5": "^7.0.0", + "parse5-htmlparser2-tree-adapter": "^7.0.0", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "dependencies": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "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==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, + "node_modules/cjs-module-lexer": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", + "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==" + }, + "node_modules/class-validator": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.1.tgz", + "integrity": "sha512-2VEG9JICxIqTpoK1eMzZqaV+u/EiwEJkMGzTrZf6sU/fwsnOITVgYJ8yojSy6CaXtO9V0Cc6ZQZ8h8m4UBuLwQ==", + "dependencies": { + "@types/validator": "^13.11.8", + "libphonenumber-js": "^1.10.53", + "validator": "^13.9.0" + } + }, + "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/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/cluster-key-slot": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", + "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/codec-parser": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/codec-parser/-/codec-parser-2.5.0.tgz", + "integrity": "sha512-Ru9t80fV8B0ZiixQl8xhMTLru+dzuis/KQld32/x5T/+3LwZb0/YvQdSKytX9JqCnRdiupvAvyYJINKrXieziQ==" + }, + "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": "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/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/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/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/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.5.tgz", + "integrity": "sha512-bQJ0YRck5ak3LgtnpKkiabX5pNF7tMUh1BSy2ZBOTh0Dim0BUu6aPPwByIns6/A5Prh8PufSPerMDUklpzes2Q==", + "dependencies": { + "bytes": "3.1.2", + "compressible": "~2.0.18", + "debug": "2.6.9", + "negotiator": "~0.6.4", + "on-headers": "~1.0.2", + "safe-buffer": "5.2.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/compression/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/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/concat-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/concat-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/concat-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/consola": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.0.tgz", + "integrity": "sha512-EiPU8G6dQG0GFHNR8ljnZFki/8a+cQwEQ+7wpxdChl02Q8HXlwEZWD5lqAF8vC2sEC3Tehr8hy7vErz88LHyUA==", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-disposition/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/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "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==", + "dev": true + }, + "node_modules/cross-fetch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", + "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", + "dependencies": { + "node-fetch": "2.6.7" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "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-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/curve25519-js": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/curve25519-js/-/curve25519-js-0.0.4.tgz", + "integrity": "sha512-axn2UMEnkhyDUPWOwVKBMVIzSQy2ejH2xRGy1wq81dqRwApXfIzfbE3hIX0ZRFBIihf/KDqK158DLwESu4AK1w==" + }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/dayjs": { + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==" + }, + "node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "dependencies": { + "ms": "^2.1.3" + }, + "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/decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "engines": { + "node": ">=0.10" + } + }, + "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==", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "engines": { + "node": ">=4.0.0" + } + }, + "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==" + }, + "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/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "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/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dijkstrajs": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz", + "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==" + }, + "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==", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "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/dom-walk": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", + "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==" + }, + "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.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "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.7", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", + "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/duplexify": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.3.tgz", + "integrity": "sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==", + "dependencies": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.2" + } + }, + "node_modules/dynamic-dedupe": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz", + "integrity": "sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ==", + "dev": true, + "dependencies": { + "xtend": "^4.0.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/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "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/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "engines": { + "node": ">= 0.8" + } + }, + "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==", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/engine.io": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.4.tgz", + "integrity": "sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==", + "dependencies": { + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.7.2", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.17.1" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/engine.io-client": { + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.3.tgz", + "integrity": "sha512-T0iLjnyNWahNyv/lcjS2y4oE358tVS/SYQNxYXGAJ9/GLgH4VCvOQ/mhTjqU88mLZCQgiG8RIegFHYCdVC+j5w==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.17.1", + "xmlhttprequest-ssl": "~2.1.1" + } + }, + "node_modules/engine.io-client/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/engine.io-client/node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "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/engine.io-parser": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io/node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/engine.io/node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "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/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/es-abstract": { + "version": "1.23.9", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.9.tgz", + "integrity": "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.0", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-regex": "^1.2.1", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.0", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.3", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.18" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "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-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "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.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "dev": true, + "dependencies": { + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/esbuild": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz", + "integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==", + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.24.2", + "@esbuild/android-arm": "0.24.2", + "@esbuild/android-arm64": "0.24.2", + "@esbuild/android-x64": "0.24.2", + "@esbuild/darwin-arm64": "0.24.2", + "@esbuild/darwin-x64": "0.24.2", + "@esbuild/freebsd-arm64": "0.24.2", + "@esbuild/freebsd-x64": "0.24.2", + "@esbuild/linux-arm": "0.24.2", + "@esbuild/linux-arm64": "0.24.2", + "@esbuild/linux-ia32": "0.24.2", + "@esbuild/linux-loong64": "0.24.2", + "@esbuild/linux-mips64el": "0.24.2", + "@esbuild/linux-ppc64": "0.24.2", + "@esbuild/linux-riscv64": "0.24.2", + "@esbuild/linux-s390x": "0.24.2", + "@esbuild/linux-x64": "0.24.2", + "@esbuild/netbsd-arm64": "0.24.2", + "@esbuild/netbsd-x64": "0.24.2", + "@esbuild/openbsd-arm64": "0.24.2", + "@esbuild/openbsd-x64": "0.24.2", + "@esbuild/sunos-x64": "0.24.2", + "@esbuild/win32-arm64": "0.24.2", + "@esbuild/win32-ia32": "0.24.2", + "@esbuild/win32-x64": "0.24.2" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "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==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", + "@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-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-module-utils": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz", + "integrity": "sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==", + "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.31.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz", + "integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==", + "dev": true, + "dependencies": { + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.8", + "array.prototype.findlastindex": "^1.2.5", + "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.12.0", + "hasown": "^2.0.2", + "is-core-module": "^2.15.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.0", + "semver": "^6.3.1", + "string.prototype.trimend": "^1.0.8", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-import/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/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/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/eslint-plugin-import/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/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-import/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/eslint-plugin-prettier": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.3.tgz", + "integrity": "sha512-qJ+y0FfCp/mQYQ/vWQ3s7eUlFEL4PyKfAJxsnYTJ4YT73nsJBWqmEpFryxV9OeUiqmsTsYJ5Y+KDNaeP31wrRw==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.9.1" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": "*", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-simple-import-sort": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-10.0.0.tgz", + "integrity": "sha512-AeTvO9UCMSNzIHRkg8S6c3RPy5YEwKWSQPx3DYghLedo2ZQxowPFLGDN1AZ2evfg6r6mjBSZSLxLFsWSu3acsw==", + "dev": true, + "peerDependencies": { + "eslint": ">=5.0.0" + } + }, + "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==", + "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==", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/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==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "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==", + "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==", + "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==", + "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==", + "engines": { + "node": ">=4.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==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "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/eventemitter2": { + "version": "6.4.9", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.9.tgz", + "integrity": "sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==" + }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==" + }, + "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/exif-parser": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/exif-parser/-/exif-parser-0.1.12.tgz", + "integrity": "sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw==" + }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/express": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.12", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-async-errors": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/express-async-errors/-/express-async-errors-3.1.1.tgz", + "integrity": "sha512-h6aK1da4tpqWSbyCa3FxB/V6Ehd4EEB15zyQq9qe75OZBp0krinNKuH4rAY+S/U/2I36vdLAUFSjQJ+TFmODng==", + "peerDependencies": { + "express": "^4.16.2" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/express/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/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-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "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.8" + }, + "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==" + }, + "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==" + }, + "node_modules/fast-redact": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.5.0.tgz", + "integrity": "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==", + "engines": { + "node": ">=6" + } + }, + "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.19.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.0.tgz", + "integrity": "sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA==", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "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==", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/file-type": { + "version": "16.5.4", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-16.5.4.tgz", + "integrity": "sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw==", + "dependencies": { + "readable-web-to-node-stream": "^3.0.0", + "strtok3": "^6.2.4", + "token-types": "^4.1.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/file-type?sponsor=1" + } + }, + "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": "1.1.0", + "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz", + "integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "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==", + "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==", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", + "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==" + }, + "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/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/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.4.tgz", + "integrity": "sha512-kKaIINnFpzW6ffJNDjjyjrk21BkDx38c0xa/klsT8VzLCaMEefv4ZTacrcVR4DmgTeBra++jMDAfS/tS799YDw==", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/form-data": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "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/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/forwarded-parse": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/forwarded-parse/-/forwarded-parse-2.1.2.tgz", + "integrity": "sha512-alTFZZQDKMporBH77856pXgzhEzaUVmLCDk+egLgIgHst3Tpndzz8MnKe+GzRJRfvVdn69HhpW7cmXzvtLvJAw==" + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, + "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==" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "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.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" + }, + "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/futoin-hkdf": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/futoin-hkdf/-/futoin-hkdf-1.5.3.tgz", + "integrity": "sha512-SewY5KdMpaoCeh7jachEWFsh1nNlaDjNHZXWqL5IGwtpEYHTgkr2+AMCgNwKWkcc0wpSYrZfR7he4WdmHFtDxQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/generic-pool": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", + "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==", + "engines": { + "node": ">= 4" + } + }, + "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-intrinsic": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.7.tgz", + "integrity": "sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "function-bind": "^1.1.2", + "get-proto": "^1.0.0", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gifwrap": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/gifwrap/-/gifwrap-0.9.4.tgz", + "integrity": "sha512-MDMwbhASQuVeD4JKd1fKgNgCRL3fGqMM4WaqpNhWO0JiMOAjbQdumbs4BbBZEy9/M00EHEjKN3HieVhCUlwjeQ==", + "dependencies": { + "image-q": "^4.0.0", + "omggif": "^1.0.10" + } + }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" + }, + "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", + "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/glob/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==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/global": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", + "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", + "dependencies": { + "min-document": "^2.19.0", + "process": "^0.11.10" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "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/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==" + }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "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.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dev": true, + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "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==", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "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/i18next": { + "version": "23.16.8", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-23.16.8.tgz", + "integrity": "sha512-06r/TitrM88Mg5FdUXAKL96dJMzgqLE5dv3ryBAra4KCwD9mJ4ndOTS95ZuymIGoE+2hzfdaMak2X11/es7ZWg==", + "funding": [ + { + "type": "individual", + "url": "https://locize.com" + }, + { + "type": "individual", + "url": "https://locize.com/i18next.html" + }, + { + "type": "individual", + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" + } + ], + "dependencies": { + "@babel/runtime": "^7.23.2" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "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.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/image-q": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/image-q/-/image-q-4.0.0.tgz", + "integrity": "sha512-PfJGVgIfKQJuq3s0tTDOKtztksibuUEbJQIYT3by6wctQo+Rdlh7ef4evJ5NCdxY4CfMbvFkocEwbl4BF8RlJw==", + "dependencies": { + "@types/node": "16.9.1" + } + }, + "node_modules/image-q/node_modules/@types/node": { + "version": "16.9.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.9.1.tgz", + "integrity": "sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g==" + }, + "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==", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-in-the-middle": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-1.12.0.tgz", + "integrity": "sha512-yAgSE7GmtRcu4ZUSFX/4v69UGXwugFFSdIQJ14LHPOPPQrWv8Y7O9PHsw8Ovk7bKCLe4sjXMbZFqGFcLHpZ89w==", + "dependencies": { + "acorn": "^8.8.2", + "acorn-import-attributes": "^1.9.5", + "cjs-module-lexer": "^1.2.2", + "module-details-from-path": "^1.0.3" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "engines": { + "node": ">=0.8.19" + } + }, + "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.", + "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==" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ipaddr.js": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", + "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-arguments": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", + "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "dev": true, + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-base64": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-base64/-/is-base64-1.1.0.tgz", + "integrity": "sha512-Nlhg7Z2dVC4/PTvIFkgVVNvPHSO2eR/Yd0XzhGiXCXEvWnptXlXa/clQ8aePPiMuxEGcWfzWbGw2Fe3d+Y3v1g==", + "bin": { + "is_base64": "bin/is-base64", + "is-base64": "bin/is-base64" + } + }, + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "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==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.1.tgz", + "integrity": "sha512-l9qO6eFlUETHtuihLcYOaLKByJ1f+N4kthcU9YjHy3N+B3hWv0y/2Nd0mu/7lTFnRQHTrSdXF50HQ3bl5fEnng==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "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==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/is-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", + "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==" + }, + "node_modules/is-generator-function": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", + "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", + "dependencies": { + "call-bound": "^1.0.3", + "get-proto": "^1.0.0", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.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-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-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.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "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==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "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.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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.1.0", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.0.tgz", + "integrity": "sha512-SXM8Nwyys6nT5WP6pltOwKytLV7FqQ4UiibxVmW+EIosHcmCqkkjViTb5SNssDlkCiEYRP1/pdWUKVvZBmsR2Q==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "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/jimp": { + "version": "0.16.13", + "resolved": "https://registry.npmjs.org/jimp/-/jimp-0.16.13.tgz", + "integrity": "sha512-Bxz8q7V4rnCky9A0ktTNGA9SkNFVWRHodddI/DaAWZJzF7sVUlFYKQ60y9JGqrKpi48ECA/TnfMzzc5C70VByA==", + "dependencies": { + "@babel/runtime": "^7.7.2", + "@jimp/custom": "^0.16.13", + "@jimp/plugins": "^0.16.13", + "@jimp/types": "^0.16.13", + "regenerator-runtime": "^0.13.3" + } + }, + "node_modules/jimp/node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + }, + "node_modules/joycon": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", + "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", + "engines": { + "node": ">=10" + } + }, + "node_modules/jpeg-js": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.4.tgz", + "integrity": "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==" + }, + "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==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "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==" + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" + }, + "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==" + }, + "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==" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonschema": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.5.0.tgz", + "integrity": "sha512-K+A9hhqbn0f3pJX17Q/7H6yQfD/5OXgdrR5UE12gMXCiN9D5Xq2o5mddV2QEcX/bjla99ASsAAQUyMCCRWAEhw==", + "engines": { + "node": "*" + } + }, + "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==", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "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==", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/libphonenumber-js": { + "version": "1.11.19", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.11.19.tgz", + "integrity": "sha512-bW/Yp/9dod6fmyR+XqSUL1N5JE7QRxQ3KrBIbYS1FTv32e5i3SEtQVX+71CYNv8maWNSOgnlCoNp9X78f/cKiA==" + }, + "node_modules/libsignal": { + "name": "@whiskeysockets/libsignal-node", + "version": "2.0.1", + "resolved": "git+ssh://git@github.com/WhiskeySockets/libsignal-node.git#1bd9275d9e621d2ba899087ebdf548b3a5a4f05e", + "dependencies": { + "curve25519-js": "^0.0.4", + "protobufjs": "6.8.8" + } + }, + "node_modules/libsignal/node_modules/@types/node": { + "version": "10.17.60", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", + "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==" + }, + "node_modules/libsignal/node_modules/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "node_modules/libsignal/node_modules/protobufjs": { + "version": "6.8.8", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.8.8.tgz", + "integrity": "sha512-AAmHtD5pXgZfi7GMpllpO3q1Xw1OYldr+dMUlAnffGTAhqkg72WdmSY71uKBF/JuyiKs8psYbtKrhi0ASCD8qw==", + "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/long": "^4.0.0", + "@types/node": "^10.1.0", + "long": "^4.0.0" + }, + "bin": { + "pbjs": "bin/pbjs", + "pbts": "bin/pbts" + } + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "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/link-preview-js": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/link-preview-js/-/link-preview-js-3.0.13.tgz", + "integrity": "sha512-6WeGlt+jnh9s8mTl4fOBtAvb9JYHhIoPsB+sKZKE/cStaHyPRNN9Y8bKL3qKvBlVQEe8pZ+d49A6kJ89oclIvw==", + "dependencies": { + "abort-controller": "^3.0.0", + "cheerio": "1.0.0-rc.11", + "cross-fetch": "3.1.5", + "url": "0.11.0" + } + }, + "node_modules/load-bmfont": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/load-bmfont/-/load-bmfont-1.4.2.tgz", + "integrity": "sha512-qElWkmjW9Oq1F9EI5Gt7aD9zcdHb9spJCW1L/dmPf7KzCCEJxq8nhHz5eCgI9aMf7vrG/wyaCqdsI+Iy9ZTlog==", + "dependencies": { + "buffer-equal": "0.0.1", + "mime": "^1.3.4", + "parse-bmfont-ascii": "^1.0.3", + "parse-bmfont-binary": "^1.0.5", + "parse-bmfont-xml": "^1.1.4", + "phin": "^3.7.1", + "xhr": "^2.0.1", + "xtend": "^4.0.0" + } + }, + "node_modules/load-bmfont/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/load-bmfont/node_modules/phin": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/phin/-/phin-3.7.1.tgz", + "integrity": "sha512-GEazpTWwTZaEQ9RhL7Nyz0WwqilbqgLahDM3D0hxWwmVDI52nXEybHqiN6/elwpkJBhcuj+WbBu+QfT0uhPGfQ==", + "dependencies": { + "centra": "^2.7.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/load-tsconfig": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/load-tsconfig/-/load-tsconfig-0.2.5.tgz", + "integrity": "sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "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==", + "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.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" + }, + "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==" + }, + "node_modules/lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==" + }, + "node_modules/long": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.4.tgz", + "integrity": "sha512-qtzLbJE8hq7VabR3mISmVGtoXP8KGc2Z/AT8OuqlYD7JTR3oqrgwdjnk07wpj1twXxYmgDXgoKVWUG/fReSzHg==" + }, + "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/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/mediainfo.js": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/mediainfo.js/-/mediainfo.js-0.3.4.tgz", + "integrity": "sha512-uTUlVqw9PcsuVt4DcXvqfQGKQBx3BCyQcDnJ68kSQyOxz0InIsCuykPShrYp+c5uDr6Mvhy5AfaboHn77xR7Ug==", + "dependencies": { + "yargs": "^17.7.2" + }, + "bin": { + "mediainfo.js": "dist/esm/cli.js" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/mime/-/mime-4.0.6.tgz", + "integrity": "sha512-4rGt7rvQHBbaSOF9POGkk1ocRP16Md1x36Xma8sz8h8/vfCUI2OtEIeCqe4Ofes853x4xDoPiFLIT47J5fI/7A==", + "funding": [ + "https://github.com/sponsors/broofa" + ], + "bin": { + "mime": "bin/cli.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/mime-db": { + "version": "1.53.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.53.0.tgz", + "integrity": "sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg==", + "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/mime-types/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/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==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/min-document": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", + "integrity": "sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==", + "dependencies": { + "dom-walk": "^0.1.0" + } + }, + "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/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minio": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/minio/-/minio-8.0.4.tgz", + "integrity": "sha512-GVW7y2PNbzjjFJ9opVMGKvDNuRkyz3bMt1q7UrHs7bsKFWLXbSvMPffjE/HkVYWUjlD8kQwMaeqiHhhvZJJOfQ==", + "dependencies": { + "async": "^3.2.4", + "block-stream2": "^2.1.0", + "browser-or-node": "^2.1.1", + "buffer-crc32": "^1.0.0", + "eventemitter3": "^5.0.1", + "fast-xml-parser": "^4.4.1", + "ipaddr.js": "^2.0.1", + "lodash": "^4.17.21", + "mime-types": "^2.1.35", + "query-string": "^7.1.3", + "stream-json": "^1.8.0", + "through2": "^4.0.2", + "web-encoding": "^1.1.5", + "xml2js": "^0.5.0 || ^0.6.2" + }, + "engines": { + "node": "^16 || ^18 || >=20" + } + }, + "node_modules/minio/node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==" + }, + "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/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" + }, + "node_modules/module-details-from-path": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.3.tgz", + "integrity": "sha512-ySViT69/76t8VhE1xXHK6Ch4NcDd26gx0MzKXLO+F7NOtnqH68d9zF94nT8ZWSxXh8ELOERsnJO/sWt1xZYw5A==" + }, + "node_modules/mpg123-decoder": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mpg123-decoder/-/mpg123-decoder-1.0.0.tgz", + "integrity": "sha512-WV+pyuMUhRqv7s8S6p/Ii4KQHdBD1pb3yaABxcKJRsNp+HQ/Y6z2iIBIaOZu0JMHPTOoICYt0REDZ7XfLu+n/g==", + "dependencies": { + "@wasm-audio-decoders/common": "9.0.5" + }, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/eshaz" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/multer": { + "version": "1.4.5-lts.1", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.1.tgz", + "integrity": "sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==", + "dependencies": { + "append-field": "^1.0.0", + "busboy": "^1.0.0", + "concat-stream": "^1.5.2", + "mkdirp": "^0.5.4", + "object-assign": "^4.1.1", + "type-is": "^1.6.4", + "xtend": "^4.0.0" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/music-metadata": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/music-metadata/-/music-metadata-7.14.0.tgz", + "integrity": "sha512-xrm3w7SV0Wk+OythZcSbaI8mcr/KHd0knJieu8bVpaPfMv/Agz5EooCAPz3OR5hbYMiUG6dgAPKZKnMzV+3amA==", + "dependencies": { + "@tokenizer/token": "^0.3.0", + "content-type": "^1.0.5", + "debug": "^4.3.4", + "file-type": "^16.5.4", + "media-typer": "^1.1.0", + "strtok3": "^6.3.0", + "token-types": "^4.2.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "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/napi-build-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", + "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" + }, + "node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-abi": { + "version": "3.73.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.73.0.tgz", + "integrity": "sha512-z8iYzQGBu35ZkTQ9mtR8RqugJZ9RCLn8fv3d7LsgDBzOijGQP3RdKTX4LA7LXw03ZhU5z0l4xfhIMgSES31+cg==", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-addon-api": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", + "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==" + }, + "node_modules/node-cache": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/node-cache/-/node-cache-5.1.2.tgz", + "integrity": "sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==", + "dependencies": { + "clone": "2.x" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/node-cron": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/node-cron/-/node-cron-3.0.3.tgz", + "integrity": "sha512-dOal67//nohNgYWb+nWmg5dkFdIwDm8EpeGYMekPMrngV3637lqnX0lbUcCtgibHTz6SEz7DAIjKvKDFYCnO1A==", + "dependencies": { + "uuid": "8.3.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/node-cron/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "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.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "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-wav": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/node-wav/-/node-wav-0.0.2.tgz", + "integrity": "sha512-M6Rm/bbG6De/gKGxOpeOobx/dnGuP0dz40adqx38boqHhlWssBJZgLCPBNtb9NkrmnKYiV04xELq+R6PFOnoLA==", + "engines": { + "node": ">=4.4.0" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=0.10.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/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-inspect": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", + "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", + "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.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ogg-opus-decoder": { + "version": "1.6.14", + "resolved": "https://registry.npmjs.org/ogg-opus-decoder/-/ogg-opus-decoder-1.6.14.tgz", + "integrity": "sha512-RQpk9yFl/mqXFwcgf1BrEYWL92HZk++aU1fOO8mPZ1+1DUYbJdpdUQEFfbPE1xcBkRGU3p75DjEO+EDMNeikFQ==", + "dependencies": { + "@wasm-audio-decoders/common": "9.0.5", + "codec-parser": "2.5.0", + "opus-decoder": "0.7.7" + }, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/eshaz" + } + }, + "node_modules/omggif": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/omggif/-/omggif-1.0.10.tgz", + "integrity": "sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw==" + }, + "node_modules/on-exit-leak-free": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", + "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "engines": { + "node": ">= 0.8" + } + }, + "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==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/openai": { + "version": "4.81.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-4.81.0.tgz", + "integrity": "sha512-lXkFkV+He3O6RGnldHncRGef4uWHssDsAVwN5I3bWcgIdDPy/w8vgtIAwvZxAj49m4WiwWVD0+eGTJ9xOv/ISA==", + "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": { + "ws": "^8.18.0", + "zod": "^3.23.8" + }, + "peerDependenciesMeta": { + "ws": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/openai/node_modules/@types/node": { + "version": "18.19.74", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.74.tgz", + "integrity": "sha512-HMwEkkifei3L605gFdV+/UwtpxP6JSzM+xFk2Ia6DNFSwSVBRh9qp5Tgf4lNFOMfPVuU0WnkcWpXZpgn5ufO4A==", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/openai/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/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "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/opus-decoder": { + "version": "0.7.7", + "resolved": "https://registry.npmjs.org/opus-decoder/-/opus-decoder-0.7.7.tgz", + "integrity": "sha512-KWDyCi/9aXnNN+jrjs+aaVdwiwzDdac81S9ul0iv1CTs4+5K4VDZKuJjIImrYOBA2oSNHDjVq4xzn6BE+XbI1A==", + "dependencies": { + "@wasm-audio-decoders/common": "9.0.5" + }, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/eshaz" + } + }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "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==", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==" + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, + "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==", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-bmfont-ascii": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/parse-bmfont-ascii/-/parse-bmfont-ascii-1.0.6.tgz", + "integrity": "sha512-U4RrVsUFCleIOBsIGYOMKjn9PavsGOXxbvYGtMOEfnId0SVNsgehXh1DxUdVPLoxd5mvcEtvmKs2Mmf0Mpa1ZA==" + }, + "node_modules/parse-bmfont-binary": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/parse-bmfont-binary/-/parse-bmfont-binary-1.0.6.tgz", + "integrity": "sha512-GxmsRea0wdGdYthjuUeWTMWPqm2+FAd4GI8vCvhgJsFnoGhTrLhXDDupwTo7rXVAgaLIGoVHDZS9p/5XbSqeWA==" + }, + "node_modules/parse-bmfont-xml": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/parse-bmfont-xml/-/parse-bmfont-xml-1.1.6.tgz", + "integrity": "sha512-0cEliVMZEhrFDwMh4SxIyVJpqYoOWDJ9P895tFuS+XuNzI5UBmBk5U5O4KuJdTnZpSBI4LFA2+ZiJaiwfSwlMA==", + "dependencies": { + "xml-parse-from-string": "^1.0.0", + "xml2js": "^0.5.0" + } + }, + "node_modules/parse-bmfont-xml/node_modules/xml2js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/parse-headers": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.5.tgz", + "integrity": "sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==" + }, + "node_modules/parse5": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", + "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==", + "dependencies": { + "entities": "^4.5.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz", + "integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==", + "dependencies": { + "domhandler": "^5.0.3", + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "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==", + "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==", + "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-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==" + }, + "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==", + "engines": { + "node": ">=8" + } + }, + "node_modules/peek-readable": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-4.1.0.tgz", + "integrity": "sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==", + "engines": { + "node": ">=8" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/pg": { + "version": "8.13.1", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.13.1.tgz", + "integrity": "sha512-OUir1A0rPNZlX//c7ksiu7crsGZTKSOXJPgtNiHGIlC9H0lO+NC6ZDYksSgBYY/thSWhnSRBv8w1lieNNGATNQ==", + "dependencies": { + "pg-connection-string": "^2.7.0", + "pg-pool": "^3.7.0", + "pg-protocol": "^1.7.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + }, + "engines": { + "node": ">= 8.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.1.1" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-cloudflare": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz", + "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", + "optional": true + }, + "node_modules/pg-connection-string": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.7.0.tgz", + "integrity": "sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA==" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.7.0.tgz", + "integrity": "sha512-ZOBQForurqh4zZWjrgSwwAtzJ7QiRX0ovFkZr2klsen3Nm0aoh33Ls0fzfv3imeH/nw/O27cjdz5kzYJfeGp/g==", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.7.0.tgz", + "integrity": "sha512-hTK/mE36i8fDDhgDFjy6xNOG+LCorxLG3WO17tku+ij6sVHXh1jQUJ8hYAnRhNla4QVD2H8er/FOjc/+EgC6yQ==" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "dependencies": { + "split2": "^4.1.0" + } + }, + "node_modules/phin": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/phin/-/phin-2.9.3.tgz", + "integrity": "sha512-CzFr90qM24ju5f88quFC/6qohjC144rehe5n6DH900lgXmUe86+xCKc10ev56gRKC4/BkHUoG4uSiQgBiIXwDA==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info." + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" + }, + "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/pino": { + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-8.21.0.tgz", + "integrity": "sha512-ip4qdzjkAyDDZklUaZkcRFb2iA118H9SgRh8yzTkSQK8HilsOJF7rSY8HoW5+I0M46AZgX/pxbprf2vvzQCE0Q==", + "dependencies": { + "atomic-sleep": "^1.0.0", + "fast-redact": "^3.1.1", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^1.2.0", + "pino-std-serializers": "^6.0.0", + "process-warning": "^3.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^3.7.0", + "thread-stream": "^2.6.0" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/pino-abstract-transport": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-1.2.0.tgz", + "integrity": "sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q==", + "dependencies": { + "readable-stream": "^4.0.0", + "split2": "^4.0.0" + } + }, + "node_modules/pino-abstract-transport/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/pino-abstract-transport/node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "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/pino-std-serializers": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-6.2.2.tgz", + "integrity": "sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA==" + }, + "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/pixelmatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-4.0.2.tgz", + "integrity": "sha512-J8B6xqiO37sU/gkcMglv6h5Jbd9xNER7aHzpfRdNmV4IbQBzBpe4l9XmbG+xPF/znacgu2jfEw+wHffaq/YkXA==", + "dependencies": { + "pngjs": "^3.0.0" + }, + "bin": { + "pixelmatch": "bin/pixelmatch" + } + }, + "node_modules/pngjs": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", + "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==", + "engines": { + "node": ">=4.0.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==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss-load-config": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", + "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "lilconfig": "^3.1.1" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "jiti": ">=1.21.0", + "postcss": ">=8.0.9", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/prebuild-install": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", + "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^2.0.0", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/prebuild-install/node_modules/tar-fs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.2.tgz", + "integrity": "sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==", + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/prebuild-install/node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "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==", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz", + "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/prisma": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-6.3.0.tgz", + "integrity": "sha512-y+Zh3Qg+xGCWyyrNUUNaFW/OltaV/yXYuTa0WRgYkz5LGyifmAsgpv94I47+qGRocZrMGcbF2A/78/oO2zgifA==", + "hasInstallScript": true, + "dependencies": { + "@prisma/engines": "6.3.0" + }, + "bin": { + "prisma": "build/index.js" + }, + "engines": { + "node": ">=18.18" + }, + "optionalDependencies": { + "fsevents": "2.3.3" + }, + "peerDependencies": { + "typescript": ">=5.1.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "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/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/process-warning": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-3.0.0.tgz", + "integrity": "sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==" + }, + "node_modules/promise-coalesce": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/promise-coalesce/-/promise-coalesce-1.1.2.tgz", + "integrity": "sha512-zLaJ9b8hnC564fnJH6NFSOGZYYdzrAJn2JUUIwzoQb32fG2QAakpDNM+CZo1km6keXkRXRM+hml1BFAPVnPkxg==", + "engines": { + "node": ">=16" + } + }, + "node_modules/protobufjs": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.4.0.tgz", + "integrity": "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==", + "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/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/pump": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", + "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", + "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/pusher": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/pusher/-/pusher-5.2.0.tgz", + "integrity": "sha512-F6LNiZyJsIkoHLz+YurjKZ1HH8V1/cMggn4k97kihjP3uTvm0P4mZzSFeHOWIy+PlJ2VInJBhUFJBYLsFR5cjg==", + "dependencies": { + "@types/node-fetch": "^2.5.7", + "abort-controller": "^3.0.0", + "is-base64": "^1.1.0", + "node-fetch": "^2.6.1", + "tweetnacl": "^1.0.0", + "tweetnacl-util": "^0.15.0" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/qoa-format": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/qoa-format/-/qoa-format-1.0.1.tgz", + "integrity": "sha512-dMB0Z6XQjdpz/Cw4Rf6RiBpQvUSPCfYlQMWvmuWlWkAT7nDQD29cVZ1SwDUB6DYJSitHENwbt90lqfI+7bvMcw==", + "dependencies": { + "@thi.ng/bitstream": "^2.2.12" + } + }, + "node_modules/qrcode": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.4.tgz", + "integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==", + "dependencies": { + "dijkstrajs": "^1.0.1", + "pngjs": "^5.0.0", + "yargs": "^15.3.1" + }, + "bin": { + "qrcode": "bin/qrcode" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/qrcode-terminal": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz", + "integrity": "sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ==", + "bin": { + "qrcode-terminal": "bin/qrcode-terminal.js" + } + }, + "node_modules/qrcode/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/qrcode/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==", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/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==", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/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==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/qrcode/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==", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/node_modules/pngjs": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", + "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/qrcode/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/qrcode/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" + }, + "node_modules/qrcode/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "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": "7.1.3", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.3.tgz", + "integrity": "sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==", + "dependencies": { + "decode-uri-component": "^0.2.2", + "filter-obj": "^1.1.0", + "split-on-first": "^1.0.0", + "strict-uri-encode": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", + "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", + "engines": { + "node": ">=0.4.x" + } + }, + "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-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==" + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readable-web-to-node-stream": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz", + "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==", + "dependencies": { + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/real-require": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/redis": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/redis/-/redis-4.7.0.tgz", + "integrity": "sha512-zvmkHEAdGMn+hMRXuMBtu4Vo5P6rHQjLoHftu+lBqq8ZTA3RCVC/WzD790bkKKiNFp7d5/9PcSD19fJyyRvOdQ==", + "workspaces": [ + "./packages/*" + ], + "dependencies": { + "@redis/bloom": "1.2.0", + "@redis/client": "1.6.0", + "@redis/graph": "1.1.1", + "@redis/json": "1.0.7", + "@redis/search": "1.2.0", + "@redis/time-series": "1.1.0" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "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.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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-in-the-middle": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-7.5.0.tgz", + "integrity": "sha512-/Tvpny/RVVicqlYTKwt/GtpZRsPG1CmJNhxVKGz+Sy/4MONfXCVNK69MFgGKdUt0/324q3ClI2dICcPgISrC8g==", + "dependencies": { + "debug": "^4.3.5", + "module-details-from-path": "^1.0.3", + "resolve": "^1.22.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + }, + "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/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "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/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", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "4.32.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.32.1.tgz", + "integrity": "sha512-z+aeEsOeEa3mEbS1Tjl6sAZ8NE3+AalQz1RJGj81M+fizusbdDMoEJwdJNHfaB40Scr4qNu+welOfes7maKonA==", + "dependencies": { + "@types/estree": "1.0.6" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.32.1", + "@rollup/rollup-android-arm64": "4.32.1", + "@rollup/rollup-darwin-arm64": "4.32.1", + "@rollup/rollup-darwin-x64": "4.32.1", + "@rollup/rollup-freebsd-arm64": "4.32.1", + "@rollup/rollup-freebsd-x64": "4.32.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.32.1", + "@rollup/rollup-linux-arm-musleabihf": "4.32.1", + "@rollup/rollup-linux-arm64-gnu": "4.32.1", + "@rollup/rollup-linux-arm64-musl": "4.32.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.32.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.32.1", + "@rollup/rollup-linux-riscv64-gnu": "4.32.1", + "@rollup/rollup-linux-s390x-gnu": "4.32.1", + "@rollup/rollup-linux-x64-gnu": "4.32.1", + "@rollup/rollup-linux-x64-musl": "4.32.1", + "@rollup/rollup-win32-arm64-msvc": "4.32.1", + "@rollup/rollup-win32-ia32-msvc": "4.32.1", + "@rollup/rollup-win32-x64-msvc": "4.32.1", + "fsevents": "~2.3.2" + } + }, + "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.3", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/sax": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==" + }, + "node_modules/semver": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.0.tgz", + "integrity": "sha512-DrfFnPzblFmNrIZzg5RzHegbiRWg7KMR7btwi2yjHwx06zsUbO5g613sVwEV7FTwmzJu+Io0lJe2GJ3LxqpvBQ==", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/send/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "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==" + }, + "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/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/sharp": { + "version": "0.32.6", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.32.6.tgz", + "integrity": "sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==", + "hasInstallScript": true, + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.2", + "node-addon-api": "^6.1.0", + "prebuild-install": "^7.1.1", + "semver": "^7.5.4", + "simple-get": "^4.0.1", + "tar-fs": "^3.0.4", + "tunnel-agent": "^0.6.0" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "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/shimmer": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", + "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==" + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "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/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "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": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "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-yenc": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/simple-yenc/-/simple-yenc-1.0.4.tgz", + "integrity": "sha512-5gvxpSd79e9a3V4QDYUqnqxeD4HGlhCakVpb6gMnDD7lexJggSBJRBO5h52y/iJrdXRilX9UCuDaIJhSWm5OWw==", + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/eshaz" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/socket.io": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz", + "integrity": "sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==", + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.6.0", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz", + "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==", + "dependencies": { + "debug": "~4.3.4", + "ws": "~8.17.1" + } + }, + "node_modules/socket.io-adapter/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io-adapter/node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "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/socket.io-client": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.1.tgz", + "integrity": "sha512-hJVXfu3E28NmzGk8o1sHhN3om52tRvwYeidbj7xKy2eIIse5IoKX3USlS6Tqt3BHAtflLIkCQBkzVrEEfWUyYQ==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.2", + "engine.io-client": "~6.6.1", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-client/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/sonic-boom": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.8.1.tgz", + "integrity": "sha512-y4Z8LCDBuum+PBP3lSV7RHrXscqksve/bi0as7mhwVnBW+/wUqKT/2Kb7um8yqcFy0duYbbPxzt89Zy2nOCaxg==", + "dependencies": { + "atomic-sleep": "^1.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-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/split-on-first": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz", + "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "engines": { + "node": ">= 10.x" + } + }, + "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/stream-chain": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/stream-chain/-/stream-chain-2.2.5.tgz", + "integrity": "sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA==" + }, + "node_modules/stream-json": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/stream-json/-/stream-json-1.9.1.tgz", + "integrity": "sha512-uWkjJ+2Nt/LO9Z/JyKZbMusL8Dkh97uUBTv3AJQ74y07lVahLY4eEFsPsE97pxYBwr8nnjMAIch5eqI0gPShyw==", + "dependencies": { + "stream-chain": "^2.2.5" + } + }, + "node_modules/stream-shift": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", + "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==" + }, + "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/streamx": { + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.22.0.tgz", + "integrity": "sha512-sLh1evHOzBy/iWRiR6d1zRcLao4gGZr3C1kzNz4fopCOKJb6xD9ub8Mpi9Mr1R6id5o43S+d93fI48UC5uM9aw==", + "dependencies": { + "fast-fifo": "^1.3.2", + "text-decoder": "^1.1.0" + }, + "optionalDependencies": { + "bare-events": "^2.2.0" + } + }, + "node_modules/strict-uri-encode": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", + "integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==", + "engines": { + "node": ">=4" + } + }, + "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_decoder/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/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": { + "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.prototype.trim": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "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/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-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==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strnum": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", + "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==" + }, + "node_modules/strtok3": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.3.0.tgz", + "integrity": "sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==", + "dependencies": { + "@tokenizer/token": "^0.3.0", + "peek-readable": "^4.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "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/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/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/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/synckit": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.2.tgz", + "integrity": "sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==", + "dev": true, + "dependencies": { + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/tar-fs": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.8.tgz", + "integrity": "sha512-ZoROL70jptorGAlgAYiLoBLItEKw/fUxg9BSYK/dF/GAGYFJOJJJMvjPAKDJraCXFwadD456FCuvLWgfhMsPwg==", + "dependencies": { + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + }, + "optionalDependencies": { + "bare-fs": "^4.0.1", + "bare-path": "^3.0.0" + } + }, + "node_modules/tar-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "node_modules/text-decoder": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz", + "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==", + "dependencies": { + "b4a": "^1.6.4" + } + }, + "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==" + }, + "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/thread-stream": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-2.7.0.tgz", + "integrity": "sha512-qQiRWsU/wvNolI6tbbCKd9iKaTnCXsTwVxhhKM6nctPdujTyztjlbUkUTUymidWcMnZ5pWR0ej4a0tjsW021vw==", + "dependencies": { + "real-require": "^0.2.0" + } + }, + "node_modules/through2": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "dependencies": { + "readable-stream": "3" + } + }, + "node_modules/timm": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/timm/-/timm-1.7.1.tgz", + "integrity": "sha512-IjZc9KIotudix8bMaBW6QvMuq64BrJWFs1+4V0lXwWGQZwH+LnX87doAYhem4caOEusRP9/g6jVDQmZ8XOk1nw==" + }, + "node_modules/tinycolor2": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz", + "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==" + }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==" + }, + "node_modules/tinyglobby": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.10.tgz", + "integrity": "sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew==", + "dependencies": { + "fdir": "^6.4.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.4.3", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.3.tgz", + "integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "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/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/token-types": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/token-types/-/token-types-4.2.1.tgz", + "integrity": "sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==", + "dependencies": { + "@tokenizer/token": "^0.3.0", + "ieee754": "^1.2.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/ts-api-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", + "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", + "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==", + "dev": true, + "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-dev": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ts-node-dev/-/ts-node-dev-2.0.0.tgz", + "integrity": "sha512-ywMrhCfH6M75yftYvrvNarLEY+SUXtUvU8/0Z6llrHQVBx12GiFk5sStF8UdfE/yfzk9IAq7O5EEbTQsxlBI8w==", + "dev": true, + "dependencies": { + "chokidar": "^3.5.1", + "dynamic-dedupe": "^0.3.0", + "minimist": "^1.2.6", + "mkdirp": "^1.0.4", + "resolve": "^1.0.0", + "rimraf": "^2.6.1", + "source-map-support": "^0.5.12", + "tree-kill": "^1.2.2", + "ts-node": "^10.4.0", + "tsconfig": "^7.0.0" + }, + "bin": { + "ts-node-dev": "lib/bin.js", + "tsnd": "lib/bin.js" + }, + "engines": { + "node": ">=0.8.0" + }, + "peerDependencies": { + "node-notifier": "*", + "typescript": "*" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/ts-node-dev/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/ts-node-dev/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/tsconfig": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz", + "integrity": "sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==", + "dev": true, + "dependencies": { + "@types/strip-bom": "^3.0.0", + "@types/strip-json-comments": "0.0.30", + "strip-bom": "^3.0.0", + "strip-json-comments": "^2.0.0" + } + }, + "node_modules/tsconfig-paths": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "dev": true, + "dependencies": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tsconfig/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" + }, + "node_modules/tsup": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/tsup/-/tsup-8.3.6.tgz", + "integrity": "sha512-XkVtlDV/58S9Ye0JxUUTcrQk4S+EqlOHKzg6Roa62rdjL1nGWNUstG0xgI4vanHdfIpjP448J8vlN0oK6XOJ5g==", + "dependencies": { + "bundle-require": "^5.0.0", + "cac": "^6.7.14", + "chokidar": "^4.0.1", + "consola": "^3.2.3", + "debug": "^4.3.7", + "esbuild": "^0.24.0", + "joycon": "^3.1.1", + "picocolors": "^1.1.1", + "postcss-load-config": "^6.0.1", + "resolve-from": "^5.0.0", + "rollup": "^4.24.0", + "source-map": "0.8.0-beta.0", + "sucrase": "^3.35.0", + "tinyexec": "^0.3.1", + "tinyglobby": "^0.2.9", + "tree-kill": "^1.2.2" + }, + "bin": { + "tsup": "dist/cli-default.js", + "tsup-node": "dist/cli-node.js" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@microsoft/api-extractor": "^7.36.0", + "@swc/core": "^1", + "postcss": "^8.4.12", + "typescript": ">=4.5.0" + }, + "peerDependenciesMeta": { + "@microsoft/api-extractor": { + "optional": true + }, + "@swc/core": { + "optional": true + }, + "postcss": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/tsup/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/tsup/node_modules/readdirp": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.1.tgz", + "integrity": "sha512-h80JrZu/MHUZCyHu5ciuoI0+WxsCxzxJTILn6Fs8rxSnFPh+UVHYfeIxK1nVGugMqkfC4vJcBOYbkfkwYK0+gw==", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/tsup/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/tsup/node_modules/source-map": { + "version": "0.8.0-beta.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", + "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", + "dependencies": { + "whatwg-url": "^7.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tsup/node_modules/tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/tsup/node_modules/webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" + }, + "node_modules/tsup/node_modules/whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "dependencies": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" + }, + "node_modules/tweetnacl-util": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz", + "integrity": "sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==" + }, + "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==", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "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==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" + }, + "node_modules/typescript": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", + "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha512-kbailJa29QrtXnxgq+DdCEGlbTeYM2eJUxsz6vjZavrCYPMIFHMKQmSKYAIuUK2i7hgPm28a8piX5NTUtM/LKQ==", + "dependencies": { + "punycode": "1.3.2", + "querystring": "0.2.0" + } + }, + "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/url/node_modules/punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==" + }, + "node_modules/utif": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/utif/-/utif-2.0.1.tgz", + "integrity": "sha512-Z/S1fNKCicQTf375lIP9G8Sa1H/phcysstNrrSdZKj1f9g58J4NMgb5IgiEZN9/nLMPDwF0W7hdOe9Qq2IYoLg==", + "dependencies": { + "pako": "^1.0.5" + } + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "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/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "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/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==", + "dev": true + }, + "node_modules/validator": { + "version": "13.12.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.12.0.tgz", + "integrity": "sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/web-encoding": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/web-encoding/-/web-encoding-1.1.5.tgz", + "integrity": "sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==", + "dependencies": { + "util": "^0.12.3" + }, + "optionalDependencies": { + "@zxing/text-encoding": "0.9.0" + } + }, + "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/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/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/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.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "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-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==" + }, + "node_modules/which-typed-array": { + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.18.tgz", + "integrity": "sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA==", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "engines": { + "node": ">=0.10.0" + } + }, + "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/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/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "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/xhr": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.6.0.tgz", + "integrity": "sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA==", + "dependencies": { + "global": "~4.4.0", + "is-function": "^1.0.1", + "parse-headers": "^2.0.0", + "xtend": "^4.0.0" + } + }, + "node_modules/xml-parse-from-string": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/xml-parse-from-string/-/xml-parse-from-string-1.0.1.tgz", + "integrity": "sha512-ErcKwJTF54uRzzNMXq2X5sMIy88zJvfN2DmdoQvy7PAFJ+tPRU6ydWuOKNMyfmOjdyBQTFREi60s0Y0SyI0G0g==" + }, + "node_modules/xml2js": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", + "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/xmlhttprequest-ssl": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz", + "integrity": "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "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": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "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/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "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==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/package.json b/package.json index b6f78480..7e948028 100644 --- a/package.json +++ b/package.json @@ -1,15 +1,23 @@ { "name": "evolution-api", - "version": "1.8.0", + "version": "2.2.3", "description": "Rest api for communication with WhatsApp", - "main": "./dist/src/main.js", + "main": "./dist/main.js", + "type": "commonjs", "scripts": { - "build": "tsc", - "start": "ts-node --files --transpile-only ./src/main.ts", - "start:prod": "bash start.sh", - "dev:server": "clear && tsnd --files --transpile-only --respawn --ignore-watch node_modules ./src/main.ts", - "test": "clear && tsnd --files --transpile-only --respawn --ignore-watch node_modules ./test/all.test.ts", - "lint": "eslint --fix --ext .ts src" + "build": "tsc --noEmit && tsup", + "start": "tsnd -r tsconfig-paths/register --files --transpile-only ./src/main.ts", + "start:prod": "node dist/main", + "dev:server": "tsnd -r tsconfig-paths/register --files --transpile-only --respawn --ignore-watch node_modules ./src/main.ts", + "test": "tsnd -r tsconfig-paths/register --files --transpile-only --respawn --ignore-watch node_modules ./test/all.test.ts", + "lint": "eslint --fix --ext .ts src", + "lint:check": "eslint --ext .ts src", + "db:generate": "node runWithProvider.js \"npx prisma generate --schema ./prisma/DATABASE_PROVIDER-schema.prisma\"", + "db:deploy": "node runWithProvider.js \"rm -rf ./prisma/migrations && cp -r ./prisma/DATABASE_PROVIDER-migrations ./prisma/migrations && npx prisma migrate deploy --schema ./prisma/DATABASE_PROVIDER-schema.prisma\"", + "db:deploy:win": "node runWithProvider.js \"xcopy /E /I prisma\\DATABASE_PROVIDER-migrations prisma\\migrations && npx prisma migrate deploy --schema prisma\\DATABASE_PROVIDER-schema.prisma\"", + "db:studio": "node runWithProvider.js \"npx prisma studio --schema ./prisma/DATABASE_PROVIDER-schema.prisma\"", + "db:migrate:dev": "node runWithProvider.js \"rm -rf ./prisma/migrations && cp -r ./prisma/DATABASE_PROVIDER-migrations ./prisma/migrations && npx prisma migrate dev --schema ./prisma/DATABASE_PROVIDER-schema.prisma && cp -r ./prisma/migrations/* ./prisma/DATABASE_PROVIDER-migrations\"", + "db:migrate:dev:win": "node runWithProvider.js \"xcopy /E /I prisma\\DATABASE_PROVIDER-migrations prisma\\migrations && npx prisma migrate dev --schema prisma\\DATABASE_PROVIDER-schema.prisma\"" }, "repository": { "type": "git", @@ -33,84 +41,84 @@ ], "author": { "name": "Davidson Gomes", - "email": "contato@agenciadgcode.com" + "email": "contato@atendai.com" }, - "license": "GPL-3.0", + "license": "Apache-2.0", "bugs": { "url": "https://github.com/EvolutionAPI/evolution-api/issues" }, "homepage": "https://github.com/EvolutionAPI/evolution-api#readme", "dependencies": { "@adiwajshing/keyed-db": "^0.2.4", + "@aws-sdk/client-sqs": "^3.723.0", "@ffmpeg-installer/ffmpeg": "^1.1.0", "@figuro/chatwoot-sdk": "^1.1.16", "@hapi/boom": "^10.0.1", - "@sentry/node": "^7.59.2", - "amqplib": "^0.10.3", - "@aws-sdk/client-sqs": "^3.569.0", - "axios": "^1.6.5", - "@whiskeysockets/baileys": "^6.7.2", + "@paralleldrive/cuid2": "^2.2.2", + "@prisma/client": "^6.1.0", + "@sentry/node": "^8.47.0", + "amqplib": "^0.10.5", + "axios": "^1.7.9", + "baileys": "github:EvolutionAPI/Baileys", "class-validator": "^0.14.1", - "compression": "^1.7.4", + "compression": "^1.7.5", "cors": "^2.8.5", - "cross-env": "^7.0.3", - "dayjs": "^1.11.7", + "dayjs": "^1.11.13", + "dotenv": "^16.4.7", "eventemitter2": "^6.4.9", - "evolution-manager": "^0.4.13", - "exiftool-vendored": "^22.0.0", - "express": "^4.18.2", + "express": "^4.21.2", "express-async-errors": "^3.1.1", - "fluent-ffmpeg": "^2.1.2", - "form-data": "^4.0.0", - "hbs": "^4.2.0", - "https-proxy-agent": "^7.0.2", + "fluent-ffmpeg": "^2.1.3", + "form-data": "^4.0.1", + "https-proxy-agent": "^7.0.6", "i18next": "^23.7.19", "jimp": "^0.16.13", - "join": "^3.0.0", - "js-yaml": "^4.1.0", + "json-schema": "^0.4.0", "jsonschema": "^1.4.1", - "jsonwebtoken": "^9.0.2", - "libphonenumber-js": "^1.10.39", - "link-preview-js": "^3.0.4", - "mongoose": "^6.10.5", + "link-preview-js": "^3.0.13", + "long": "^5.2.3", + "mediainfo.js": "^0.3.4", + "mime": "^4.0.0", + "mime-types": "^2.1.35", + "minio": "^8.0.3", + "multer": "^1.4.5-lts.1", "node-cache": "^5.1.2", - "node-mime-types": "^1.1.0", - "node-windows": "^1.0.0-beta.8", - "parse-bmfont-xml": "^1.1.4", - "pg": "^8.11.3", + "node-cron": "^3.0.3", + "openai": "^4.77.3", + "pg": "^8.13.1", "pino": "^8.11.0", - "qrcode": "^1.5.1", + "prisma": "^6.1.0", + "pusher": "^5.2.0", + "qrcode": "^1.5.4", "qrcode-terminal": "^0.12.0", - "redis": "^4.6.5", - "sharp": "^0.32.2", - "socket.io": "^4.7.1", - "socks-proxy-agent": "^8.0.1", - "swagger-ui-express": "^5.0.0", - "uuid": "^9.0.0", - "xml2js": "^0.6.2", - "yamljs": "^0.3.0" + "redis": "^4.7.0", + "sharp": "^0.32.6", + "socket.io": "^4.8.1", + "socket.io-client": "^4.8.1", + "tsup": "^8.3.5" }, "devDependencies": { - "@types/compression": "^1.7.2", - "@types/cors": "^2.8.13", - "@types/express": "^4.17.17", - "@types/js-yaml": "^4.0.5", - "@types/jsonwebtoken": "^8.5.9", - "@types/mime-types": "^2.1.1", - "@types/node": "^18.15.11", - "@types/node-windows": "^0.1.2", - "@types/qrcode": "^1.5.0", - "@types/qrcode-terminal": "^0.12.0", - "@types/uuid": "^8.3.4", - "@typescript-eslint/eslint-plugin": "^5.62.0", - "@typescript-eslint/parser": "^5.62.0", + "@types/compression": "^1.7.5", + "@types/cors": "^2.8.17", + "@types/express": "^4.17.18", + "@types/json-schema": "^7.0.15", + "@types/mime": "^4.0.0", + "@types/mime-types": "^2.1.4", + "@types/node": "^22.10.5", + "@types/node-cron": "^3.0.11", + "@types/qrcode": "^1.5.5", + "@types/qrcode-terminal": "^0.12.2", + "@types/uuid": "^10.0.0", + "@typescript-eslint/eslint-plugin": "^6.21.0", + "@typescript-eslint/parser": "^6.21.0", "eslint": "^8.45.0", - "eslint-config-prettier": "^8.8.0", - "eslint-plugin-import": "^2.27.5", - "eslint-plugin-prettier": "^4.2.1", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-import": "^2.31.0", + "eslint-plugin-prettier": "^5.2.1", "eslint-plugin-simple-import-sort": "^10.0.0", - "prettier": "^2.8.8", + "prettier": "^3.4.2", "ts-node-dev": "^2.0.0", - "typescript": "^4.9.5" + "tsconfig-paths": "^4.2.0", + "typescript": "^5.7.2" } } diff --git a/prisma/mysql-migrations/20240809105427_init/migration.sql b/prisma/mysql-migrations/20240809105427_init/migration.sql new file mode 100644 index 00000000..096aebb0 --- /dev/null +++ b/prisma/mysql-migrations/20240809105427_init/migration.sql @@ -0,0 +1,588 @@ +-- CreateTable +CREATE TABLE `Instance` ( + `id` VARCHAR(191) NOT NULL, + `name` VARCHAR(255) NOT NULL, + `connectionStatus` ENUM('open', 'close', 'connecting') NOT NULL DEFAULT 'open', + `ownerJid` VARCHAR(100) NULL, + `profileName` VARCHAR(100) NULL, + `profilePicUrl` VARCHAR(500) NULL, + `integration` VARCHAR(100) NULL, + `number` VARCHAR(100) NULL, + `businessId` VARCHAR(100) NULL, + `token` VARCHAR(255) NULL, + `clientName` VARCHAR(100) NULL, + `disconnectionReasonCode` INTEGER NULL, + `disconnectionObject` JSON NULL, + `disconnectionAt` TIMESTAMP NULL, + `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + `updatedAt` TIMESTAMP NULL, + + UNIQUE INDEX `Instance_name_key`(`name`), + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `Session` ( + `id` VARCHAR(191) NOT NULL, + `sessionId` VARCHAR(191) NOT NULL, + `creds` TEXT NULL, + `createdAt` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + + UNIQUE INDEX `Session_sessionId_key`(`sessionId`), + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `Chat` ( + `id` VARCHAR(191) NOT NULL, + `remoteJid` VARCHAR(100) NOT NULL, + `labels` JSON NULL, + `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + `updatedAt` TIMESTAMP NULL, + `instanceId` VARCHAR(191) NOT NULL, + + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `Contact` ( + `id` VARCHAR(191) NOT NULL, + `remoteJid` VARCHAR(100) NOT NULL, + `pushName` VARCHAR(100) NULL, + `profilePicUrl` VARCHAR(500) NULL, + `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + `updatedAt` TIMESTAMP NULL, + `instanceId` VARCHAR(191) NOT NULL, + + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `Message` ( + `id` VARCHAR(191) NOT NULL, + `key` JSON NOT NULL, + `pushName` VARCHAR(100) NULL, + `participant` VARCHAR(100) NULL, + `messageType` VARCHAR(100) NOT NULL, + `message` JSON NOT NULL, + `contextInfo` JSON NULL, + `source` ENUM('ios', 'android', 'web', 'unknown', 'desktop') NOT NULL, + `messageTimestamp` INTEGER NOT NULL, + `chatwootMessageId` INTEGER NULL, + `chatwootInboxId` INTEGER NULL, + `chatwootConversationId` INTEGER NULL, + `chatwootContactInboxSourceId` VARCHAR(100) NULL, + `chatwootIsRead` BOOLEAN NULL DEFAULT false, + `instanceId` VARCHAR(191) NOT NULL, + `typebotSessionId` VARCHAR(191) NULL, + `openaiSessionId` VARCHAR(191) NULL, + `webhookUrl` VARCHAR(500) NULL, + `difySessionId` VARCHAR(191) NULL, + + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `MessageUpdate` ( + `id` VARCHAR(191) NOT NULL, + `keyId` VARCHAR(100) NOT NULL, + `remoteJid` VARCHAR(100) NOT NULL, + `fromMe` BOOLEAN NOT NULL, + `participant` VARCHAR(100) NULL, + `pollUpdates` JSON NULL, + `status` VARCHAR(30) NOT NULL, + `messageId` VARCHAR(191) NOT NULL, + `instanceId` VARCHAR(191) NOT NULL, + + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `Webhook` ( + `id` VARCHAR(191) NOT NULL, + `url` VARCHAR(500) NOT NULL, + `enabled` BOOLEAN NULL DEFAULT true, + `events` JSON NULL, + `webhookByEvents` BOOLEAN NULL DEFAULT false, + `webhookBase64` BOOLEAN NULL DEFAULT false, + `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + `updatedAt` TIMESTAMP NOT NULL, + `instanceId` VARCHAR(191) NOT NULL, + + UNIQUE INDEX `Webhook_instanceId_key`(`instanceId`), + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `Chatwoot` ( + `id` VARCHAR(191) NOT NULL, + `enabled` BOOLEAN NULL DEFAULT true, + `accountId` VARCHAR(100) NULL, + `token` VARCHAR(100) NULL, + `url` VARCHAR(500) NULL, + `nameInbox` VARCHAR(100) NULL, + `signMsg` BOOLEAN NULL DEFAULT false, + `signDelimiter` VARCHAR(100) NULL, + `number` VARCHAR(100) NULL, + `reopenConversation` BOOLEAN NULL DEFAULT false, + `conversationPending` BOOLEAN NULL DEFAULT false, + `mergeBrazilContacts` BOOLEAN NULL DEFAULT false, + `importContacts` BOOLEAN NULL DEFAULT false, + `importMessages` BOOLEAN NULL DEFAULT false, + `daysLimitImportMessages` INTEGER NULL, + `organization` VARCHAR(100) NULL, + `logo` VARCHAR(500) NULL, + `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + `updatedAt` TIMESTAMP NOT NULL, + `instanceId` VARCHAR(191) NOT NULL, + + UNIQUE INDEX `Chatwoot_instanceId_key`(`instanceId`), + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `Label` ( + `id` VARCHAR(191) NOT NULL, + `labelId` VARCHAR(100) NULL, + `name` VARCHAR(100) NOT NULL, + `color` VARCHAR(100) NOT NULL, + `predefinedId` VARCHAR(100) NULL, + `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + `updatedAt` TIMESTAMP NOT NULL, + `instanceId` VARCHAR(191) NOT NULL, + + UNIQUE INDEX `Label_labelId_key`(`labelId`), + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `Proxy` ( + `id` VARCHAR(191) NOT NULL, + `enabled` BOOLEAN NOT NULL DEFAULT false, + `host` VARCHAR(100) NOT NULL, + `port` VARCHAR(100) NOT NULL, + `protocol` VARCHAR(100) NOT NULL, + `username` VARCHAR(100) NOT NULL, + `password` VARCHAR(100) NOT NULL, + `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + `updatedAt` TIMESTAMP NOT NULL, + `instanceId` VARCHAR(191) NOT NULL, + + UNIQUE INDEX `Proxy_instanceId_key`(`instanceId`), + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `Setting` ( + `id` VARCHAR(191) NOT NULL, + `rejectCall` BOOLEAN NOT NULL DEFAULT false, + `msgCall` VARCHAR(100) NULL, + `groupsIgnore` BOOLEAN NOT NULL DEFAULT false, + `alwaysOnline` BOOLEAN NOT NULL DEFAULT false, + `readMessages` BOOLEAN NOT NULL DEFAULT false, + `readStatus` BOOLEAN NOT NULL DEFAULT false, + `syncFullHistory` BOOLEAN NOT NULL DEFAULT false, + `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + `updatedAt` TIMESTAMP NOT NULL, + `instanceId` VARCHAR(191) NOT NULL, + + UNIQUE INDEX `Setting_instanceId_key`(`instanceId`), + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `Rabbitmq` ( + `id` VARCHAR(191) NOT NULL, + `enabled` BOOLEAN NOT NULL DEFAULT false, + `events` JSON NOT NULL, + `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + `updatedAt` TIMESTAMP NOT NULL, + `instanceId` VARCHAR(191) NOT NULL, + + UNIQUE INDEX `Rabbitmq_instanceId_key`(`instanceId`), + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `Sqs` ( + `id` VARCHAR(191) NOT NULL, + `enabled` BOOLEAN NOT NULL DEFAULT false, + `events` JSON NOT NULL, + `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + `updatedAt` TIMESTAMP NOT NULL, + `instanceId` VARCHAR(191) NOT NULL, + + UNIQUE INDEX `Sqs_instanceId_key`(`instanceId`), + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `Websocket` ( + `id` VARCHAR(191) NOT NULL, + `enabled` BOOLEAN NOT NULL DEFAULT false, + `events` JSON NOT NULL, + `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + `updatedAt` TIMESTAMP NOT NULL, + `instanceId` VARCHAR(191) NOT NULL, + + UNIQUE INDEX `Websocket_instanceId_key`(`instanceId`), + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `Typebot` ( + `id` VARCHAR(191) NOT NULL, + `enabled` BOOLEAN NOT NULL DEFAULT true, + `description` VARCHAR(255) NULL, + `url` VARCHAR(500) NOT NULL, + `typebot` VARCHAR(100) NOT NULL, + `expire` INTEGER NULL DEFAULT 0, + `keywordFinish` VARCHAR(100) NULL, + `delayMessage` INTEGER NULL, + `unknownMessage` VARCHAR(100) NULL, + `listeningFromMe` BOOLEAN NULL DEFAULT false, + `stopBotFromMe` BOOLEAN NULL DEFAULT false, + `keepOpen` BOOLEAN NULL DEFAULT false, + `debounceTime` INTEGER NULL, + `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + `updatedAt` TIMESTAMP NULL, + `ignoreJids` JSON NULL, + `triggerType` ENUM('all', 'keyword', 'none') NULL, + `triggerOperator` ENUM('contains', 'equals', 'startsWith', 'endsWith', 'regex') NULL, + `triggerValue` VARCHAR(191) NULL, + `instanceId` VARCHAR(191) NOT NULL, + + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `TypebotSession` ( + `id` VARCHAR(191) NOT NULL, + `remoteJid` VARCHAR(100) NOT NULL, + `pushName` VARCHAR(100) NULL, + `sessionId` VARCHAR(100) NOT NULL, + `status` ENUM('opened', 'closed', 'paused') NOT NULL, + `prefilledVariables` JSON NULL, + `awaitUser` BOOLEAN NOT NULL DEFAULT false, + `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + `updatedAt` TIMESTAMP NOT NULL, + `typebotId` VARCHAR(191) NOT NULL, + `instanceId` VARCHAR(191) NOT NULL, + + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `TypebotSetting` ( + `id` VARCHAR(191) NOT NULL, + `expire` INTEGER NULL DEFAULT 0, + `keywordFinish` VARCHAR(100) NULL, + `delayMessage` INTEGER NULL, + `unknownMessage` VARCHAR(100) NULL, + `listeningFromMe` BOOLEAN NULL DEFAULT false, + `stopBotFromMe` BOOLEAN NULL DEFAULT false, + `keepOpen` BOOLEAN NULL DEFAULT false, + `debounceTime` INTEGER NULL, + `typebotIdFallback` VARCHAR(100) NULL, + `ignoreJids` JSON NULL, + `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + `updatedAt` TIMESTAMP NOT NULL, + `instanceId` VARCHAR(191) NOT NULL, + + UNIQUE INDEX `TypebotSetting_instanceId_key`(`instanceId`), + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `Media` ( + `id` VARCHAR(191) NOT NULL, + `fileName` VARCHAR(500) NOT NULL, + `type` VARCHAR(100) NOT NULL, + `mimetype` VARCHAR(100) NOT NULL, + `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + `messageId` VARCHAR(191) NOT NULL, + `instanceId` VARCHAR(191) NOT NULL, + + UNIQUE INDEX `Media_fileName_key`(`fileName`), + UNIQUE INDEX `Media_messageId_key`(`messageId`), + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `OpenaiCreds` ( + `id` VARCHAR(191) NOT NULL, + `name` VARCHAR(255) NULL, + `apiKey` VARCHAR(255) NULL, + `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + `updatedAt` TIMESTAMP NOT NULL, + `instanceId` VARCHAR(191) NOT NULL, + + UNIQUE INDEX `OpenaiCreds_name_key`(`name`), + UNIQUE INDEX `OpenaiCreds_apiKey_key`(`apiKey`), + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `OpenaiBot` ( + `id` VARCHAR(191) NOT NULL, + `enabled` BOOLEAN NOT NULL DEFAULT true, + `description` VARCHAR(255) NULL, + `botType` ENUM('assistant', 'chatCompletion') NOT NULL, + `assistantId` VARCHAR(255) NULL, + `functionUrl` VARCHAR(500) NULL, + `model` VARCHAR(100) NULL, + `systemMessages` JSON NULL, + `assistantMessages` JSON NULL, + `userMessages` JSON NULL, + `maxTokens` INTEGER NULL, + `expire` INTEGER NULL DEFAULT 0, + `keywordFinish` VARCHAR(100) NULL, + `delayMessage` INTEGER NULL, + `unknownMessage` VARCHAR(100) NULL, + `listeningFromMe` BOOLEAN NULL DEFAULT false, + `stopBotFromMe` BOOLEAN NULL DEFAULT false, + `keepOpen` BOOLEAN NULL DEFAULT false, + `debounceTime` INTEGER NULL, + `ignoreJids` JSON NULL, + `triggerType` ENUM('all', 'keyword', 'none') NULL, + `triggerOperator` ENUM('contains', 'equals', 'startsWith', 'endsWith', 'regex') NULL, + `triggerValue` VARCHAR(191) NULL, + `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + `updatedAt` TIMESTAMP NOT NULL, + `openaiCredsId` VARCHAR(191) NOT NULL, + `instanceId` VARCHAR(191) NOT NULL, + + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `OpenaiSession` ( + `id` VARCHAR(191) NOT NULL, + `sessionId` VARCHAR(255) NOT NULL, + `remoteJid` VARCHAR(100) NOT NULL, + `status` ENUM('opened', 'closed', 'paused') NOT NULL, + `awaitUser` BOOLEAN NOT NULL DEFAULT false, + `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + `updatedAt` TIMESTAMP NOT NULL, + `openaiBotId` VARCHAR(191) NOT NULL, + `instanceId` VARCHAR(191) NOT NULL, + + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `OpenaiSetting` ( + `id` VARCHAR(191) NOT NULL, + `expire` INTEGER NULL DEFAULT 0, + `keywordFinish` VARCHAR(100) NULL, + `delayMessage` INTEGER NULL, + `unknownMessage` VARCHAR(100) NULL, + `listeningFromMe` BOOLEAN NULL DEFAULT false, + `stopBotFromMe` BOOLEAN NULL DEFAULT false, + `keepOpen` BOOLEAN NULL DEFAULT false, + `debounceTime` INTEGER NULL, + `ignoreJids` JSON NULL, + `speechToText` BOOLEAN NULL DEFAULT false, + `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + `updatedAt` TIMESTAMP NOT NULL, + `openaiCredsId` VARCHAR(191) NOT NULL, + `openaiIdFallback` VARCHAR(100) NULL, + `instanceId` VARCHAR(191) NOT NULL, + + UNIQUE INDEX `OpenaiSetting_openaiCredsId_key`(`openaiCredsId`), + UNIQUE INDEX `OpenaiSetting_instanceId_key`(`instanceId`), + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `Template` ( + `id` VARCHAR(191) NOT NULL, + `templateId` VARCHAR(255) NOT NULL, + `name` VARCHAR(255) NOT NULL, + `template` JSON NOT NULL, + `webhookUrl` VARCHAR(500) NULL, + `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + `updatedAt` TIMESTAMP NOT NULL, + `instanceId` VARCHAR(191) NOT NULL, + + UNIQUE INDEX `Template_templateId_key`(`templateId`), + UNIQUE INDEX `Template_name_key`(`name`), + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `Dify` ( + `id` VARCHAR(191) NOT NULL, + `enabled` BOOLEAN NOT NULL DEFAULT true, + `description` VARCHAR(255) NULL, + `botType` ENUM('chatBot', 'textGenerator', 'agent', 'workflow') NOT NULL, + `apiUrl` VARCHAR(255) NULL, + `apiKey` VARCHAR(255) NULL, + `expire` INTEGER NULL DEFAULT 0, + `keywordFinish` VARCHAR(100) NULL, + `delayMessage` INTEGER NULL, + `unknownMessage` VARCHAR(100) NULL, + `listeningFromMe` BOOLEAN NULL DEFAULT false, + `stopBotFromMe` BOOLEAN NULL DEFAULT false, + `keepOpen` BOOLEAN NULL DEFAULT false, + `debounceTime` INTEGER NULL, + `ignoreJids` JSON NULL, + `triggerType` ENUM('all', 'keyword', 'none') NULL, + `triggerOperator` ENUM('contains', 'equals', 'startsWith', 'endsWith', 'regex') NULL, + `triggerValue` VARCHAR(191) NULL, + `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + `updatedAt` TIMESTAMP NOT NULL, + `instanceId` VARCHAR(191) NOT NULL, + + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `DifySession` ( + `id` VARCHAR(191) NOT NULL, + `sessionId` VARCHAR(255) NOT NULL, + `remoteJid` VARCHAR(100) NOT NULL, + `status` ENUM('opened', 'closed', 'paused') NOT NULL, + `awaitUser` BOOLEAN NOT NULL DEFAULT false, + `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + `updatedAt` TIMESTAMP NOT NULL, + `difyId` VARCHAR(191) NOT NULL, + `instanceId` VARCHAR(191) NOT NULL, + + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `DifySetting` ( + `id` VARCHAR(191) NOT NULL, + `expire` INTEGER NULL DEFAULT 0, + `keywordFinish` VARCHAR(100) NULL, + `delayMessage` INTEGER NULL, + `unknownMessage` VARCHAR(100) NULL, + `listeningFromMe` BOOLEAN NULL DEFAULT false, + `stopBotFromMe` BOOLEAN NULL DEFAULT false, + `keepOpen` BOOLEAN NULL DEFAULT false, + `debounceTime` INTEGER NULL, + `ignoreJids` JSON NULL, + `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + `updatedAt` TIMESTAMP NOT NULL, + `difyIdFallback` VARCHAR(100) NULL, + `instanceId` VARCHAR(191) NOT NULL, + + UNIQUE INDEX `DifySetting_instanceId_key`(`instanceId`), + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- AddForeignKey +ALTER TABLE `Session` ADD CONSTRAINT `Session_sessionId_fkey` FOREIGN KEY (`sessionId`) REFERENCES `Instance`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `Chat` ADD CONSTRAINT `Chat_instanceId_fkey` FOREIGN KEY (`instanceId`) REFERENCES `Instance`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `Contact` ADD CONSTRAINT `Contact_instanceId_fkey` FOREIGN KEY (`instanceId`) REFERENCES `Instance`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `Message` ADD CONSTRAINT `Message_instanceId_fkey` FOREIGN KEY (`instanceId`) REFERENCES `Instance`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `Message` ADD CONSTRAINT `Message_typebotSessionId_fkey` FOREIGN KEY (`typebotSessionId`) REFERENCES `TypebotSession`(`id`) ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `Message` ADD CONSTRAINT `Message_openaiSessionId_fkey` FOREIGN KEY (`openaiSessionId`) REFERENCES `OpenaiSession`(`id`) ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `Message` ADD CONSTRAINT `Message_difySessionId_fkey` FOREIGN KEY (`difySessionId`) REFERENCES `DifySession`(`id`) ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `MessageUpdate` ADD CONSTRAINT `MessageUpdate_messageId_fkey` FOREIGN KEY (`messageId`) REFERENCES `Message`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `MessageUpdate` ADD CONSTRAINT `MessageUpdate_instanceId_fkey` FOREIGN KEY (`instanceId`) REFERENCES `Instance`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `Webhook` ADD CONSTRAINT `Webhook_instanceId_fkey` FOREIGN KEY (`instanceId`) REFERENCES `Instance`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `Chatwoot` ADD CONSTRAINT `Chatwoot_instanceId_fkey` FOREIGN KEY (`instanceId`) REFERENCES `Instance`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `Label` ADD CONSTRAINT `Label_instanceId_fkey` FOREIGN KEY (`instanceId`) REFERENCES `Instance`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `Proxy` ADD CONSTRAINT `Proxy_instanceId_fkey` FOREIGN KEY (`instanceId`) REFERENCES `Instance`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `Setting` ADD CONSTRAINT `Setting_instanceId_fkey` FOREIGN KEY (`instanceId`) REFERENCES `Instance`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `Rabbitmq` ADD CONSTRAINT `Rabbitmq_instanceId_fkey` FOREIGN KEY (`instanceId`) REFERENCES `Instance`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `Sqs` ADD CONSTRAINT `Sqs_instanceId_fkey` FOREIGN KEY (`instanceId`) REFERENCES `Instance`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `Websocket` ADD CONSTRAINT `Websocket_instanceId_fkey` FOREIGN KEY (`instanceId`) REFERENCES `Instance`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `Typebot` ADD CONSTRAINT `Typebot_instanceId_fkey` FOREIGN KEY (`instanceId`) REFERENCES `Instance`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `TypebotSession` ADD CONSTRAINT `TypebotSession_typebotId_fkey` FOREIGN KEY (`typebotId`) REFERENCES `Typebot`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `TypebotSession` ADD CONSTRAINT `TypebotSession_instanceId_fkey` FOREIGN KEY (`instanceId`) REFERENCES `Instance`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `TypebotSetting` ADD CONSTRAINT `TypebotSetting_typebotIdFallback_fkey` FOREIGN KEY (`typebotIdFallback`) REFERENCES `Typebot`(`id`) ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `TypebotSetting` ADD CONSTRAINT `TypebotSetting_instanceId_fkey` FOREIGN KEY (`instanceId`) REFERENCES `Instance`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `Media` ADD CONSTRAINT `Media_messageId_fkey` FOREIGN KEY (`messageId`) REFERENCES `Message`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `Media` ADD CONSTRAINT `Media_instanceId_fkey` FOREIGN KEY (`instanceId`) REFERENCES `Instance`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `OpenaiCreds` ADD CONSTRAINT `OpenaiCreds_instanceId_fkey` FOREIGN KEY (`instanceId`) REFERENCES `Instance`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `OpenaiBot` ADD CONSTRAINT `OpenaiBot_openaiCredsId_fkey` FOREIGN KEY (`openaiCredsId`) REFERENCES `OpenaiCreds`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `OpenaiBot` ADD CONSTRAINT `OpenaiBot_instanceId_fkey` FOREIGN KEY (`instanceId`) REFERENCES `Instance`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `OpenaiSession` ADD CONSTRAINT `OpenaiSession_openaiBotId_fkey` FOREIGN KEY (`openaiBotId`) REFERENCES `OpenaiBot`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `OpenaiSession` ADD CONSTRAINT `OpenaiSession_instanceId_fkey` FOREIGN KEY (`instanceId`) REFERENCES `Instance`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `OpenaiSetting` ADD CONSTRAINT `OpenaiSetting_openaiCredsId_fkey` FOREIGN KEY (`openaiCredsId`) REFERENCES `OpenaiCreds`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `OpenaiSetting` ADD CONSTRAINT `OpenaiSetting_openaiIdFallback_fkey` FOREIGN KEY (`openaiIdFallback`) REFERENCES `OpenaiBot`(`id`) ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `OpenaiSetting` ADD CONSTRAINT `OpenaiSetting_instanceId_fkey` FOREIGN KEY (`instanceId`) REFERENCES `Instance`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `Template` ADD CONSTRAINT `Template_instanceId_fkey` FOREIGN KEY (`instanceId`) REFERENCES `Instance`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `Dify` ADD CONSTRAINT `Dify_instanceId_fkey` FOREIGN KEY (`instanceId`) REFERENCES `Instance`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `DifySession` ADD CONSTRAINT `DifySession_difyId_fkey` FOREIGN KEY (`difyId`) REFERENCES `Dify`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `DifySession` ADD CONSTRAINT `DifySession_instanceId_fkey` FOREIGN KEY (`instanceId`) REFERENCES `Instance`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `DifySetting` ADD CONSTRAINT `DifySetting_difyIdFallback_fkey` FOREIGN KEY (`difyIdFallback`) REFERENCES `Dify`(`id`) ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `DifySetting` ADD CONSTRAINT `DifySetting_instanceId_fkey` FOREIGN KEY (`instanceId`) REFERENCES `Instance`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/mysql-migrations/20240813153900_add_unique_index_for_remoted_jid_and_instance_in_contacts/migration.sql b/prisma/mysql-migrations/20240813153900_add_unique_index_for_remoted_jid_and_instance_in_contacts/migration.sql new file mode 100644 index 00000000..5765ce97 --- /dev/null +++ b/prisma/mysql-migrations/20240813153900_add_unique_index_for_remoted_jid_and_instance_in_contacts/migration.sql @@ -0,0 +1,173 @@ +/* +Warnings: +- You are about to alter the column `createdAt` on the `Chat` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `updatedAt` on the `Chat` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `createdAt` on the `Chatwoot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `updatedAt` on the `Chatwoot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `createdAt` on the `Contact` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `updatedAt` on the `Contact` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `createdAt` on the `Dify` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `updatedAt` on the `Dify` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `createdAt` on the `DifySession` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `updatedAt` on the `DifySession` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `createdAt` on the `DifySetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `updatedAt` on the `DifySetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `disconnectionAt` on the `Instance` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `createdAt` on the `Instance` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `updatedAt` on the `Instance` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `createdAt` on the `Label` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `updatedAt` on the `Label` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `createdAt` on the `Media` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `createdAt` on the `OpenaiBot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `updatedAt` on the `OpenaiBot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `createdAt` on the `OpenaiCreds` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `updatedAt` on the `OpenaiCreds` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `createdAt` on the `OpenaiSession` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `updatedAt` on the `OpenaiSession` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `createdAt` on the `OpenaiSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `updatedAt` on the `OpenaiSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `createdAt` on the `Proxy` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `updatedAt` on the `Proxy` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `createdAt` on the `Rabbitmq` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `updatedAt` on the `Rabbitmq` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `createdAt` on the `Session` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `createdAt` on the `Setting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `updatedAt` on the `Setting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `createdAt` on the `Sqs` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `updatedAt` on the `Sqs` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `createdAt` on the `Template` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `updatedAt` on the `Template` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `createdAt` on the `Typebot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `updatedAt` on the `Typebot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `createdAt` on the `TypebotSession` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `updatedAt` on the `TypebotSession` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `createdAt` on the `TypebotSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `updatedAt` on the `TypebotSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `createdAt` on the `Webhook` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `updatedAt` on the `Webhook` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `createdAt` on the `Websocket` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- You are about to alter the column `updatedAt` on the `Websocket` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. +- A unique constraint covering the columns `[remoteJid,instanceId]` on the table `Contact` will be added. If there are existing duplicate values, this will fail. +*/ +-- AlterTable +ALTER TABLE `Chat` +ADD COLUMN `name` VARCHAR(100) NULL, +MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, +MODIFY `updatedAt` TIMESTAMP NULL; + +-- AlterTable +ALTER TABLE `Chatwoot` +MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, +MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Contact` +MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, +MODIFY `updatedAt` TIMESTAMP NULL; + +-- AlterTable +ALTER TABLE `Dify` +MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, +MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `DifySession` +MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, +MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `DifySetting` +MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, +MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Instance` +MODIFY `disconnectionAt` TIMESTAMP NULL, +MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, +MODIFY `updatedAt` TIMESTAMP NULL; + +-- AlterTable +ALTER TABLE `Label` +MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, +MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Media` +MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP; + +-- AlterTable +ALTER TABLE `OpenaiBot` +MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, +MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `OpenaiCreds` +MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, +MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `OpenaiSession` +MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, +MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `OpenaiSetting` +MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, +MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Proxy` +MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, +MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Rabbitmq` +MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, +MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Session` +MODIFY `createdAt` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP; + +-- AlterTable +ALTER TABLE `Setting` +MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, +MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Sqs` +MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, +MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Template` +MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, +MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Typebot` +MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, +MODIFY `updatedAt` TIMESTAMP NULL; + +-- AlterTable +ALTER TABLE `TypebotSession` +MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, +MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `TypebotSetting` +MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, +MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Webhook` +MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, +MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Websocket` +MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, +MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- CreateIndex +CREATE UNIQUE INDEX `Contact_remoteJid_instanceId_key` ON `Contact` (`remoteJid`, `instanceId`); \ No newline at end of file diff --git a/prisma/mysql-migrations/20240814173138_add_ignore_jids_chatwoot/migration.sql b/prisma/mysql-migrations/20240814173138_add_ignore_jids_chatwoot/migration.sql new file mode 100644 index 00000000..99a38e4c --- /dev/null +++ b/prisma/mysql-migrations/20240814173138_add_ignore_jids_chatwoot/migration.sql @@ -0,0 +1,150 @@ +/* + Warnings: + + - You are about to alter the column `createdAt` on the `Chat` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Chat` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Chatwoot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Chatwoot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Contact` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Contact` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Dify` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Dify` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `DifySession` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `DifySession` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `DifySetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `DifySetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `disconnectionAt` on the `Instance` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Instance` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Instance` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Label` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Label` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Media` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `OpenaiBot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `OpenaiBot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `OpenaiCreds` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `OpenaiCreds` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `OpenaiSession` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `OpenaiSession` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `OpenaiSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `OpenaiSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Proxy` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Proxy` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Rabbitmq` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Rabbitmq` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Session` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Setting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Setting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Sqs` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Sqs` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Template` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Template` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Typebot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Typebot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `TypebotSession` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `TypebotSession` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `TypebotSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `TypebotSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Webhook` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Webhook` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Websocket` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Websocket` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + +*/ +-- DropIndex +DROP INDEX `Label_labelId_key` ON `Label`; + +-- AlterTable +ALTER TABLE `Chat` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NULL; + +-- AlterTable +ALTER TABLE `Chatwoot` ADD COLUMN `ignoreJids` JSON NULL, + MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Contact` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NULL; + +-- AlterTable +ALTER TABLE `Dify` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `DifySession` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `DifySetting` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Instance` MODIFY `disconnectionAt` TIMESTAMP NULL, + MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NULL; + +-- AlterTable +ALTER TABLE `Label` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Media` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP; + +-- AlterTable +ALTER TABLE `OpenaiBot` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `OpenaiCreds` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `OpenaiSession` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `OpenaiSetting` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Proxy` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Rabbitmq` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Session` MODIFY `createdAt` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP; + +-- AlterTable +ALTER TABLE `Setting` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Sqs` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Template` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Typebot` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NULL; + +-- AlterTable +ALTER TABLE `TypebotSession` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `TypebotSetting` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Webhook` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Websocket` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; diff --git a/prisma/mysql-migrations/20240814214314_integrations_unification/migration.sql b/prisma/mysql-migrations/20240814214314_integrations_unification/migration.sql new file mode 100644 index 00000000..30b455ce --- /dev/null +++ b/prisma/mysql-migrations/20240814214314_integrations_unification/migration.sql @@ -0,0 +1,208 @@ +/* + Warnings: + + - You are about to alter the column `createdAt` on the `Chat` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Chat` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Chatwoot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Chatwoot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Contact` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Contact` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Dify` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Dify` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `DifySetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `DifySetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `disconnectionAt` on the `Instance` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Instance` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Instance` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Label` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Label` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Media` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to drop the column `difySessionId` on the `Message` table. All the data in the column will be lost. + - You are about to drop the column `openaiSessionId` on the `Message` table. All the data in the column will be lost. + - You are about to alter the column `createdAt` on the `OpenaiBot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `OpenaiBot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `OpenaiCreds` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `OpenaiCreds` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `OpenaiSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `OpenaiSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Proxy` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Proxy` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Rabbitmq` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Rabbitmq` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Session` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Setting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Setting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Sqs` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Sqs` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Template` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Template` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Typebot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Typebot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `TypebotSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `TypebotSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Webhook` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Webhook` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Websocket` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Websocket` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to drop the `DifySession` table. If the table is not empty, all the data it contains will be lost. + - You are about to drop the `OpenaiSession` table. If the table is not empty, all the data it contains will be lost. + - You are about to drop the `TypebotSession` table. If the table is not empty, all the data it contains will be lost. + +*/ +-- DropForeignKey +ALTER TABLE `DifySession` DROP FOREIGN KEY `DifySession_difyId_fkey`; + +-- DropForeignKey +ALTER TABLE `DifySession` DROP FOREIGN KEY `DifySession_instanceId_fkey`; + +-- DropForeignKey +ALTER TABLE `Message` DROP FOREIGN KEY `Message_difySessionId_fkey`; + +-- DropForeignKey +ALTER TABLE `Message` DROP FOREIGN KEY `Message_openaiSessionId_fkey`; + +-- DropForeignKey +ALTER TABLE `Message` DROP FOREIGN KEY `Message_typebotSessionId_fkey`; + +-- DropForeignKey +ALTER TABLE `OpenaiSession` DROP FOREIGN KEY `OpenaiSession_instanceId_fkey`; + +-- DropForeignKey +ALTER TABLE `OpenaiSession` DROP FOREIGN KEY `OpenaiSession_openaiBotId_fkey`; + +-- DropForeignKey +ALTER TABLE `TypebotSession` DROP FOREIGN KEY `TypebotSession_instanceId_fkey`; + +-- DropForeignKey +ALTER TABLE `TypebotSession` DROP FOREIGN KEY `TypebotSession_typebotId_fkey`; + +-- AlterTable +ALTER TABLE `Chat` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NULL; + +-- AlterTable +ALTER TABLE `Chatwoot` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Contact` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NULL; + +-- AlterTable +ALTER TABLE `Dify` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `DifySetting` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Instance` MODIFY `disconnectionAt` TIMESTAMP NULL, + MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NULL; + +-- AlterTable +ALTER TABLE `Label` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Media` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP; + +-- AlterTable +ALTER TABLE `Message` DROP COLUMN `difySessionId`, + DROP COLUMN `openaiSessionId`, + ADD COLUMN `sessionId` VARCHAR(191) NULL; + +-- AlterTable +ALTER TABLE `OpenaiBot` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `OpenaiCreds` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `OpenaiSetting` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Proxy` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Rabbitmq` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Session` MODIFY `createdAt` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP; + +-- AlterTable +ALTER TABLE `Setting` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Sqs` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Template` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Typebot` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NULL; + +-- AlterTable +ALTER TABLE `TypebotSetting` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Webhook` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Websocket` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- DropTable +DROP TABLE `DifySession`; + +-- DropTable +DROP TABLE `OpenaiSession`; + +-- DropTable +DROP TABLE `TypebotSession`; + +-- CreateTable +CREATE TABLE `IntegrationSession` ( + `id` VARCHAR(191) NOT NULL, + `sessionId` VARCHAR(255) NOT NULL, + `remoteJid` VARCHAR(100) NOT NULL, + `pushName` VARCHAR(191) NULL, + `status` ENUM('opened', 'closed', 'paused') NOT NULL, + `awaitUser` BOOLEAN NOT NULL DEFAULT false, + `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + `updatedAt` TIMESTAMP NOT NULL, + `instanceId` VARCHAR(191) NOT NULL, + `parameters` JSON NULL, + `openaiBotId` VARCHAR(191) NULL, + `difyId` VARCHAR(191) NULL, + `typebotId` VARCHAR(191) NULL, + + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- AddForeignKey +ALTER TABLE `Message` ADD CONSTRAINT `Message_sessionId_fkey` FOREIGN KEY (`sessionId`) REFERENCES `IntegrationSession`(`id`) ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `IntegrationSession` ADD CONSTRAINT `IntegrationSession_instanceId_fkey` FOREIGN KEY (`instanceId`) REFERENCES `Instance`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `IntegrationSession` ADD CONSTRAINT `IntegrationSession_openaiBotId_fkey` FOREIGN KEY (`openaiBotId`) REFERENCES `OpenaiBot`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `IntegrationSession` ADD CONSTRAINT `IntegrationSession_difyId_fkey` FOREIGN KEY (`difyId`) REFERENCES `Dify`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `IntegrationSession` ADD CONSTRAINT `IntegrationSession_typebotId_fkey` FOREIGN KEY (`typebotId`) REFERENCES `Typebot`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/mysql-migrations/20240821203259_add_postgres_migrations/migration.sql b/prisma/mysql-migrations/20240821203259_add_postgres_migrations/migration.sql new file mode 100644 index 00000000..9c248d9c --- /dev/null +++ b/prisma/mysql-migrations/20240821203259_add_postgres_migrations/migration.sql @@ -0,0 +1,269 @@ +/* + Warnings: + + - You are about to alter the column `createdAt` on the `Chat` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Chat` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Chatwoot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Chatwoot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Contact` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Contact` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Dify` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Dify` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `DifySetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `DifySetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `disconnectionAt` on the `Instance` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Instance` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Instance` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to drop the column `difyId` on the `IntegrationSession` table. All the data in the column will be lost. + - You are about to drop the column `openaiBotId` on the `IntegrationSession` table. All the data in the column will be lost. + - You are about to drop the column `typebotId` on the `IntegrationSession` table. All the data in the column will be lost. + - You are about to alter the column `createdAt` on the `IntegrationSession` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `IntegrationSession` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Label` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Label` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Media` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `OpenaiBot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `OpenaiBot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `OpenaiCreds` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `OpenaiCreds` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `OpenaiSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `OpenaiSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Proxy` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Proxy` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Rabbitmq` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Rabbitmq` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Session` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Setting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Setting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Sqs` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Sqs` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Template` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Template` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Typebot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Typebot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `TypebotSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `TypebotSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Webhook` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Webhook` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Websocket` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Websocket` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + +*/ +-- DropForeignKey +ALTER TABLE `IntegrationSession` DROP FOREIGN KEY `IntegrationSession_difyId_fkey`; + +-- DropForeignKey +ALTER TABLE `IntegrationSession` DROP FOREIGN KEY `IntegrationSession_openaiBotId_fkey`; + +-- DropForeignKey +ALTER TABLE `IntegrationSession` DROP FOREIGN KEY `IntegrationSession_typebotId_fkey`; + +-- DropIndex +DROP INDEX `Message_typebotSessionId_fkey` ON `Message`; + +-- AlterTable +ALTER TABLE `Chat` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NULL; + +-- AlterTable +ALTER TABLE `Chatwoot` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Contact` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NULL; + +-- AlterTable +ALTER TABLE `Dify` MODIFY `triggerType` ENUM('all', 'keyword', 'none', 'advanced') NULL, + MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `DifySetting` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Instance` MODIFY `disconnectionAt` TIMESTAMP NULL, + MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NULL; + +-- AlterTable +ALTER TABLE `IntegrationSession` DROP COLUMN `difyId`, + DROP COLUMN `openaiBotId`, + DROP COLUMN `typebotId`, + ADD COLUMN `botId` VARCHAR(191) NULL, + ADD COLUMN `context` JSON NULL, + MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Label` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Media` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP; + +-- AlterTable +ALTER TABLE `OpenaiBot` MODIFY `triggerType` ENUM('all', 'keyword', 'none', 'advanced') NULL, + MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `OpenaiCreds` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `OpenaiSetting` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Proxy` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Rabbitmq` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Session` MODIFY `createdAt` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP; + +-- AlterTable +ALTER TABLE `Setting` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Sqs` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Template` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Typebot` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NULL, + MODIFY `triggerType` ENUM('all', 'keyword', 'none', 'advanced') NULL; + +-- AlterTable +ALTER TABLE `TypebotSetting` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Webhook` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Websocket` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- CreateTable +CREATE TABLE `GenericBot` ( + `id` VARCHAR(191) NOT NULL, + `enabled` BOOLEAN NOT NULL DEFAULT true, + `description` VARCHAR(255) NULL, + `apiUrl` VARCHAR(255) NULL, + `apiKey` VARCHAR(255) NULL, + `expire` INTEGER NULL DEFAULT 0, + `keywordFinish` VARCHAR(100) NULL, + `delayMessage` INTEGER NULL, + `unknownMessage` VARCHAR(100) NULL, + `listeningFromMe` BOOLEAN NULL DEFAULT false, + `stopBotFromMe` BOOLEAN NULL DEFAULT false, + `keepOpen` BOOLEAN NULL DEFAULT false, + `debounceTime` INTEGER NULL, + `ignoreJids` JSON NULL, + `triggerType` ENUM('all', 'keyword', 'none', 'advanced') NULL, + `triggerOperator` ENUM('contains', 'equals', 'startsWith', 'endsWith', 'regex') NULL, + `triggerValue` VARCHAR(191) NULL, + `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + `updatedAt` TIMESTAMP NOT NULL, + `instanceId` VARCHAR(191) NOT NULL, + + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `GenericSetting` ( + `id` VARCHAR(191) NOT NULL, + `expire` INTEGER NULL DEFAULT 0, + `keywordFinish` VARCHAR(100) NULL, + `delayMessage` INTEGER NULL, + `unknownMessage` VARCHAR(100) NULL, + `listeningFromMe` BOOLEAN NULL DEFAULT false, + `stopBotFromMe` BOOLEAN NULL DEFAULT false, + `keepOpen` BOOLEAN NULL DEFAULT false, + `debounceTime` INTEGER NULL, + `ignoreJids` JSON NULL, + `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + `updatedAt` TIMESTAMP NOT NULL, + `botIdFallback` VARCHAR(100) NULL, + `instanceId` VARCHAR(191) NOT NULL, + + UNIQUE INDEX `GenericSetting_instanceId_key`(`instanceId`), + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `Flowise` ( + `id` VARCHAR(191) NOT NULL, + `enabled` BOOLEAN NOT NULL DEFAULT true, + `description` VARCHAR(255) NULL, + `apiUrl` VARCHAR(255) NULL, + `apiKey` VARCHAR(255) NULL, + `expire` INTEGER NULL DEFAULT 0, + `keywordFinish` VARCHAR(100) NULL, + `delayMessage` INTEGER NULL, + `unknownMessage` VARCHAR(100) NULL, + `listeningFromMe` BOOLEAN NULL DEFAULT false, + `stopBotFromMe` BOOLEAN NULL DEFAULT false, + `keepOpen` BOOLEAN NULL DEFAULT false, + `debounceTime` INTEGER NULL, + `ignoreJids` JSON NULL, + `triggerType` ENUM('all', 'keyword', 'none', 'advanced') NULL, + `triggerOperator` ENUM('contains', 'equals', 'startsWith', 'endsWith', 'regex') NULL, + `triggerValue` VARCHAR(191) NULL, + `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + `updatedAt` TIMESTAMP NOT NULL, + `instanceId` VARCHAR(191) NOT NULL, + + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `FlowiseSetting` ( + `id` VARCHAR(191) NOT NULL, + `expire` INTEGER NULL DEFAULT 0, + `keywordFinish` VARCHAR(100) NULL, + `delayMessage` INTEGER NULL, + `unknownMessage` VARCHAR(100) NULL, + `listeningFromMe` BOOLEAN NULL DEFAULT false, + `stopBotFromMe` BOOLEAN NULL DEFAULT false, + `keepOpen` BOOLEAN NULL DEFAULT false, + `debounceTime` INTEGER NULL, + `ignoreJids` JSON NULL, + `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + `updatedAt` TIMESTAMP NOT NULL, + `flowiseIdFallback` VARCHAR(100) NULL, + `instanceId` VARCHAR(191) NOT NULL, + + UNIQUE INDEX `FlowiseSetting_instanceId_key`(`instanceId`), + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- AddForeignKey +ALTER TABLE `GenericBot` ADD CONSTRAINT `GenericBot_instanceId_fkey` FOREIGN KEY (`instanceId`) REFERENCES `Instance`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `GenericSetting` ADD CONSTRAINT `GenericSetting_botIdFallback_fkey` FOREIGN KEY (`botIdFallback`) REFERENCES `GenericBot`(`id`) ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `GenericSetting` ADD CONSTRAINT `GenericSetting_instanceId_fkey` FOREIGN KEY (`instanceId`) REFERENCES `Instance`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `Flowise` ADD CONSTRAINT `Flowise_instanceId_fkey` FOREIGN KEY (`instanceId`) REFERENCES `Instance`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `FlowiseSetting` ADD CONSTRAINT `FlowiseSetting_flowiseIdFallback_fkey` FOREIGN KEY (`flowiseIdFallback`) REFERENCES `Flowise`(`id`) ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `FlowiseSetting` ADD CONSTRAINT `FlowiseSetting_instanceId_fkey` FOREIGN KEY (`instanceId`) REFERENCES `Instance`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/mysql-migrations/20240824162012_add_type_on_integration_sessions/migration.sql b/prisma/mysql-migrations/20240824162012_add_type_on_integration_sessions/migration.sql new file mode 100644 index 00000000..5c08030c --- /dev/null +++ b/prisma/mysql-migrations/20240824162012_add_type_on_integration_sessions/migration.sql @@ -0,0 +1,159 @@ +/* + Warnings: + + - You are about to alter the column `createdAt` on the `Chat` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Chat` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Chatwoot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Chatwoot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Contact` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Contact` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Dify` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Dify` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `DifySetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `DifySetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Flowise` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Flowise` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `FlowiseSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `FlowiseSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `GenericBot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `GenericBot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `GenericSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `GenericSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `disconnectionAt` on the `Instance` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Instance` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Instance` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `IntegrationSession` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `IntegrationSession` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Label` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Label` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Media` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `OpenaiBot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `OpenaiBot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `OpenaiCreds` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `OpenaiCreds` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `OpenaiSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `OpenaiSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Proxy` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Proxy` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Rabbitmq` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Rabbitmq` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Session` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Setting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Setting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Sqs` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Sqs` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Template` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Template` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Typebot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Typebot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `TypebotSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `TypebotSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Webhook` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Webhook` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Websocket` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Websocket` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + +*/ +-- AlterTable +ALTER TABLE `Chat` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NULL; + +-- AlterTable +ALTER TABLE `Chatwoot` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Contact` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NULL; + +-- AlterTable +ALTER TABLE `Dify` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `DifySetting` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Flowise` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `FlowiseSetting` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `GenericBot` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `GenericSetting` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Instance` MODIFY `disconnectionAt` TIMESTAMP NULL, + MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NULL; + +-- AlterTable +ALTER TABLE `IntegrationSession` ADD COLUMN `type` VARCHAR(100) NULL, + MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Label` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Media` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP; + +-- AlterTable +ALTER TABLE `OpenaiBot` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `OpenaiCreds` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `OpenaiSetting` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Proxy` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Rabbitmq` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Session` MODIFY `createdAt` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP; + +-- AlterTable +ALTER TABLE `Setting` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Sqs` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Template` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Typebot` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NULL; + +-- AlterTable +ALTER TABLE `TypebotSetting` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Webhook` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Websocket` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; diff --git a/prisma/mysql-migrations/20240825131301_change_to_evolution_bot/migration.sql b/prisma/mysql-migrations/20240825131301_change_to_evolution_bot/migration.sql new file mode 100644 index 00000000..9a2d937c --- /dev/null +++ b/prisma/mysql-migrations/20240825131301_change_to_evolution_bot/migration.sql @@ -0,0 +1,219 @@ +/* + Warnings: + + - You are about to alter the column `createdAt` on the `Chat` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Chat` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Chatwoot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Chatwoot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Contact` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Contact` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Dify` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Dify` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `DifySetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `DifySetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Flowise` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Flowise` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `FlowiseSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `FlowiseSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `disconnectionAt` on the `Instance` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Instance` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Instance` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `IntegrationSession` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `IntegrationSession` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Label` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Label` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Media` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `OpenaiBot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `OpenaiBot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `OpenaiCreds` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `OpenaiCreds` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `OpenaiSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `OpenaiSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Proxy` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Proxy` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Rabbitmq` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Rabbitmq` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Session` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Setting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Setting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Sqs` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Sqs` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Template` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Template` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Typebot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Typebot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `TypebotSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `TypebotSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Webhook` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Webhook` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Websocket` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Websocket` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to drop the `GenericBot` table. If the table is not empty, all the data it contains will be lost. + - You are about to drop the `GenericSetting` table. If the table is not empty, all the data it contains will be lost. + +*/ +-- DropForeignKey +ALTER TABLE `GenericBot` DROP FOREIGN KEY `GenericBot_instanceId_fkey`; + +-- DropForeignKey +ALTER TABLE `GenericSetting` DROP FOREIGN KEY `GenericSetting_botIdFallback_fkey`; + +-- DropForeignKey +ALTER TABLE `GenericSetting` DROP FOREIGN KEY `GenericSetting_instanceId_fkey`; + +-- AlterTable +ALTER TABLE `Chat` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NULL; + +-- AlterTable +ALTER TABLE `Chatwoot` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Contact` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NULL; + +-- AlterTable +ALTER TABLE `Dify` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `DifySetting` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Flowise` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `FlowiseSetting` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Instance` MODIFY `disconnectionAt` TIMESTAMP NULL, + MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NULL; + +-- AlterTable +ALTER TABLE `IntegrationSession` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Label` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Media` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP; + +-- AlterTable +ALTER TABLE `OpenaiBot` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `OpenaiCreds` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `OpenaiSetting` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Proxy` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Rabbitmq` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Session` MODIFY `createdAt` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP; + +-- AlterTable +ALTER TABLE `Setting` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Sqs` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Template` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Typebot` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NULL; + +-- AlterTable +ALTER TABLE `TypebotSetting` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Webhook` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Websocket` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- DropTable +DROP TABLE `GenericBot`; + +-- DropTable +DROP TABLE `GenericSetting`; + +-- CreateTable +CREATE TABLE `EvolutionBot` ( + `id` VARCHAR(191) NOT NULL, + `enabled` BOOLEAN NOT NULL DEFAULT true, + `description` VARCHAR(255) NULL, + `apiUrl` VARCHAR(255) NULL, + `apiKey` VARCHAR(255) NULL, + `expire` INTEGER NULL DEFAULT 0, + `keywordFinish` VARCHAR(100) NULL, + `delayMessage` INTEGER NULL, + `unknownMessage` VARCHAR(100) NULL, + `listeningFromMe` BOOLEAN NULL DEFAULT false, + `stopBotFromMe` BOOLEAN NULL DEFAULT false, + `keepOpen` BOOLEAN NULL DEFAULT false, + `debounceTime` INTEGER NULL, + `ignoreJids` JSON NULL, + `triggerType` ENUM('all', 'keyword', 'none', 'advanced') NULL, + `triggerOperator` ENUM('contains', 'equals', 'startsWith', 'endsWith', 'regex') NULL, + `triggerValue` VARCHAR(191) NULL, + `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + `updatedAt` TIMESTAMP NOT NULL, + `instanceId` VARCHAR(191) NOT NULL, + + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `EvolutionBotSetting` ( + `id` VARCHAR(191) NOT NULL, + `expire` INTEGER NULL DEFAULT 0, + `keywordFinish` VARCHAR(100) NULL, + `delayMessage` INTEGER NULL, + `unknownMessage` VARCHAR(100) NULL, + `listeningFromMe` BOOLEAN NULL DEFAULT false, + `stopBotFromMe` BOOLEAN NULL DEFAULT false, + `keepOpen` BOOLEAN NULL DEFAULT false, + `debounceTime` INTEGER NULL, + `ignoreJids` JSON NULL, + `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + `updatedAt` TIMESTAMP NOT NULL, + `botIdFallback` VARCHAR(100) NULL, + `instanceId` VARCHAR(191) NOT NULL, + + UNIQUE INDEX `EvolutionBotSetting_instanceId_key`(`instanceId`), + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- AddForeignKey +ALTER TABLE `EvolutionBot` ADD CONSTRAINT `EvolutionBot_instanceId_fkey` FOREIGN KEY (`instanceId`) REFERENCES `Instance`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `EvolutionBotSetting` ADD CONSTRAINT `EvolutionBotSetting_botIdFallback_fkey` FOREIGN KEY (`botIdFallback`) REFERENCES `EvolutionBot`(`id`) ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `EvolutionBotSetting` ADD CONSTRAINT `EvolutionBotSetting_instanceId_fkey` FOREIGN KEY (`instanceId`) REFERENCES `Instance`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/mysql-migrations/20241001172800_add_message_status/migration.sql b/prisma/mysql-migrations/20241001172800_add_message_status/migration.sql new file mode 100644 index 00000000..f5444070 --- /dev/null +++ b/prisma/mysql-migrations/20241001172800_add_message_status/migration.sql @@ -0,0 +1,174 @@ +/* + Warnings: + + - You are about to alter the column `createdAt` on the `Chat` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Chat` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Chatwoot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Chatwoot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Contact` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Contact` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Dify` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Dify` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `DifySetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `DifySetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `EvolutionBot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `EvolutionBot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `EvolutionBotSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `EvolutionBotSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Flowise` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Flowise` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `FlowiseSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `FlowiseSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `disconnectionAt` on the `Instance` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Instance` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Instance` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `IntegrationSession` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `IntegrationSession` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Label` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Label` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Media` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `OpenaiBot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `OpenaiBot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `OpenaiCreds` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `OpenaiCreds` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `OpenaiSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `OpenaiSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Proxy` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Proxy` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Rabbitmq` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Rabbitmq` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Session` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Setting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Setting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Sqs` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Sqs` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Template` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Template` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Typebot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Typebot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `TypebotSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `TypebotSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Webhook` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Webhook` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Websocket` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Websocket` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + +*/ +-- AlterTable +ALTER TABLE `Chat` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NULL; + +-- AlterTable +ALTER TABLE `Chatwoot` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Contact` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NULL; + +-- AlterTable +ALTER TABLE `Dify` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `DifySetting` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `EvolutionBot` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `EvolutionBotSetting` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Flowise` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `FlowiseSetting` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Instance` MODIFY `disconnectionAt` TIMESTAMP NULL, + MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NULL; + +-- AlterTable +ALTER TABLE `IntegrationSession` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Label` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Media` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP; + +-- AlterTable +ALTER TABLE `Message` ADD COLUMN `status` INTEGER NULL; + +-- AlterTable +ALTER TABLE `OpenaiBot` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `OpenaiCreds` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `OpenaiSetting` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Proxy` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Rabbitmq` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Session` MODIFY `createdAt` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP; + +-- AlterTable +ALTER TABLE `Setting` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Sqs` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Template` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Typebot` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NULL; + +-- AlterTable +ALTER TABLE `TypebotSetting` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Webhook` ADD COLUMN `headers` JSON NULL, + MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Websocket` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- CreateTable +CREATE TABLE `IsOnWhatsapp` ( + `id` VARCHAR(191) NOT NULL, + `remoteJid` VARCHAR(100) NOT NULL, + `jidOptions` VARCHAR(191) NOT NULL, + `createdAt` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updatedAt` TIMESTAMP NOT NULL, + + UNIQUE INDEX `IsOnWhatsapp_remoteJid_key`(`remoteJid`), + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; diff --git a/prisma/mysql-migrations/20241108101333_fix_message_status_as_string/migration.sql b/prisma/mysql-migrations/20241108101333_fix_message_status_as_string/migration.sql new file mode 100644 index 00000000..ae17f418 --- /dev/null +++ b/prisma/mysql-migrations/20241108101333_fix_message_status_as_string/migration.sql @@ -0,0 +1,232 @@ +/* + Warnings: + + - You are about to alter the column `createdAt` on the `Chat` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Chat` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Chatwoot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Chatwoot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Contact` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Contact` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Dify` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Dify` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `DifySetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `DifySetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `EvolutionBot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `EvolutionBot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `EvolutionBotSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `EvolutionBotSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Flowise` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Flowise` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `FlowiseSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `FlowiseSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `disconnectionAt` on the `Instance` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Instance` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Instance` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `IntegrationSession` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `IntegrationSession` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `IsOnWhatsapp` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `IsOnWhatsapp` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Label` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Label` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Media` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `OpenaiBot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `OpenaiBot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `OpenaiCreds` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `OpenaiCreds` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `OpenaiSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `OpenaiSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Proxy` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Proxy` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Rabbitmq` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Rabbitmq` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Session` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Setting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Setting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Sqs` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Sqs` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Template` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Template` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Typebot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Typebot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `TypebotSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `TypebotSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Webhook` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Webhook` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `createdAt` on the `Websocket` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + - You are about to alter the column `updatedAt` on the `Websocket` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. + +*/ +-- AlterTable +ALTER TABLE `Chat` ADD COLUMN `unreadMessages` INTEGER NOT NULL DEFAULT 0, + MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NULL; + +-- AlterTable +ALTER TABLE `Chatwoot` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Contact` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NULL; + +-- AlterTable +ALTER TABLE `Dify` ADD COLUMN `splitMessages` BOOLEAN NULL DEFAULT false, + ADD COLUMN `timePerChar` INTEGER NULL DEFAULT 50, + MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `DifySetting` ADD COLUMN `splitMessages` BOOLEAN NULL DEFAULT false, + ADD COLUMN `timePerChar` INTEGER NULL DEFAULT 50, + MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `EvolutionBot` ADD COLUMN `splitMessages` BOOLEAN NULL DEFAULT false, + ADD COLUMN `timePerChar` INTEGER NULL DEFAULT 50, + MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `EvolutionBotSetting` ADD COLUMN `splitMessages` BOOLEAN NULL DEFAULT false, + ADD COLUMN `timePerChar` INTEGER NULL DEFAULT 50, + MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Flowise` ADD COLUMN `splitMessages` BOOLEAN NULL DEFAULT false, + ADD COLUMN `timePerChar` INTEGER NULL DEFAULT 50, + MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `FlowiseSetting` ADD COLUMN `splitMessages` BOOLEAN NULL DEFAULT false, + ADD COLUMN `timePerChar` INTEGER NULL DEFAULT 50, + MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Instance` MODIFY `disconnectionAt` TIMESTAMP NULL, + MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NULL; + +-- AlterTable +ALTER TABLE `IntegrationSession` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `IsOnWhatsapp` MODIFY `createdAt` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Label` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Media` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP; + +-- AlterTable +ALTER TABLE `Message` MODIFY `status` VARCHAR(30) NULL; + +-- AlterTable +ALTER TABLE `OpenaiBot` ADD COLUMN `splitMessages` BOOLEAN NULL DEFAULT false, + ADD COLUMN `timePerChar` INTEGER NULL DEFAULT 50, + MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `OpenaiCreds` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `OpenaiSetting` ADD COLUMN `splitMessages` BOOLEAN NULL DEFAULT false, + ADD COLUMN `timePerChar` INTEGER NULL DEFAULT 50, + MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Proxy` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Rabbitmq` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Session` MODIFY `createdAt` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP; + +-- AlterTable +ALTER TABLE `Setting` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Sqs` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Template` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Typebot` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NULL; + +-- AlterTable +ALTER TABLE `TypebotSetting` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Webhook` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- AlterTable +ALTER TABLE `Websocket` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + MODIFY `updatedAt` TIMESTAMP NOT NULL; + +-- CreateTable +CREATE TABLE `Pusher` ( + `id` VARCHAR(191) NOT NULL, + `enabled` BOOLEAN NOT NULL DEFAULT false, + `appId` VARCHAR(100) NOT NULL, + `key` VARCHAR(100) NOT NULL, + `secret` VARCHAR(100) NOT NULL, + `cluster` VARCHAR(100) NOT NULL, + `useTLS` BOOLEAN NOT NULL DEFAULT false, + `events` JSON NOT NULL, + `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + `updatedAt` TIMESTAMP NOT NULL, + `instanceId` VARCHAR(191) NOT NULL, + + UNIQUE INDEX `Pusher_instanceId_key`(`instanceId`), + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateIndex +CREATE INDEX `Chat_remoteJid_idx` ON `Chat`(`remoteJid`); + +-- CreateIndex +CREATE INDEX `Contact_remoteJid_idx` ON `Contact`(`remoteJid`); + +-- CreateIndex +CREATE INDEX `Setting_instanceId_idx` ON `Setting`(`instanceId`); + +-- CreateIndex +CREATE INDEX `Webhook_instanceId_idx` ON `Webhook`(`instanceId`); + +-- AddForeignKey +ALTER TABLE `Pusher` ADD CONSTRAINT `Pusher_instanceId_fkey` FOREIGN KEY (`instanceId`) REFERENCES `Instance`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- RenameIndex +ALTER TABLE `Chat` RENAME INDEX `Chat_instanceId_fkey` TO `Chat_instanceId_idx`; + +-- RenameIndex +ALTER TABLE `Contact` RENAME INDEX `Contact_instanceId_fkey` TO `Contact_instanceId_idx`; + +-- RenameIndex +ALTER TABLE `Message` RENAME INDEX `Message_instanceId_fkey` TO `Message_instanceId_idx`; + +-- RenameIndex +ALTER TABLE `MessageUpdate` RENAME INDEX `MessageUpdate_instanceId_fkey` TO `MessageUpdate_instanceId_idx`; + +-- RenameIndex +ALTER TABLE `MessageUpdate` RENAME INDEX `MessageUpdate_messageId_fkey` TO `MessageUpdate_messageId_idx`; diff --git a/prisma/mysql-migrations/migration_lock.toml b/prisma/mysql-migrations/migration_lock.toml new file mode 100644 index 00000000..e5a788a7 --- /dev/null +++ b/prisma/mysql-migrations/migration_lock.toml @@ -0,0 +1,3 @@ +# Please do not edit this file manually +# It should be added in your version-control system (i.e. Git) +provider = "mysql" \ No newline at end of file diff --git a/prisma/mysql-schema.prisma b/prisma/mysql-schema.prisma new file mode 100644 index 00000000..a73ca069 --- /dev/null +++ b/prisma/mysql-schema.prisma @@ -0,0 +1,629 @@ +// This is your Prisma schema file, +// learn more about it in the docs: https://pris.ly/d/prisma-schema + +// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions? +// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init + +generator client { + provider = "prisma-client-js" +} + +datasource db { + provider = "mysql" + url = env("DATABASE_CONNECTION_URI") +} + +enum InstanceConnectionStatus { + open + close + connecting +} + +enum DeviceMessage { + ios + android + web + unknown + desktop +} + +enum SessionStatus { + opened + closed + paused +} + +enum TriggerType { + all + keyword + none + advanced +} + +enum TriggerOperator { + contains + equals + startsWith + endsWith + regex +} + +enum OpenaiBotType { + assistant + chatCompletion +} + +enum DifyBotType { + chatBot + textGenerator + agent + workflow +} + +model Instance { + id String @id @default(cuid()) + name String @unique @db.VarChar(255) + connectionStatus InstanceConnectionStatus @default(open) + ownerJid String? @db.VarChar(100) + profileName String? @db.VarChar(100) + profilePicUrl String? @db.VarChar(500) + integration String? @db.VarChar(100) + number String? @db.VarChar(100) + businessId String? @db.VarChar(100) + token String? @db.VarChar(255) + clientName String? @db.VarChar(100) + disconnectionReasonCode Int? @db.Int + disconnectionObject Json? @db.Json + disconnectionAt DateTime? @db.Timestamp + createdAt DateTime? @default(dbgenerated("CURRENT_TIMESTAMP")) @db.Timestamp + updatedAt DateTime? @updatedAt @db.Timestamp + Chat Chat[] + Contact Contact[] + Message Message[] + Webhook Webhook? + Chatwoot Chatwoot? + Label Label[] + Proxy Proxy? + Setting Setting? + Rabbitmq Rabbitmq? + Sqs Sqs? + Websocket Websocket? + Typebot Typebot[] + Session Session? + MessageUpdate MessageUpdate[] + TypebotSetting TypebotSetting? + Media Media[] + OpenaiCreds OpenaiCreds[] + OpenaiBot OpenaiBot[] + OpenaiSetting OpenaiSetting? + Template Template[] + Dify Dify[] + DifySetting DifySetting? + integrationSessions IntegrationSession[] + EvolutionBot EvolutionBot[] + EvolutionBotSetting EvolutionBotSetting? + Flowise Flowise[] + FlowiseSetting FlowiseSetting? + Pusher Pusher? +} + +model Session { + id String @id @default(cuid()) + sessionId String @unique + creds String? @db.Text + createdAt DateTime @default(dbgenerated("CURRENT_TIMESTAMP")) @db.Timestamp + Instance Instance @relation(fields: [sessionId], references: [id], onDelete: Cascade) +} + +model Chat { + id String @id @default(cuid()) + remoteJid String @db.VarChar(100) + name String? @db.VarChar(100) + labels Json? @db.Json + createdAt DateTime? @default(dbgenerated("CURRENT_TIMESTAMP")) @db.Timestamp + updatedAt DateTime? @updatedAt @db.Timestamp + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String + unreadMessages Int @default(0) + @@index([instanceId]) + @@index([remoteJid]) + @@unique([instanceId, remoteJid]) +} + +model Contact { + id String @id @default(cuid()) + remoteJid String @db.VarChar(100) + pushName String? @db.VarChar(100) + profilePicUrl String? @db.VarChar(500) + createdAt DateTime? @default(dbgenerated("CURRENT_TIMESTAMP")) @db.Timestamp + updatedAt DateTime? @updatedAt @db.Timestamp + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String + + @@unique([remoteJid, instanceId]) + @@index([remoteJid]) + @@index([instanceId]) +} + +model Message { + id String @id @default(cuid()) + key Json @db.Json + pushName String? @db.VarChar(100) + participant String? @db.VarChar(100) + messageType String @db.VarChar(100) + message Json @db.Json + contextInfo Json? @db.Json + source DeviceMessage + messageTimestamp Int @db.Int + chatwootMessageId Int? @db.Int + chatwootInboxId Int? @db.Int + chatwootConversationId Int? @db.Int + chatwootContactInboxSourceId String? @db.VarChar(100) + chatwootIsRead Boolean? @default(false) + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String + typebotSessionId String? + MessageUpdate MessageUpdate[] + Media Media? + webhookUrl String? @db.VarChar(500) + status String? @db.VarChar(30) + + sessionId String? + session IntegrationSession? @relation(fields: [sessionId], references: [id]) + @@index([instanceId]) +} + +model MessageUpdate { + id String @id @default(cuid()) + keyId String @db.VarChar(100) + remoteJid String @db.VarChar(100) + fromMe Boolean + participant String? @db.VarChar(100) + pollUpdates Json? @db.Json + status String @db.VarChar(30) + Message Message @relation(fields: [messageId], references: [id], onDelete: Cascade) + messageId String + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String + @@index([instanceId]) + @@index([messageId]) +} + +model Webhook { + id String @id @default(cuid()) + url String @db.VarChar(500) + headers Json? @db.Json + enabled Boolean? @default(true) + events Json? @db.Json + webhookByEvents Boolean? @default(false) + webhookBase64 Boolean? @default(false) + createdAt DateTime? @default(dbgenerated("CURRENT_TIMESTAMP")) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String @unique + @@index([instanceId]) +} + +model Chatwoot { + id String @id @default(cuid()) + enabled Boolean? @default(true) + accountId String? @db.VarChar(100) + token String? @db.VarChar(100) + url String? @db.VarChar(500) + nameInbox String? @db.VarChar(100) + signMsg Boolean? @default(false) + signDelimiter String? @db.VarChar(100) + number String? @db.VarChar(100) + reopenConversation Boolean? @default(false) + conversationPending Boolean? @default(false) + mergeBrazilContacts Boolean? @default(false) + importContacts Boolean? @default(false) + importMessages Boolean? @default(false) + daysLimitImportMessages Int? @db.Int + organization String? @db.VarChar(100) + logo String? @db.VarChar(500) + ignoreJids Json? + createdAt DateTime? @default(dbgenerated("CURRENT_TIMESTAMP")) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String @unique +} + +model Label { + id String @id @default(cuid()) + labelId String? @db.VarChar(100) + name String @db.VarChar(100) + color String @db.VarChar(100) + predefinedId String? @db.VarChar(100) + createdAt DateTime? @default(dbgenerated("CURRENT_TIMESTAMP")) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String +} + +model Proxy { + id String @id @default(cuid()) + enabled Boolean @default(false) + host String @db.VarChar(100) + port String @db.VarChar(100) + protocol String @db.VarChar(100) + username String @db.VarChar(100) + password String @db.VarChar(100) + createdAt DateTime? @default(dbgenerated("CURRENT_TIMESTAMP")) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String @unique +} + +model Setting { + id String @id @default(cuid()) + rejectCall Boolean @default(false) + msgCall String? @db.VarChar(100) + groupsIgnore Boolean @default(false) + alwaysOnline Boolean @default(false) + readMessages Boolean @default(false) + readStatus Boolean @default(false) + syncFullHistory Boolean @default(false) + wavoipToken String? @db.VarChar(100) + createdAt DateTime? @default(dbgenerated("CURRENT_TIMESTAMP")) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String @unique + @@index([instanceId]) +} + +model Rabbitmq { + id String @id @default(cuid()) + enabled Boolean @default(false) + events Json @db.Json + createdAt DateTime? @default(dbgenerated("CURRENT_TIMESTAMP")) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String @unique +} + +model Sqs { + id String @id @default(cuid()) + enabled Boolean @default(false) + events Json @db.Json + createdAt DateTime? @default(dbgenerated("CURRENT_TIMESTAMP")) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String @unique +} + +model Websocket { + id String @id @default(cuid()) + enabled Boolean @default(false) + events Json @db.Json + createdAt DateTime? @default(dbgenerated("CURRENT_TIMESTAMP")) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String @unique +} + +model Pusher { + id String @id @default(cuid()) + enabled Boolean @default(false) + appId String @db.VarChar(100) + key String @db.VarChar(100) + secret String @db.VarChar(100) + cluster String @db.VarChar(100) + useTLS Boolean @default(false) + events Json @db.Json + createdAt DateTime? @default(dbgenerated("CURRENT_TIMESTAMP")) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String @unique +} + +model Typebot { + id String @id @default(cuid()) + enabled Boolean @default(true) + description String? @db.VarChar(255) + url String @db.VarChar(500) + typebot String @db.VarChar(100) + expire Int? @default(0) @db.Int + keywordFinish String? @db.VarChar(100) + delayMessage Int? @db.Int + unknownMessage String? @db.VarChar(100) + listeningFromMe Boolean? @default(false) + stopBotFromMe Boolean? @default(false) + keepOpen Boolean? @default(false) + debounceTime Int? @db.Int + createdAt DateTime? @default(dbgenerated("CURRENT_TIMESTAMP")) @db.Timestamp + updatedAt DateTime? @updatedAt @db.Timestamp + ignoreJids Json? + triggerType TriggerType? + triggerOperator TriggerOperator? + triggerValue String? + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String + TypebotSetting TypebotSetting[] +} + +model TypebotSetting { + id String @id @default(cuid()) + expire Int? @default(0) @db.Int + keywordFinish String? @db.VarChar(100) + delayMessage Int? @db.Int + unknownMessage String? @db.VarChar(100) + listeningFromMe Boolean? @default(false) + stopBotFromMe Boolean? @default(false) + keepOpen Boolean? @default(false) + debounceTime Int? @db.Int + typebotIdFallback String? @db.VarChar(100) + ignoreJids Json? + createdAt DateTime? @default(dbgenerated("CURRENT_TIMESTAMP")) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + Fallback Typebot? @relation(fields: [typebotIdFallback], references: [id]) + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String @unique +} + +model IntegrationSession { + id String @id @default(cuid()) + sessionId String @db.VarChar(255) + remoteJid String @db.VarChar(100) + pushName String? + status SessionStatus + awaitUser Boolean @default(false) + context Json? + type String? @db.VarChar(100) + createdAt DateTime? @default(dbgenerated("CURRENT_TIMESTAMP")) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + Message Message[] + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String + parameters Json? + + botId String? +} + +model Media { + id String @id @default(cuid()) + fileName String @unique @db.VarChar(500) + type String @db.VarChar(100) + mimetype String @db.VarChar(100) + createdAt DateTime? @default(dbgenerated("CURRENT_TIMESTAMP")) @db.Timestamp + Message Message @relation(fields: [messageId], references: [id], onDelete: Cascade) + messageId String @unique + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String +} + +model OpenaiCreds { + id String @id @default(cuid()) + name String? @unique @db.VarChar(255) + apiKey String? @unique @db.VarChar(255) + createdAt DateTime? @default(dbgenerated("CURRENT_TIMESTAMP")) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String + OpenaiAssistant OpenaiBot[] + OpenaiSetting OpenaiSetting? +} + +model OpenaiBot { + id String @id @default(cuid()) + enabled Boolean @default(true) + description String? @db.VarChar(255) + botType OpenaiBotType + assistantId String? @db.VarChar(255) + functionUrl String? @db.VarChar(500) + model String? @db.VarChar(100) + systemMessages Json? @db.Json + assistantMessages Json? @db.Json + userMessages Json? @db.Json + maxTokens Int? @db.Int + expire Int? @default(0) @db.Int + keywordFinish String? @db.VarChar(100) + delayMessage Int? @db.Int + unknownMessage String? @db.VarChar(100) + listeningFromMe Boolean? @default(false) + stopBotFromMe Boolean? @default(false) + keepOpen Boolean? @default(false) + debounceTime Int? @db.Int + ignoreJids Json? + splitMessages Boolean? @default(false) + timePerChar Int? @default(50) @db.Int + triggerType TriggerType? + triggerOperator TriggerOperator? + triggerValue String? + createdAt DateTime? @default(dbgenerated("CURRENT_TIMESTAMP")) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + OpenaiCreds OpenaiCreds @relation(fields: [openaiCredsId], references: [id], onDelete: Cascade) + openaiCredsId String + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String + OpenaiSetting OpenaiSetting[] +} + +model OpenaiSetting { + id String @id @default(cuid()) + expire Int? @default(0) @db.Int + keywordFinish String? @db.VarChar(100) + delayMessage Int? @db.Int + unknownMessage String? @db.VarChar(100) + listeningFromMe Boolean? @default(false) + stopBotFromMe Boolean? @default(false) + keepOpen Boolean? @default(false) + debounceTime Int? @db.Int + ignoreJids Json? + splitMessages Boolean? @default(false) + timePerChar Int? @default(50) @db.Int + speechToText Boolean? @default(false) + createdAt DateTime? @default(dbgenerated("CURRENT_TIMESTAMP")) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + OpenaiCreds OpenaiCreds? @relation(fields: [openaiCredsId], references: [id]) + openaiCredsId String @unique + Fallback OpenaiBot? @relation(fields: [openaiIdFallback], references: [id]) + openaiIdFallback String? @db.VarChar(100) + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String @unique +} + +model Template { + id String @id @default(cuid()) + templateId String @unique @db.VarChar(255) + name String @unique @db.VarChar(255) + template Json @db.Json + webhookUrl String? @db.VarChar(500) + createdAt DateTime? @default(dbgenerated("CURRENT_TIMESTAMP")) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String +} + +model Dify { + id String @id @default(cuid()) + enabled Boolean @default(true) + description String? @db.VarChar(255) + botType DifyBotType + apiUrl String? @db.VarChar(255) + apiKey String? @db.VarChar(255) + expire Int? @default(0) @db.Int + keywordFinish String? @db.VarChar(100) + delayMessage Int? @db.Int + unknownMessage String? @db.VarChar(100) + listeningFromMe Boolean? @default(false) + stopBotFromMe Boolean? @default(false) + keepOpen Boolean? @default(false) + debounceTime Int? @db.Int + ignoreJids Json? + splitMessages Boolean? @default(false) + timePerChar Int? @default(50) @db.Int + triggerType TriggerType? + triggerOperator TriggerOperator? + triggerValue String? + createdAt DateTime? @default(dbgenerated("CURRENT_TIMESTAMP")) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String + DifySetting DifySetting[] +} + +model DifySetting { + id String @id @default(cuid()) + expire Int? @default(0) @db.Int + keywordFinish String? @db.VarChar(100) + delayMessage Int? @db.Int + unknownMessage String? @db.VarChar(100) + listeningFromMe Boolean? @default(false) + stopBotFromMe Boolean? @default(false) + keepOpen Boolean? @default(false) + debounceTime Int? @db.Int + ignoreJids Json? + splitMessages Boolean? @default(false) + timePerChar Int? @default(50) @db.Int + createdAt DateTime? @default(dbgenerated("CURRENT_TIMESTAMP")) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + Fallback Dify? @relation(fields: [difyIdFallback], references: [id]) + difyIdFallback String? @db.VarChar(100) + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String @unique +} + +model EvolutionBot { + id String @id @default(cuid()) + enabled Boolean @default(true) + description String? @db.VarChar(255) + apiUrl String? @db.VarChar(255) + apiKey String? @db.VarChar(255) + expire Int? @default(0) @db.Int + keywordFinish String? @db.VarChar(100) + delayMessage Int? @db.Int + unknownMessage String? @db.VarChar(100) + listeningFromMe Boolean? @default(false) + stopBotFromMe Boolean? @default(false) + keepOpen Boolean? @default(false) + debounceTime Int? @db.Int + ignoreJids Json? + splitMessages Boolean? @default(false) + timePerChar Int? @default(50) @db.Int + triggerType TriggerType? + triggerOperator TriggerOperator? + triggerValue String? + createdAt DateTime? @default(dbgenerated("CURRENT_TIMESTAMP")) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String + EvolutionBotSetting EvolutionBotSetting[] +} + +model EvolutionBotSetting { + id String @id @default(cuid()) + expire Int? @default(0) @db.Int + keywordFinish String? @db.VarChar(100) + delayMessage Int? @db.Int + unknownMessage String? @db.VarChar(100) + listeningFromMe Boolean? @default(false) + stopBotFromMe Boolean? @default(false) + keepOpen Boolean? @default(false) + debounceTime Int? @db.Int + ignoreJids Json? + splitMessages Boolean? @default(false) + timePerChar Int? @default(50) @db.Int + createdAt DateTime? @default(dbgenerated("CURRENT_TIMESTAMP")) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + Fallback EvolutionBot? @relation(fields: [botIdFallback], references: [id]) + botIdFallback String? @db.VarChar(100) + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String @unique +} + +model Flowise { + id String @id @default(cuid()) + enabled Boolean @default(true) + description String? @db.VarChar(255) + apiUrl String? @db.VarChar(255) + apiKey String? @db.VarChar(255) + expire Int? @default(0) @db.Int + keywordFinish String? @db.VarChar(100) + delayMessage Int? @db.Int + unknownMessage String? @db.VarChar(100) + listeningFromMe Boolean? @default(false) + stopBotFromMe Boolean? @default(false) + keepOpen Boolean? @default(false) + debounceTime Int? @db.Int + ignoreJids Json? + splitMessages Boolean? @default(false) + timePerChar Int? @default(50) @db.Int + triggerType TriggerType? + triggerOperator TriggerOperator? + triggerValue String? + createdAt DateTime? @default(dbgenerated("CURRENT_TIMESTAMP")) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String + FlowiseSetting FlowiseSetting[] +} + +model FlowiseSetting { + id String @id @default(cuid()) + expire Int? @default(0) @db.Int + keywordFinish String? @db.VarChar(100) + delayMessage Int? @db.Int + unknownMessage String? @db.VarChar(100) + listeningFromMe Boolean? @default(false) + stopBotFromMe Boolean? @default(false) + keepOpen Boolean? @default(false) + debounceTime Int? @db.Int + ignoreJids Json? + splitMessages Boolean? @default(false) + timePerChar Int? @default(50) @db.Int + createdAt DateTime? @default(dbgenerated("CURRENT_TIMESTAMP")) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + Fallback Flowise? @relation(fields: [flowiseIdFallback], references: [id]) + flowiseIdFallback String? @db.VarChar(100) + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String @unique +} + +model IsOnWhatsapp { + id String @id @default(cuid()) + remoteJid String @unique @db.VarChar(100) + jidOptions String + createdAt DateTime @default(dbgenerated("CURRENT_TIMESTAMP")) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp +} diff --git a/prisma/postgresql-migrations/20240609181238_init/migration.sql b/prisma/postgresql-migrations/20240609181238_init/migration.sql new file mode 100644 index 00000000..8f605495 --- /dev/null +++ b/prisma/postgresql-migrations/20240609181238_init/migration.sql @@ -0,0 +1,375 @@ +-- CreateEnum +CREATE TYPE "InstanceConnectionStatus" AS ENUM ('open', 'close', 'connecting'); + +-- CreateEnum +CREATE TYPE "DeviceMessage" AS ENUM ('ios', 'android', 'web', 'unknown', 'desktop'); + +-- CreateEnum +CREATE TYPE "TypebotSessionStatus" AS ENUM ('open', 'closed', 'paused'); + +-- CreateEnum +CREATE TYPE "TriggerType" AS ENUM ('all', 'keyword'); + +-- CreateEnum +CREATE TYPE "TriggerOperator" AS ENUM ('contains', 'equals', 'startsWith', 'endsWith'); + +-- CreateTable +CREATE TABLE "Instance" ( + "id" TEXT NOT NULL, + "name" VARCHAR(255) NOT NULL, + "connectionStatus" "InstanceConnectionStatus" NOT NULL DEFAULT 'open', + "ownerJid" VARCHAR(100), + "profilePicUrl" VARCHAR(500), + "integration" VARCHAR(100), + "number" VARCHAR(100), + "token" VARCHAR(255), + "clientName" VARCHAR(100), + "createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP, + + CONSTRAINT "Instance_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Session" ( + "id" TEXT NOT NULL, + "sessionId" TEXT NOT NULL, + "creds" TEXT, + "createdAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "Session_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Chat" ( + "id" TEXT NOT NULL, + "remoteJid" VARCHAR(100) NOT NULL, + "labels" JSONB, + "createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP, + "instanceId" TEXT NOT NULL, + + CONSTRAINT "Chat_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Contact" ( + "id" TEXT NOT NULL, + "remoteJid" VARCHAR(100) NOT NULL, + "pushName" VARCHAR(100), + "profilePicUrl" VARCHAR(500), + "createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP, + "instanceId" TEXT NOT NULL, + + CONSTRAINT "Contact_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Message" ( + "id" TEXT NOT NULL, + "key" JSONB NOT NULL, + "pushName" VARCHAR(100), + "participant" VARCHAR(100), + "messageType" VARCHAR(100) NOT NULL, + "message" JSONB NOT NULL, + "contextInfo" JSONB, + "source" "DeviceMessage" NOT NULL, + "messageTimestamp" INTEGER NOT NULL, + "chatwootMessageId" INTEGER, + "chatwootInboxId" INTEGER, + "chatwootConversationId" INTEGER, + "chatwootContactInboxSourceId" VARCHAR(100), + "chatwootIsRead" BOOLEAN, + "instanceId" TEXT NOT NULL, + "typebotSessionId" TEXT, + + CONSTRAINT "Message_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "MessageUpdate" ( + "id" TEXT NOT NULL, + "keyId" VARCHAR(100) NOT NULL, + "remoteJid" VARCHAR(100) NOT NULL, + "fromMe" BOOLEAN NOT NULL, + "participant" VARCHAR(100), + "pollUpdates" JSONB, + "status" VARCHAR(30) NOT NULL, + "messageId" TEXT NOT NULL, + "instanceId" TEXT NOT NULL, + + CONSTRAINT "MessageUpdate_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Webhook" ( + "id" TEXT NOT NULL, + "url" VARCHAR(500) NOT NULL, + "enabled" BOOLEAN DEFAULT true, + "events" JSONB, + "webhookByEvents" BOOLEAN DEFAULT false, + "webhookBase64" BOOLEAN DEFAULT false, + "createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP NOT NULL, + "instanceId" TEXT NOT NULL, + + CONSTRAINT "Webhook_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Chatwoot" ( + "id" TEXT NOT NULL, + "enabled" BOOLEAN DEFAULT true, + "accountId" VARCHAR(100), + "token" VARCHAR(100), + "url" VARCHAR(500), + "nameInbox" VARCHAR(100), + "signMsg" BOOLEAN DEFAULT false, + "signDelimiter" VARCHAR(100), + "number" VARCHAR(100), + "reopenConversation" BOOLEAN DEFAULT false, + "conversationPending" BOOLEAN DEFAULT false, + "mergeBrazilContacts" BOOLEAN DEFAULT false, + "importContacts" BOOLEAN DEFAULT false, + "importMessages" BOOLEAN DEFAULT false, + "daysLimitImportMessages" INTEGER, + "createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP NOT NULL, + "instanceId" TEXT NOT NULL, + + CONSTRAINT "Chatwoot_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Label" ( + "id" TEXT NOT NULL, + "labelId" VARCHAR(100), + "name" VARCHAR(100) NOT NULL, + "color" VARCHAR(100) NOT NULL, + "predefinedId" VARCHAR(100), + "createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP NOT NULL, + "instanceId" TEXT NOT NULL, + + CONSTRAINT "Label_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Proxy" ( + "id" TEXT NOT NULL, + "enabled" BOOLEAN NOT NULL DEFAULT false, + "host" VARCHAR(100) NOT NULL, + "port" VARCHAR(100) NOT NULL, + "protocol" VARCHAR(100) NOT NULL, + "username" VARCHAR(100) NOT NULL, + "password" VARCHAR(100) NOT NULL, + "createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP NOT NULL, + "instanceId" TEXT NOT NULL, + + CONSTRAINT "Proxy_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Setting" ( + "id" TEXT NOT NULL, + "rejectCall" BOOLEAN NOT NULL DEFAULT false, + "msgCall" VARCHAR(100), + "groupsIgnore" BOOLEAN NOT NULL DEFAULT false, + "alwaysOnline" BOOLEAN NOT NULL DEFAULT false, + "readMessages" BOOLEAN NOT NULL DEFAULT false, + "readStatus" BOOLEAN NOT NULL DEFAULT false, + "syncFullHistory" BOOLEAN NOT NULL DEFAULT false, + "createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP NOT NULL, + "instanceId" TEXT NOT NULL, + + CONSTRAINT "Setting_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Rabbitmq" ( + "id" TEXT NOT NULL, + "enabled" BOOLEAN NOT NULL DEFAULT false, + "events" JSONB NOT NULL, + "createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP NOT NULL, + "instanceId" TEXT NOT NULL, + + CONSTRAINT "Rabbitmq_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Sqs" ( + "id" TEXT NOT NULL, + "enabled" BOOLEAN NOT NULL DEFAULT false, + "events" JSONB NOT NULL, + "createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP NOT NULL, + "instanceId" TEXT NOT NULL, + + CONSTRAINT "Sqs_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Websocket" ( + "id" TEXT NOT NULL, + "enabled" BOOLEAN NOT NULL DEFAULT false, + "events" JSONB NOT NULL, + "createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP NOT NULL, + "instanceId" TEXT NOT NULL, + + CONSTRAINT "Websocket_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Typebot" ( + "id" TEXT NOT NULL, + "enabled" BOOLEAN NOT NULL DEFAULT true, + "url" VARCHAR(500) NOT NULL, + "typebot" VARCHAR(100) NOT NULL, + "expire" INTEGER DEFAULT 0, + "keywordFinish" VARCHAR(100), + "delayMessage" INTEGER, + "unknownMessage" VARCHAR(100), + "listeningFromMe" BOOLEAN DEFAULT false, + "stopBotFromMe" BOOLEAN DEFAULT false, + "keepOpen" BOOLEAN DEFAULT false, + "createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP, + "triggerType" "TriggerType", + "triggerOperator" "TriggerOperator", + "triggerValue" TEXT, + "instanceId" TEXT NOT NULL, + + CONSTRAINT "Typebot_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "TypebotSession" ( + "id" TEXT NOT NULL, + "remoteJid" VARCHAR(100) NOT NULL, + "pushName" VARCHAR(100), + "sessionId" VARCHAR(100) NOT NULL, + "status" VARCHAR(100) NOT NULL, + "prefilledVariables" JSONB, + "awaitUser" BOOLEAN NOT NULL DEFAULT false, + "createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP NOT NULL, + "typebotId" TEXT NOT NULL, + "instanceId" TEXT NOT NULL, + + CONSTRAINT "TypebotSession_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "TypebotSetting" ( + "id" TEXT NOT NULL, + "expire" INTEGER DEFAULT 0, + "keywordFinish" VARCHAR(100), + "delayMessage" INTEGER, + "unknownMessage" VARCHAR(100), + "listeningFromMe" BOOLEAN DEFAULT false, + "stopBotFromMe" BOOLEAN DEFAULT false, + "keepOpen" BOOLEAN DEFAULT false, + "createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP NOT NULL, + "instanceId" TEXT NOT NULL, + + CONSTRAINT "TypebotSetting_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "Instance_name_key" ON "Instance"("name"); + +-- CreateIndex +CREATE UNIQUE INDEX "Instance_token_key" ON "Instance"("token"); + +-- CreateIndex +CREATE UNIQUE INDEX "Session_sessionId_key" ON "Session"("sessionId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Webhook_instanceId_key" ON "Webhook"("instanceId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Chatwoot_instanceId_key" ON "Chatwoot"("instanceId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Label_labelId_key" ON "Label"("labelId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Proxy_instanceId_key" ON "Proxy"("instanceId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Setting_instanceId_key" ON "Setting"("instanceId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Rabbitmq_instanceId_key" ON "Rabbitmq"("instanceId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Sqs_instanceId_key" ON "Sqs"("instanceId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Websocket_instanceId_key" ON "Websocket"("instanceId"); + +-- CreateIndex +CREATE UNIQUE INDEX "TypebotSetting_instanceId_key" ON "TypebotSetting"("instanceId"); + +-- AddForeignKey +ALTER TABLE "Session" ADD CONSTRAINT "Session_sessionId_fkey" FOREIGN KEY ("sessionId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Chat" ADD CONSTRAINT "Chat_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Contact" ADD CONSTRAINT "Contact_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Message" ADD CONSTRAINT "Message_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Message" ADD CONSTRAINT "Message_typebotSessionId_fkey" FOREIGN KEY ("typebotSessionId") REFERENCES "TypebotSession"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "MessageUpdate" ADD CONSTRAINT "MessageUpdate_messageId_fkey" FOREIGN KEY ("messageId") REFERENCES "Message"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "MessageUpdate" ADD CONSTRAINT "MessageUpdate_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Webhook" ADD CONSTRAINT "Webhook_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Chatwoot" ADD CONSTRAINT "Chatwoot_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Label" ADD CONSTRAINT "Label_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Proxy" ADD CONSTRAINT "Proxy_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Setting" ADD CONSTRAINT "Setting_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Rabbitmq" ADD CONSTRAINT "Rabbitmq_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Sqs" ADD CONSTRAINT "Sqs_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Websocket" ADD CONSTRAINT "Websocket_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Typebot" ADD CONSTRAINT "Typebot_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "TypebotSession" ADD CONSTRAINT "TypebotSession_typebotId_fkey" FOREIGN KEY ("typebotId") REFERENCES "Typebot"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "TypebotSession" ADD CONSTRAINT "TypebotSession_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "TypebotSetting" ADD CONSTRAINT "TypebotSetting_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/postgresql-migrations/20240610144159_create_column_profile_name_instance/migration.sql b/prisma/postgresql-migrations/20240610144159_create_column_profile_name_instance/migration.sql new file mode 100644 index 00000000..5fd02895 --- /dev/null +++ b/prisma/postgresql-migrations/20240610144159_create_column_profile_name_instance/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "Instance" ADD COLUMN "profileName" VARCHAR(100); diff --git a/prisma/postgresql-migrations/20240611125754_create_columns_whitelabel_chatwoot/migration.sql b/prisma/postgresql-migrations/20240611125754_create_columns_whitelabel_chatwoot/migration.sql new file mode 100644 index 00000000..a94f2ef6 --- /dev/null +++ b/prisma/postgresql-migrations/20240611125754_create_columns_whitelabel_chatwoot/migration.sql @@ -0,0 +1,3 @@ +-- AlterTable +ALTER TABLE "Chatwoot" ADD COLUMN "logo" VARCHAR(500), +ADD COLUMN "organization" VARCHAR(100); diff --git a/prisma/postgresql-migrations/20240611202817_create_columns_debounce_time_typebot/migration.sql b/prisma/postgresql-migrations/20240611202817_create_columns_debounce_time_typebot/migration.sql new file mode 100644 index 00000000..85d2e768 --- /dev/null +++ b/prisma/postgresql-migrations/20240611202817_create_columns_debounce_time_typebot/migration.sql @@ -0,0 +1,5 @@ +-- AlterTable +ALTER TABLE "Typebot" ADD COLUMN "debounceTime" INTEGER; + +-- AlterTable +ALTER TABLE "TypebotSetting" ADD COLUMN "debounceTime" INTEGER; diff --git a/prisma/postgresql-migrations/20240712144948_add_business_id_column_to_instances/migration.sql b/prisma/postgresql-migrations/20240712144948_add_business_id_column_to_instances/migration.sql new file mode 100644 index 00000000..58b64ff5 --- /dev/null +++ b/prisma/postgresql-migrations/20240712144948_add_business_id_column_to_instances/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "Instance" ADD COLUMN "businessId" VARCHAR(100); diff --git a/prisma/postgresql-migrations/20240712150256_create_templates_table/migration.sql b/prisma/postgresql-migrations/20240712150256_create_templates_table/migration.sql new file mode 100644 index 00000000..cb441beb --- /dev/null +++ b/prisma/postgresql-migrations/20240712150256_create_templates_table/migration.sql @@ -0,0 +1,21 @@ +-- CreateTable +CREATE TABLE "Template" ( + "id" TEXT NOT NULL, + "name" VARCHAR(255) NOT NULL, + "language" VARCHAR(255) NOT NULL, + "templateId" VARCHAR(255) NOT NULL, + "createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP NOT NULL, + "instanceId" TEXT NOT NULL, + + CONSTRAINT "Template_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "Template_templateId_key" ON "Template"("templateId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Template_instanceId_key" ON "Template"("instanceId"); + +-- AddForeignKey +ALTER TABLE "Template" ADD CONSTRAINT "Template_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/postgresql-migrations/20240712155950_adjusts_in_templates_table/migration.sql b/prisma/postgresql-migrations/20240712155950_adjusts_in_templates_table/migration.sql new file mode 100644 index 00000000..2ec61dac --- /dev/null +++ b/prisma/postgresql-migrations/20240712155950_adjusts_in_templates_table/migration.sql @@ -0,0 +1,2 @@ +-- DropIndex +DROP INDEX "Template_instanceId_key"; diff --git a/prisma/postgresql-migrations/20240712162206_remove_templates_table/migration.sql b/prisma/postgresql-migrations/20240712162206_remove_templates_table/migration.sql new file mode 100644 index 00000000..3da4351a --- /dev/null +++ b/prisma/postgresql-migrations/20240712162206_remove_templates_table/migration.sql @@ -0,0 +1,11 @@ +/* + Warnings: + + - You are about to drop the `Template` table. If the table is not empty, all the data it contains will be lost. + +*/ +-- DropForeignKey +ALTER TABLE "Template" DROP CONSTRAINT "Template_instanceId_fkey"; + +-- DropTable +DROP TABLE "Template"; diff --git a/prisma/postgresql-migrations/20240712223655_column_fallback_typebot/migration.sql b/prisma/postgresql-migrations/20240712223655_column_fallback_typebot/migration.sql new file mode 100644 index 00000000..b16e7d87 --- /dev/null +++ b/prisma/postgresql-migrations/20240712223655_column_fallback_typebot/migration.sql @@ -0,0 +1,8 @@ +-- AlterEnum +ALTER TYPE "TriggerOperator" ADD VALUE 'regex'; + +-- AlterTable +ALTER TABLE "TypebotSetting" ADD COLUMN "typebotIdFallback" VARCHAR(100); + +-- AddForeignKey +ALTER TABLE "TypebotSetting" ADD CONSTRAINT "TypebotSetting_typebotIdFallback_fkey" FOREIGN KEY ("typebotIdFallback") REFERENCES "Typebot"("id") ON DELETE SET NULL ON UPDATE CASCADE; diff --git a/prisma/postgresql-migrations/20240712230631_column_ignore_jids_typebot/migration.sql b/prisma/postgresql-migrations/20240712230631_column_ignore_jids_typebot/migration.sql new file mode 100644 index 00000000..a4e75cf1 --- /dev/null +++ b/prisma/postgresql-migrations/20240712230631_column_ignore_jids_typebot/migration.sql @@ -0,0 +1,5 @@ +-- AlterTable +ALTER TABLE "Typebot" ADD COLUMN "ignoreJids" JSONB; + +-- AlterTable +ALTER TABLE "TypebotSetting" ADD COLUMN "ignoreJids" JSONB; diff --git a/prisma/postgresql-migrations/20240713184337_add_media_table/migration.sql b/prisma/postgresql-migrations/20240713184337_add_media_table/migration.sql new file mode 100644 index 00000000..17e03802 --- /dev/null +++ b/prisma/postgresql-migrations/20240713184337_add_media_table/migration.sql @@ -0,0 +1,24 @@ +-- CreateTable +CREATE TABLE "Media" ( + "id" TEXT NOT NULL, + "fileName" VARCHAR(500) NOT NULL, + "type" VARCHAR(100) NOT NULL, + "mimetype" VARCHAR(100) NOT NULL, + "createdAt" DATE DEFAULT CURRENT_TIMESTAMP, + "messageId" TEXT NOT NULL, + "instanceId" TEXT NOT NULL, + + CONSTRAINT "Media_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "Media_fileName_key" ON "Media"("fileName"); + +-- CreateIndex +CREATE UNIQUE INDEX "Media_messageId_key" ON "Media"("messageId"); + +-- AddForeignKey +ALTER TABLE "Media" ADD CONSTRAINT "Media_messageId_fkey" FOREIGN KEY ("messageId") REFERENCES "Message"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Media" ADD CONSTRAINT "Media_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/postgresql-migrations/20240718121437_add_openai_tables/migration.sql b/prisma/postgresql-migrations/20240718121437_add_openai_tables/migration.sql new file mode 100644 index 00000000..37ee5c69 --- /dev/null +++ b/prisma/postgresql-migrations/20240718121437_add_openai_tables/migration.sql @@ -0,0 +1,118 @@ +-- AlterTable +ALTER TABLE "Message" ADD COLUMN "openaiSessionId" TEXT; + +-- CreateTable +CREATE TABLE "OpenaiCreds" ( + "id" TEXT NOT NULL, + "apiKey" VARCHAR(255) NOT NULL, + "createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP NOT NULL, + "instanceId" TEXT NOT NULL, + + CONSTRAINT "OpenaiCreds_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "OpenaiBot" ( + "id" TEXT NOT NULL, + "botType" VARCHAR(100) NOT NULL, + "assistantId" VARCHAR(255), + "model" VARCHAR(100), + "systemMessages" JSONB, + "assistantMessages" JSONB, + "userMessages" JSONB, + "maxTokens" INTEGER, + "expire" INTEGER DEFAULT 0, + "keywordFinish" VARCHAR(100), + "delayMessage" INTEGER, + "unknownMessage" VARCHAR(100), + "listeningFromMe" BOOLEAN DEFAULT false, + "stopBotFromMe" BOOLEAN DEFAULT false, + "keepOpen" BOOLEAN DEFAULT false, + "debounceTime" INTEGER, + "ignoreJids" JSONB, + "triggerType" "TriggerType", + "triggerOperator" "TriggerOperator", + "triggerValue" TEXT, + "createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP NOT NULL, + "openaiCredsId" TEXT NOT NULL, + "instanceId" TEXT NOT NULL, + + CONSTRAINT "OpenaiBot_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "OpenaiSession" ( + "id" TEXT NOT NULL, + "sessionId" VARCHAR(255) NOT NULL, + "remoteJid" VARCHAR(100) NOT NULL, + "status" "TypebotSessionStatus" NOT NULL, + "awaitUser" BOOLEAN NOT NULL DEFAULT false, + "createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP NOT NULL, + "openaiBotId" TEXT NOT NULL, + "instanceId" TEXT NOT NULL, + + CONSTRAINT "OpenaiSession_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "OpenaiSetting" ( + "id" TEXT NOT NULL, + "expire" INTEGER DEFAULT 0, + "keywordFinish" VARCHAR(100), + "delayMessage" INTEGER, + "unknownMessage" VARCHAR(100), + "listeningFromMe" BOOLEAN DEFAULT false, + "stopBotFromMe" BOOLEAN DEFAULT false, + "keepOpen" BOOLEAN DEFAULT false, + "debounceTime" INTEGER, + "ignoreJids" JSONB, + "createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP NOT NULL, + "openaiCredsId" TEXT NOT NULL, + "openaiIdFallback" VARCHAR(100), + "instanceId" TEXT NOT NULL, + + CONSTRAINT "OpenaiSetting_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "OpenaiCreds_apiKey_key" ON "OpenaiCreds"("apiKey"); + +-- CreateIndex +CREATE UNIQUE INDEX "OpenaiCreds_instanceId_key" ON "OpenaiCreds"("instanceId"); + +-- CreateIndex +CREATE UNIQUE INDEX "OpenaiBot_assistantId_key" ON "OpenaiBot"("assistantId"); + +-- CreateIndex +CREATE UNIQUE INDEX "OpenaiSetting_instanceId_key" ON "OpenaiSetting"("instanceId"); + +-- AddForeignKey +ALTER TABLE "Message" ADD CONSTRAINT "Message_openaiSessionId_fkey" FOREIGN KEY ("openaiSessionId") REFERENCES "OpenaiSession"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "OpenaiCreds" ADD CONSTRAINT "OpenaiCreds_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "OpenaiBot" ADD CONSTRAINT "OpenaiBot_openaiCredsId_fkey" FOREIGN KEY ("openaiCredsId") REFERENCES "OpenaiCreds"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "OpenaiBot" ADD CONSTRAINT "OpenaiBot_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "OpenaiSession" ADD CONSTRAINT "OpenaiSession_openaiBotId_fkey" FOREIGN KEY ("openaiBotId") REFERENCES "OpenaiBot"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "OpenaiSession" ADD CONSTRAINT "OpenaiSession_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "OpenaiSetting" ADD CONSTRAINT "OpenaiSetting_openaiCredsId_fkey" FOREIGN KEY ("openaiCredsId") REFERENCES "OpenaiCreds"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "OpenaiSetting" ADD CONSTRAINT "OpenaiSetting_openaiIdFallback_fkey" FOREIGN KEY ("openaiIdFallback") REFERENCES "OpenaiBot"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "OpenaiSetting" ADD CONSTRAINT "OpenaiSetting_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/postgresql-migrations/20240718123923_adjusts_openai_tables/migration.sql b/prisma/postgresql-migrations/20240718123923_adjusts_openai_tables/migration.sql new file mode 100644 index 00000000..cea06fa4 --- /dev/null +++ b/prisma/postgresql-migrations/20240718123923_adjusts_openai_tables/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "OpenaiBot" ADD COLUMN "enabled" BOOLEAN NOT NULL DEFAULT true; diff --git a/prisma/postgresql-migrations/20240722173259_add_name_column_to_openai_creds/migration.sql b/prisma/postgresql-migrations/20240722173259_add_name_column_to_openai_creds/migration.sql new file mode 100644 index 00000000..e7538a27 --- /dev/null +++ b/prisma/postgresql-migrations/20240722173259_add_name_column_to_openai_creds/migration.sql @@ -0,0 +1,12 @@ +/* + Warnings: + + - A unique constraint covering the columns `[name]` on the table `OpenaiCreds` will be added. If there are existing duplicate values, this will fail. + +*/ +-- AlterTable +ALTER TABLE "OpenaiCreds" ADD COLUMN "name" VARCHAR(255), +ALTER COLUMN "apiKey" DROP NOT NULL; + +-- CreateIndex +CREATE UNIQUE INDEX "OpenaiCreds_name_key" ON "OpenaiCreds"("name"); diff --git a/prisma/postgresql-migrations/20240722173518_add_name_column_to_openai_creds/migration.sql b/prisma/postgresql-migrations/20240722173518_add_name_column_to_openai_creds/migration.sql new file mode 100644 index 00000000..856abf67 --- /dev/null +++ b/prisma/postgresql-migrations/20240722173518_add_name_column_to_openai_creds/migration.sql @@ -0,0 +1,2 @@ +-- DropIndex +DROP INDEX "OpenaiCreds_instanceId_key"; diff --git a/prisma/postgresql-migrations/20240723152648_adjusts_in_column_openai_creds/migration.sql b/prisma/postgresql-migrations/20240723152648_adjusts_in_column_openai_creds/migration.sql new file mode 100644 index 00000000..7f1af2e6 --- /dev/null +++ b/prisma/postgresql-migrations/20240723152648_adjusts_in_column_openai_creds/migration.sql @@ -0,0 +1,8 @@ +/* + Warnings: + + - A unique constraint covering the columns `[openaiCredsId]` on the table `OpenaiSetting` will be added. If there are existing duplicate values, this will fail. + +*/ +-- CreateIndex +CREATE UNIQUE INDEX "OpenaiSetting_openaiCredsId_key" ON "OpenaiSetting"("openaiCredsId"); diff --git a/prisma/postgresql-migrations/20240723200254_add_webhookurl_on_message/migration.sql b/prisma/postgresql-migrations/20240723200254_add_webhookurl_on_message/migration.sql new file mode 100644 index 00000000..20567778 --- /dev/null +++ b/prisma/postgresql-migrations/20240723200254_add_webhookurl_on_message/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "Message" ADD COLUMN "webhookUrl" VARCHAR(500); diff --git a/prisma/postgresql-migrations/20240725184147_create_template_table/migration.sql b/prisma/postgresql-migrations/20240725184147_create_template_table/migration.sql new file mode 100644 index 00000000..0b1d6ad0 --- /dev/null +++ b/prisma/postgresql-migrations/20240725184147_create_template_table/migration.sql @@ -0,0 +1,21 @@ +-- CreateTable +CREATE TABLE "Template" ( + "id" TEXT NOT NULL, + "templateId" VARCHAR(255) NOT NULL, + "name" VARCHAR(255) NOT NULL, + "template" JSONB NOT NULL, + "createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP NOT NULL, + "instanceId" TEXT NOT NULL, + + CONSTRAINT "Template_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "Template_templateId_key" ON "Template"("templateId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Template_name_key" ON "Template"("name"); + +-- AddForeignKey +ALTER TABLE "Template" ADD CONSTRAINT "Template_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/postgresql-migrations/20240725202651_add_webhook_url_template_table/migration.sql b/prisma/postgresql-migrations/20240725202651_add_webhook_url_template_table/migration.sql new file mode 100644 index 00000000..ecb55e49 --- /dev/null +++ b/prisma/postgresql-migrations/20240725202651_add_webhook_url_template_table/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "Template" ADD COLUMN "webhookUrl" VARCHAR(500); diff --git a/prisma/postgresql-migrations/20240725221646_modify_token_instance_table/migration.sql b/prisma/postgresql-migrations/20240725221646_modify_token_instance_table/migration.sql new file mode 100644 index 00000000..632509e0 --- /dev/null +++ b/prisma/postgresql-migrations/20240725221646_modify_token_instance_table/migration.sql @@ -0,0 +1,2 @@ +-- DropIndex +DROP INDEX "Instance_token_key"; diff --git a/prisma/postgresql-migrations/20240729115127_modify_trigger_type_openai_typebot_table/migration.sql b/prisma/postgresql-migrations/20240729115127_modify_trigger_type_openai_typebot_table/migration.sql new file mode 100644 index 00000000..cb5a2505 --- /dev/null +++ b/prisma/postgresql-migrations/20240729115127_modify_trigger_type_openai_typebot_table/migration.sql @@ -0,0 +1,2 @@ +-- AlterEnum +ALTER TYPE "TriggerType" ADD VALUE 'none'; diff --git a/prisma/postgresql-migrations/20240729180347_modify_typebot_session_status_openai_typebot_table/migration.sql b/prisma/postgresql-migrations/20240729180347_modify_typebot_session_status_openai_typebot_table/migration.sql new file mode 100644 index 00000000..2fad828c --- /dev/null +++ b/prisma/postgresql-migrations/20240729180347_modify_typebot_session_status_openai_typebot_table/migration.sql @@ -0,0 +1,20 @@ +/* + Warnings: + + - The values [open] on the enum `TypebotSessionStatus` will be removed. If these variants are still used in the database, this will fail. + - Changed the type of `status` on the `TypebotSession` table. No cast exists, the column would be dropped and recreated, which cannot be done if there is data, since the column is required. + +*/ +-- AlterEnum +BEGIN; +CREATE TYPE "TypebotSessionStatus_new" AS ENUM ('opened', 'closed', 'paused'); +ALTER TABLE "TypebotSession" ALTER COLUMN "status" TYPE "TypebotSessionStatus_new" USING ("status"::text::"TypebotSessionStatus_new"); +ALTER TABLE "OpenaiSession" ALTER COLUMN "status" TYPE "TypebotSessionStatus_new" USING ("status"::text::"TypebotSessionStatus_new"); +ALTER TYPE "TypebotSessionStatus" RENAME TO "TypebotSessionStatus_old"; +ALTER TYPE "TypebotSessionStatus_new" RENAME TO "TypebotSessionStatus"; +DROP TYPE "TypebotSessionStatus_old"; +COMMIT; + +-- AlterTable +ALTER TABLE "TypebotSession" DROP COLUMN "status", +ADD COLUMN "status" "TypebotSessionStatus" NOT NULL; diff --git a/prisma/postgresql-migrations/20240730152156_create_dify_tables/migration.sql b/prisma/postgresql-migrations/20240730152156_create_dify_tables/migration.sql new file mode 100644 index 00000000..bf693f50 --- /dev/null +++ b/prisma/postgresql-migrations/20240730152156_create_dify_tables/migration.sql @@ -0,0 +1,103 @@ +/* + Warnings: + + - Changed the type of `botType` on the `OpenaiBot` table. No cast exists, the column would be dropped and recreated, which cannot be done if there is data, since the column is required. + +*/ +-- CreateEnum +CREATE TYPE "OpenaiBotType" AS ENUM ('assistant', 'chatCompletion'); + +-- CreateEnum +CREATE TYPE "DifyBotType" AS ENUM ('chatBot', 'textGenerator', 'agent', 'workflow'); + +-- DropIndex +DROP INDEX "OpenaiBot_assistantId_key"; + +-- AlterTable +ALTER TABLE "Message" ADD COLUMN "difySessionId" TEXT; + +-- AlterTable +ALTER TABLE "OpenaiBot" DROP COLUMN "botType", +ADD COLUMN "botType" "OpenaiBotType" NOT NULL; + +-- CreateTable +CREATE TABLE "Dify" ( + "id" TEXT NOT NULL, + "enabled" BOOLEAN NOT NULL DEFAULT true, + "botType" "DifyBotType" NOT NULL, + "apiUrl" VARCHAR(255), + "apiKey" VARCHAR(255), + "expire" INTEGER DEFAULT 0, + "keywordFinish" VARCHAR(100), + "delayMessage" INTEGER, + "unknownMessage" VARCHAR(100), + "listeningFromMe" BOOLEAN DEFAULT false, + "stopBotFromMe" BOOLEAN DEFAULT false, + "keepOpen" BOOLEAN DEFAULT false, + "debounceTime" INTEGER, + "ignoreJids" JSONB, + "triggerType" "TriggerType", + "triggerOperator" "TriggerOperator", + "triggerValue" TEXT, + "createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP NOT NULL, + "instanceId" TEXT NOT NULL, + + CONSTRAINT "Dify_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "DifySession" ( + "id" TEXT NOT NULL, + "sessionId" VARCHAR(255) NOT NULL, + "remoteJid" VARCHAR(100) NOT NULL, + "status" "TypebotSessionStatus" NOT NULL, + "awaitUser" BOOLEAN NOT NULL DEFAULT false, + "createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP NOT NULL, + "difyId" TEXT NOT NULL, + "instanceId" TEXT NOT NULL, + + CONSTRAINT "DifySession_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "DifySetting" ( + "id" TEXT NOT NULL, + "expire" INTEGER DEFAULT 0, + "keywordFinish" VARCHAR(100), + "delayMessage" INTEGER, + "unknownMessage" VARCHAR(100), + "listeningFromMe" BOOLEAN DEFAULT false, + "stopBotFromMe" BOOLEAN DEFAULT false, + "keepOpen" BOOLEAN DEFAULT false, + "debounceTime" INTEGER, + "ignoreJids" JSONB, + "createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP NOT NULL, + "difyIdFallback" VARCHAR(100), + "instanceId" TEXT NOT NULL, + + CONSTRAINT "DifySetting_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "DifySetting_instanceId_key" ON "DifySetting"("instanceId"); + +-- AddForeignKey +ALTER TABLE "Message" ADD CONSTRAINT "Message_difySessionId_fkey" FOREIGN KEY ("difySessionId") REFERENCES "DifySession"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Dify" ADD CONSTRAINT "Dify_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "DifySession" ADD CONSTRAINT "DifySession_difyId_fkey" FOREIGN KEY ("difyId") REFERENCES "Dify"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "DifySession" ADD CONSTRAINT "DifySession_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "DifySetting" ADD CONSTRAINT "DifySetting_difyIdFallback_fkey" FOREIGN KEY ("difyIdFallback") REFERENCES "Dify"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "DifySetting" ADD CONSTRAINT "DifySetting_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/postgresql-migrations/20240801193907_add_column_speech_to_text_openai_setting_table/migration.sql b/prisma/postgresql-migrations/20240801193907_add_column_speech_to_text_openai_setting_table/migration.sql new file mode 100644 index 00000000..1f8e1fe5 --- /dev/null +++ b/prisma/postgresql-migrations/20240801193907_add_column_speech_to_text_openai_setting_table/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "OpenaiSetting" ADD COLUMN "speechToText" BOOLEAN DEFAULT false; diff --git a/prisma/postgresql-migrations/20240803163908_add_column_description_on_integrations_table/migration.sql b/prisma/postgresql-migrations/20240803163908_add_column_description_on_integrations_table/migration.sql new file mode 100644 index 00000000..e948023b --- /dev/null +++ b/prisma/postgresql-migrations/20240803163908_add_column_description_on_integrations_table/migration.sql @@ -0,0 +1,8 @@ +-- AlterTable +ALTER TABLE "Dify" ADD COLUMN "description" VARCHAR(255); + +-- AlterTable +ALTER TABLE "OpenaiBot" ADD COLUMN "description" VARCHAR(255); + +-- AlterTable +ALTER TABLE "Typebot" ADD COLUMN "description" VARCHAR(255); diff --git a/prisma/postgresql-migrations/20240808210239_add_column_function_url_openaibot_table/migration.sql b/prisma/postgresql-migrations/20240808210239_add_column_function_url_openaibot_table/migration.sql new file mode 100644 index 00000000..16ca6b5d --- /dev/null +++ b/prisma/postgresql-migrations/20240808210239_add_column_function_url_openaibot_table/migration.sql @@ -0,0 +1,7 @@ +-- AlterTable +ALTER TABLE "Instance" ADD COLUMN "disconnectionAt" TIMESTAMP, +ADD COLUMN "disconnectionObject" JSONB, +ADD COLUMN "disconnectionReasonCode" INTEGER; + +-- AlterTable +ALTER TABLE "OpenaiBot" ADD COLUMN "functionUrl" VARCHAR(500); diff --git a/prisma/postgresql-migrations/20240811021156_add_chat_name_column/migration.sql b/prisma/postgresql-migrations/20240811021156_add_chat_name_column/migration.sql new file mode 100644 index 00000000..79d7fc1f --- /dev/null +++ b/prisma/postgresql-migrations/20240811021156_add_chat_name_column/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "Chat" ADD COLUMN "name" VARCHAR(100); diff --git a/prisma/postgresql-migrations/20240811183328_add_unique_index_for_remoted_jid_and_instance_in_contacts/migration.sql b/prisma/postgresql-migrations/20240811183328_add_unique_index_for_remoted_jid_and_instance_in_contacts/migration.sql new file mode 100644 index 00000000..1adcb7f4 --- /dev/null +++ b/prisma/postgresql-migrations/20240811183328_add_unique_index_for_remoted_jid_and_instance_in_contacts/migration.sql @@ -0,0 +1,17 @@ +/* + Warnings: + + - A unique constraint covering the columns `[remoteJid,instanceId]` on the table `Contact` will be added. If there are existing duplicate values, this will fail. + +*/ +-- Remove the duplicates +DELETE FROM "Contact" +WHERE ctid NOT IN ( + SELECT min(ctid) + FROM "Contact" + GROUP BY "remoteJid", "instanceId" +); + + +-- CreateIndex +CREATE UNIQUE INDEX "Contact_remoteJid_instanceId_key" ON "Contact"("remoteJid", "instanceId"); diff --git a/prisma/postgresql-migrations/20240813003116_make_label_unique_for_instance/migration.sql b/prisma/postgresql-migrations/20240813003116_make_label_unique_for_instance/migration.sql new file mode 100644 index 00000000..9110ed8a --- /dev/null +++ b/prisma/postgresql-migrations/20240813003116_make_label_unique_for_instance/migration.sql @@ -0,0 +1,11 @@ +/* + Warnings: + + - A unique constraint covering the columns `[labelId,instanceId]` on the table `Label` will be added. If there are existing duplicate values, this will fail. + +*/ +-- DropIndex +DROP INDEX "Label_labelId_key"; + +-- CreateIndex +CREATE UNIQUE INDEX "Label_labelId_instanceId_key" ON "Label"("labelId", "instanceId"); diff --git a/prisma/postgresql-migrations/20240814173033_add_ignore_jids_chatwoot/migration.sql b/prisma/postgresql-migrations/20240814173033_add_ignore_jids_chatwoot/migration.sql new file mode 100644 index 00000000..61470ed6 --- /dev/null +++ b/prisma/postgresql-migrations/20240814173033_add_ignore_jids_chatwoot/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "Chatwoot" ADD COLUMN "ignoreJids" JSONB; diff --git a/prisma/postgresql-migrations/20240814202359_integrations_unification/migration.sql b/prisma/postgresql-migrations/20240814202359_integrations_unification/migration.sql new file mode 100644 index 00000000..1192cf54 --- /dev/null +++ b/prisma/postgresql-migrations/20240814202359_integrations_unification/migration.sql @@ -0,0 +1,92 @@ +/* + Warnings: + + - You are about to drop the column `difySessionId` on the `Message` table. All the data in the column will be lost. + - You are about to drop the column `openaiSessionId` on the `Message` table. All the data in the column will be lost. + - You are about to drop the column `typebotSessionId` on the `Message` table. All the data in the column will be lost. + - You are about to drop the `DifySession` table. If the table is not empty, all the data it contains will be lost. + - You are about to drop the `OpenaiSession` table. If the table is not empty, all the data it contains will be lost. + - You are about to drop the `TypebotSession` table. If the table is not empty, all the data it contains will be lost. + +*/ +-- CreateEnum +CREATE TYPE "SessionStatus" AS ENUM ('opened', 'closed', 'paused'); + +-- DropForeignKey +ALTER TABLE "DifySession" DROP CONSTRAINT "DifySession_difyId_fkey"; + +-- DropForeignKey +ALTER TABLE "DifySession" DROP CONSTRAINT "DifySession_instanceId_fkey"; + +-- DropForeignKey +ALTER TABLE "Message" DROP CONSTRAINT "Message_difySessionId_fkey"; + +-- DropForeignKey +ALTER TABLE "Message" DROP CONSTRAINT "Message_openaiSessionId_fkey"; + +-- DropForeignKey +ALTER TABLE "Message" DROP CONSTRAINT "Message_typebotSessionId_fkey"; + +-- DropForeignKey +ALTER TABLE "OpenaiSession" DROP CONSTRAINT "OpenaiSession_instanceId_fkey"; + +-- DropForeignKey +ALTER TABLE "OpenaiSession" DROP CONSTRAINT "OpenaiSession_openaiBotId_fkey"; + +-- DropForeignKey +ALTER TABLE "TypebotSession" DROP CONSTRAINT "TypebotSession_instanceId_fkey"; + +-- DropForeignKey +ALTER TABLE "TypebotSession" DROP CONSTRAINT "TypebotSession_typebotId_fkey"; + +-- AlterTable +ALTER TABLE "Message" DROP COLUMN "difySessionId", +DROP COLUMN "openaiSessionId", +DROP COLUMN "typebotSessionId", +ADD COLUMN "sessionId" TEXT; + +-- DropTable +DROP TABLE "DifySession"; + +-- DropTable +DROP TABLE "OpenaiSession"; + +-- DropTable +DROP TABLE "TypebotSession"; + +-- DropEnum +DROP TYPE "TypebotSessionStatus"; + +-- CreateTable +CREATE TABLE "IntegrationSession" ( + "id" TEXT NOT NULL, + "sessionId" VARCHAR(255) NOT NULL, + "remoteJid" VARCHAR(100) NOT NULL, + "pushName" TEXT, + "status" "SessionStatus" NOT NULL, + "awaitUser" BOOLEAN NOT NULL DEFAULT false, + "createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP NOT NULL, + "instanceId" TEXT NOT NULL, + "parameters" JSONB, + "openaiBotId" TEXT, + "difyId" TEXT, + "typebotId" TEXT, + + CONSTRAINT "IntegrationSession_pkey" PRIMARY KEY ("id") +); + +-- AddForeignKey +ALTER TABLE "Message" ADD CONSTRAINT "Message_sessionId_fkey" FOREIGN KEY ("sessionId") REFERENCES "IntegrationSession"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "IntegrationSession" ADD CONSTRAINT "IntegrationSession_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "IntegrationSession" ADD CONSTRAINT "IntegrationSession_openaiBotId_fkey" FOREIGN KEY ("openaiBotId") REFERENCES "OpenaiBot"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "IntegrationSession" ADD CONSTRAINT "IntegrationSession_difyId_fkey" FOREIGN KEY ("difyId") REFERENCES "Dify"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "IntegrationSession" ADD CONSTRAINT "IntegrationSession_typebotId_fkey" FOREIGN KEY ("typebotId") REFERENCES "Typebot"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/postgresql-migrations/20240817110155_add_trigger_type_advanced/migration.sql b/prisma/postgresql-migrations/20240817110155_add_trigger_type_advanced/migration.sql new file mode 100644 index 00000000..9d88fe37 --- /dev/null +++ b/prisma/postgresql-migrations/20240817110155_add_trigger_type_advanced/migration.sql @@ -0,0 +1,2 @@ +-- AlterEnum +ALTER TYPE "TriggerType" ADD VALUE 'advanced'; diff --git a/prisma/postgresql-migrations/20240819154941_add_context_to_integration_session/migration.sql b/prisma/postgresql-migrations/20240819154941_add_context_to_integration_session/migration.sql new file mode 100644 index 00000000..68adcd8c --- /dev/null +++ b/prisma/postgresql-migrations/20240819154941_add_context_to_integration_session/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "IntegrationSession" ADD COLUMN "context" JSONB; diff --git a/prisma/postgresql-migrations/20240821120816_bot_id_integration_session/migration.sql b/prisma/postgresql-migrations/20240821120816_bot_id_integration_session/migration.sql new file mode 100644 index 00000000..bfe174b6 --- /dev/null +++ b/prisma/postgresql-migrations/20240821120816_bot_id_integration_session/migration.sql @@ -0,0 +1,22 @@ +/* + Warnings: + + - You are about to drop the column `difyId` on the `IntegrationSession` table. All the data in the column will be lost. + - You are about to drop the column `openaiBotId` on the `IntegrationSession` table. All the data in the column will be lost. + - You are about to drop the column `typebotId` on the `IntegrationSession` table. All the data in the column will be lost. + +*/ +-- DropForeignKey +ALTER TABLE "IntegrationSession" DROP CONSTRAINT "IntegrationSession_difyId_fkey"; + +-- DropForeignKey +ALTER TABLE "IntegrationSession" DROP CONSTRAINT "IntegrationSession_openaiBotId_fkey"; + +-- DropForeignKey +ALTER TABLE "IntegrationSession" DROP CONSTRAINT "IntegrationSession_typebotId_fkey"; + +-- AlterTable +ALTER TABLE "IntegrationSession" DROP COLUMN "difyId", +DROP COLUMN "openaiBotId", +DROP COLUMN "typebotId", +ADD COLUMN "botId" TEXT; diff --git a/prisma/postgresql-migrations/20240821171327_add_generic_bot_table/migration.sql b/prisma/postgresql-migrations/20240821171327_add_generic_bot_table/migration.sql new file mode 100644 index 00000000..6ea99e2b --- /dev/null +++ b/prisma/postgresql-migrations/20240821171327_add_generic_bot_table/migration.sql @@ -0,0 +1,57 @@ +-- CreateTable +CREATE TABLE "GenericBot" ( + "id" TEXT NOT NULL, + "enabled" BOOLEAN NOT NULL DEFAULT true, + "description" VARCHAR(255), + "apiUrl" VARCHAR(255), + "apiKey" VARCHAR(255), + "expire" INTEGER DEFAULT 0, + "keywordFinish" VARCHAR(100), + "delayMessage" INTEGER, + "unknownMessage" VARCHAR(100), + "listeningFromMe" BOOLEAN DEFAULT false, + "stopBotFromMe" BOOLEAN DEFAULT false, + "keepOpen" BOOLEAN DEFAULT false, + "debounceTime" INTEGER, + "ignoreJids" JSONB, + "triggerType" "TriggerType", + "triggerOperator" "TriggerOperator", + "triggerValue" TEXT, + "createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP NOT NULL, + "instanceId" TEXT NOT NULL, + + CONSTRAINT "GenericBot_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "GenericSetting" ( + "id" TEXT NOT NULL, + "expire" INTEGER DEFAULT 0, + "keywordFinish" VARCHAR(100), + "delayMessage" INTEGER, + "unknownMessage" VARCHAR(100), + "listeningFromMe" BOOLEAN DEFAULT false, + "stopBotFromMe" BOOLEAN DEFAULT false, + "keepOpen" BOOLEAN DEFAULT false, + "debounceTime" INTEGER, + "ignoreJids" JSONB, + "createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP NOT NULL, + "botIdFallback" VARCHAR(100), + "instanceId" TEXT NOT NULL, + + CONSTRAINT "GenericSetting_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "GenericSetting_instanceId_key" ON "GenericSetting"("instanceId"); + +-- AddForeignKey +ALTER TABLE "GenericBot" ADD CONSTRAINT "GenericBot_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "GenericSetting" ADD CONSTRAINT "GenericSetting_botIdFallback_fkey" FOREIGN KEY ("botIdFallback") REFERENCES "GenericBot"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "GenericSetting" ADD CONSTRAINT "GenericSetting_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/postgresql-migrations/20240821194524_add_flowise_table/migration.sql b/prisma/postgresql-migrations/20240821194524_add_flowise_table/migration.sql new file mode 100644 index 00000000..e61141ae --- /dev/null +++ b/prisma/postgresql-migrations/20240821194524_add_flowise_table/migration.sql @@ -0,0 +1,57 @@ +-- CreateTable +CREATE TABLE "Flowise" ( + "id" TEXT NOT NULL, + "enabled" BOOLEAN NOT NULL DEFAULT true, + "description" VARCHAR(255), + "apiUrl" VARCHAR(255), + "apiKey" VARCHAR(255), + "expire" INTEGER DEFAULT 0, + "keywordFinish" VARCHAR(100), + "delayMessage" INTEGER, + "unknownMessage" VARCHAR(100), + "listeningFromMe" BOOLEAN DEFAULT false, + "stopBotFromMe" BOOLEAN DEFAULT false, + "keepOpen" BOOLEAN DEFAULT false, + "debounceTime" INTEGER, + "ignoreJids" JSONB, + "triggerType" "TriggerType", + "triggerOperator" "TriggerOperator", + "triggerValue" TEXT, + "createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP NOT NULL, + "instanceId" TEXT NOT NULL, + + CONSTRAINT "Flowise_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "FlowiseSetting" ( + "id" TEXT NOT NULL, + "expire" INTEGER DEFAULT 0, + "keywordFinish" VARCHAR(100), + "delayMessage" INTEGER, + "unknownMessage" VARCHAR(100), + "listeningFromMe" BOOLEAN DEFAULT false, + "stopBotFromMe" BOOLEAN DEFAULT false, + "keepOpen" BOOLEAN DEFAULT false, + "debounceTime" INTEGER, + "ignoreJids" JSONB, + "createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP NOT NULL, + "flowiseIdFallback" VARCHAR(100), + "instanceId" TEXT NOT NULL, + + CONSTRAINT "FlowiseSetting_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "FlowiseSetting_instanceId_key" ON "FlowiseSetting"("instanceId"); + +-- AddForeignKey +ALTER TABLE "Flowise" ADD CONSTRAINT "Flowise_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "FlowiseSetting" ADD CONSTRAINT "FlowiseSetting_flowiseIdFallback_fkey" FOREIGN KEY ("flowiseIdFallback") REFERENCES "Flowise"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "FlowiseSetting" ADD CONSTRAINT "FlowiseSetting_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/postgresql-migrations/20240824161333_add_type_on_integration_sessions/migration.sql b/prisma/postgresql-migrations/20240824161333_add_type_on_integration_sessions/migration.sql new file mode 100644 index 00000000..954c2560 --- /dev/null +++ b/prisma/postgresql-migrations/20240824161333_add_type_on_integration_sessions/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "IntegrationSession" ADD COLUMN "type" VARCHAR(100); diff --git a/prisma/postgresql-migrations/20240825130616_change_to_evolution_bot/migration.sql b/prisma/postgresql-migrations/20240825130616_change_to_evolution_bot/migration.sql new file mode 100644 index 00000000..11880ee3 --- /dev/null +++ b/prisma/postgresql-migrations/20240825130616_change_to_evolution_bot/migration.sql @@ -0,0 +1,79 @@ +/* + Warnings: + + - You are about to drop the `GenericBot` table. If the table is not empty, all the data it contains will be lost. + - You are about to drop the `GenericSetting` table. If the table is not empty, all the data it contains will be lost. + +*/ +-- DropForeignKey +ALTER TABLE "GenericBot" DROP CONSTRAINT "GenericBot_instanceId_fkey"; + +-- DropForeignKey +ALTER TABLE "GenericSetting" DROP CONSTRAINT "GenericSetting_botIdFallback_fkey"; + +-- DropForeignKey +ALTER TABLE "GenericSetting" DROP CONSTRAINT "GenericSetting_instanceId_fkey"; + +-- DropTable +DROP TABLE "GenericBot"; + +-- DropTable +DROP TABLE "GenericSetting"; + +-- CreateTable +CREATE TABLE "EvolutionBot" ( + "id" TEXT NOT NULL, + "enabled" BOOLEAN NOT NULL DEFAULT true, + "description" VARCHAR(255), + "apiUrl" VARCHAR(255), + "apiKey" VARCHAR(255), + "expire" INTEGER DEFAULT 0, + "keywordFinish" VARCHAR(100), + "delayMessage" INTEGER, + "unknownMessage" VARCHAR(100), + "listeningFromMe" BOOLEAN DEFAULT false, + "stopBotFromMe" BOOLEAN DEFAULT false, + "keepOpen" BOOLEAN DEFAULT false, + "debounceTime" INTEGER, + "ignoreJids" JSONB, + "triggerType" "TriggerType", + "triggerOperator" "TriggerOperator", + "triggerValue" TEXT, + "createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP NOT NULL, + "instanceId" TEXT NOT NULL, + + CONSTRAINT "EvolutionBot_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "EvolutionBotSetting" ( + "id" TEXT NOT NULL, + "expire" INTEGER DEFAULT 0, + "keywordFinish" VARCHAR(100), + "delayMessage" INTEGER, + "unknownMessage" VARCHAR(100), + "listeningFromMe" BOOLEAN DEFAULT false, + "stopBotFromMe" BOOLEAN DEFAULT false, + "keepOpen" BOOLEAN DEFAULT false, + "debounceTime" INTEGER, + "ignoreJids" JSONB, + "createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP NOT NULL, + "botIdFallback" VARCHAR(100), + "instanceId" TEXT NOT NULL, + + CONSTRAINT "EvolutionBotSetting_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "EvolutionBotSetting_instanceId_key" ON "EvolutionBotSetting"("instanceId"); + +-- AddForeignKey +ALTER TABLE "EvolutionBot" ADD CONSTRAINT "EvolutionBot_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "EvolutionBotSetting" ADD CONSTRAINT "EvolutionBotSetting_botIdFallback_fkey" FOREIGN KEY ("botIdFallback") REFERENCES "EvolutionBot"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "EvolutionBotSetting" ADD CONSTRAINT "EvolutionBotSetting_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/postgresql-migrations/20240828140837_add_is_on_whatsapp_table/migration.sql b/prisma/postgresql-migrations/20240828140837_add_is_on_whatsapp_table/migration.sql new file mode 100644 index 00000000..bb577211 --- /dev/null +++ b/prisma/postgresql-migrations/20240828140837_add_is_on_whatsapp_table/migration.sql @@ -0,0 +1,14 @@ +-- CreateTable +CREATE TABLE "is_on_whatsapp" ( + "id" TEXT NOT NULL, + "remote_jid" VARCHAR(100) NOT NULL, + "name" TEXT, + "jid_options" TEXT NOT NULL, + "created_at" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP NOT NULL, + + CONSTRAINT "is_on_whatsapp_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "is_on_whatsapp_remote_jid_key" ON "is_on_whatsapp"("remote_jid"); diff --git a/prisma/postgresql-migrations/20240828141556_remove_name_column_from_on_whatsapp_table/migration.sql b/prisma/postgresql-migrations/20240828141556_remove_name_column_from_on_whatsapp_table/migration.sql new file mode 100644 index 00000000..de907df7 --- /dev/null +++ b/prisma/postgresql-migrations/20240828141556_remove_name_column_from_on_whatsapp_table/migration.sql @@ -0,0 +1,8 @@ +/* + Warnings: + + - You are about to drop the column `name` on the `is_on_whatsapp` table. All the data in the column will be lost. + +*/ +-- AlterTable +ALTER TABLE "is_on_whatsapp" DROP COLUMN "name"; diff --git a/prisma/postgresql-migrations/20240830193533_changed_table_case/migration.sql b/prisma/postgresql-migrations/20240830193533_changed_table_case/migration.sql new file mode 100644 index 00000000..209dd18c --- /dev/null +++ b/prisma/postgresql-migrations/20240830193533_changed_table_case/migration.sql @@ -0,0 +1,22 @@ +/* + Warnings: + + - You are about to drop the `is_on_whatsapp` table. If the table is not empty, all the data it contains will be lost. + +*/ +-- DropTable +DROP TABLE "is_on_whatsapp"; + +-- CreateTable +CREATE TABLE "IsOnWhatsapp" ( + "id" TEXT NOT NULL, + "remoteJid" VARCHAR(100) NOT NULL, + "jidOptions" TEXT NOT NULL, + "createdAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP NOT NULL, + + CONSTRAINT "IsOnWhatsapp_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "IsOnWhatsapp_remoteJid_key" ON "IsOnWhatsapp"("remoteJid"); diff --git a/prisma/postgresql-migrations/20240906202019_add_headers_on_webhook_config/migration.sql b/prisma/postgresql-migrations/20240906202019_add_headers_on_webhook_config/migration.sql new file mode 100644 index 00000000..1dc3ccbc --- /dev/null +++ b/prisma/postgresql-migrations/20240906202019_add_headers_on_webhook_config/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "Webhook" ADD COLUMN "headers" JSONB; diff --git a/prisma/postgresql-migrations/20241001180457_add_message_status/migration.sql b/prisma/postgresql-migrations/20241001180457_add_message_status/migration.sql new file mode 100644 index 00000000..7bfb86b8 --- /dev/null +++ b/prisma/postgresql-migrations/20241001180457_add_message_status/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "Message" ADD COLUMN "status" INTEGER; diff --git a/prisma/postgresql-migrations/20241006130306_alter_status_on_message_table/migration.sql b/prisma/postgresql-migrations/20241006130306_alter_status_on_message_table/migration.sql new file mode 100644 index 00000000..7f20bfc8 --- /dev/null +++ b/prisma/postgresql-migrations/20241006130306_alter_status_on_message_table/migration.sql @@ -0,0 +1,7 @@ +-- AlterTable +ALTER TABLE "Message" +ALTER COLUMN "status" +SET + DATA TYPE VARCHAR(30); + +UPDATE "Message" SET "status" = 'PENDING'; \ No newline at end of file diff --git a/prisma/postgresql-migrations/20241007164026_add_unread_messages_on_chat_table/migration.sql b/prisma/postgresql-migrations/20241007164026_add_unread_messages_on_chat_table/migration.sql new file mode 100644 index 00000000..5a62ee08 --- /dev/null +++ b/prisma/postgresql-migrations/20241007164026_add_unread_messages_on_chat_table/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "Chat" ADD COLUMN "unreadMessages" INTEGER NOT NULL DEFAULT 0; diff --git a/prisma/postgresql-migrations/20241011085129_create_pusher_table/migration.sql b/prisma/postgresql-migrations/20241011085129_create_pusher_table/migration.sql new file mode 100644 index 00000000..fa5d1965 --- /dev/null +++ b/prisma/postgresql-migrations/20241011085129_create_pusher_table/migration.sql @@ -0,0 +1,22 @@ +-- CreateTable +CREATE TABLE "Pusher" ( + "id" TEXT NOT NULL, + "enabled" BOOLEAN NOT NULL DEFAULT false, + "appId" VARCHAR(100) NOT NULL, + "key" VARCHAR(100) NOT NULL, + "secret" VARCHAR(100) NOT NULL, + "cluster" VARCHAR(100) NOT NULL, + "useTLS" BOOLEAN NOT NULL DEFAULT false, + "events" JSONB NOT NULL, + "createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP NOT NULL, + "instanceId" TEXT NOT NULL, + + CONSTRAINT "Pusher_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "Pusher_instanceId_key" ON "Pusher"("instanceId"); + +-- AddForeignKey +ALTER TABLE "Pusher" ADD CONSTRAINT "Pusher_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/postgresql-migrations/20241011100803_split_messages_and_time_per_char_integrations/migration.sql b/prisma/postgresql-migrations/20241011100803_split_messages_and_time_per_char_integrations/migration.sql new file mode 100644 index 00000000..de3f8095 --- /dev/null +++ b/prisma/postgresql-migrations/20241011100803_split_messages_and_time_per_char_integrations/migration.sql @@ -0,0 +1,31 @@ +-- AlterTable +ALTER TABLE "Dify" ADD COLUMN "splitMessages" BOOLEAN DEFAULT false, +ADD COLUMN "timePerChar" INTEGER DEFAULT 50; + +-- AlterTable +ALTER TABLE "DifySetting" ADD COLUMN "splitMessages" BOOLEAN DEFAULT false, +ADD COLUMN "timePerChar" INTEGER DEFAULT 50; + +-- AlterTable +ALTER TABLE "EvolutionBot" ADD COLUMN "splitMessages" BOOLEAN DEFAULT false, +ADD COLUMN "timePerChar" INTEGER DEFAULT 50; + +-- AlterTable +ALTER TABLE "EvolutionBotSetting" ADD COLUMN "splitMessages" BOOLEAN DEFAULT false, +ADD COLUMN "timePerChar" INTEGER DEFAULT 50; + +-- AlterTable +ALTER TABLE "Flowise" ADD COLUMN "splitMessages" BOOLEAN DEFAULT false, +ADD COLUMN "timePerChar" INTEGER DEFAULT 50; + +-- AlterTable +ALTER TABLE "FlowiseSetting" ADD COLUMN "splitMessages" BOOLEAN DEFAULT false, +ADD COLUMN "timePerChar" INTEGER DEFAULT 50; + +-- AlterTable +ALTER TABLE "OpenaiBot" ADD COLUMN "splitMessages" BOOLEAN DEFAULT false, +ADD COLUMN "timePerChar" INTEGER DEFAULT 50; + +-- AlterTable +ALTER TABLE "OpenaiSetting" ADD COLUMN "splitMessages" BOOLEAN DEFAULT false, +ADD COLUMN "timePerChar" INTEGER DEFAULT 50; diff --git a/prisma/postgresql-migrations/20241017144950_create_index/migration.sql b/prisma/postgresql-migrations/20241017144950_create_index/migration.sql new file mode 100644 index 00000000..803fafc1 --- /dev/null +++ b/prisma/postgresql-migrations/20241017144950_create_index/migration.sql @@ -0,0 +1,26 @@ +-- CreateIndex +CREATE INDEX "Chat_instanceId_idx" ON "Chat"("instanceId"); + +-- CreateIndex +CREATE INDEX "Chat_remoteJid_idx" ON "Chat"("remoteJid"); + +-- CreateIndex +CREATE INDEX "Contact_remoteJid_idx" ON "Contact"("remoteJid"); + +-- CreateIndex +CREATE INDEX "Contact_instanceId_idx" ON "Contact"("instanceId"); + +-- CreateIndex +CREATE INDEX "Message_instanceId_idx" ON "Message"("instanceId"); + +-- CreateIndex +CREATE INDEX "MessageUpdate_instanceId_idx" ON "MessageUpdate"("instanceId"); + +-- CreateIndex +CREATE INDEX "MessageUpdate_messageId_idx" ON "MessageUpdate"("messageId"); + +-- CreateIndex +CREATE INDEX "Setting_instanceId_idx" ON "Setting"("instanceId"); + +-- CreateIndex +CREATE INDEX "Webhook_instanceId_idx" ON "Webhook"("instanceId"); diff --git a/prisma/postgresql-migrations/20250116001415_add_wavoip_token_to_settings_table/migration.sql b/prisma/postgresql-migrations/20250116001415_add_wavoip_token_to_settings_table/migration.sql new file mode 100644 index 00000000..26898a08 --- /dev/null +++ b/prisma/postgresql-migrations/20250116001415_add_wavoip_token_to_settings_table/migration.sql @@ -0,0 +1,19 @@ +/* +Warnings: + +- A unique constraint covering the columns `[remoteJid,instanceId]` on the table `Chat` will be added. If there are existing duplicate values, this will fail. + +*/ + +-- AlterTable +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 + FROM information_schema.columns + WHERE table_name = 'Setting' + AND column_name = 'wavoipToken' + ) THEN + ALTER TABLE "Setting" ADD COLUMN "wavoipToken" VARCHAR(100); + END IF; +END $$; \ No newline at end of file diff --git a/prisma/postgresql-migrations/migration_lock.toml b/prisma/postgresql-migrations/migration_lock.toml new file mode 100644 index 00000000..fbffa92c --- /dev/null +++ b/prisma/postgresql-migrations/migration_lock.toml @@ -0,0 +1,3 @@ +# Please do not edit this file manually +# It should be added in your version-control system (i.e. Git) +provider = "postgresql" \ No newline at end of file diff --git a/prisma/postgresql-schema.prisma b/prisma/postgresql-schema.prisma new file mode 100644 index 00000000..a9782ce5 --- /dev/null +++ b/prisma/postgresql-schema.prisma @@ -0,0 +1,629 @@ +// This is your Prisma schema file, +// learn more about it in the docs: https://pris.ly/d/prisma-schema + +// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions? +// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init + +generator client { + provider = "prisma-client-js" +} + +datasource db { + provider = "postgresql" + url = env("DATABASE_CONNECTION_URI") +} + +enum InstanceConnectionStatus { + open + close + connecting +} + +enum DeviceMessage { + ios + android + web + unknown + desktop +} + +enum SessionStatus { + opened + closed + paused +} + +enum TriggerType { + all + keyword + none + advanced +} + +enum TriggerOperator { + contains + equals + startsWith + endsWith + regex +} + +enum OpenaiBotType { + assistant + chatCompletion +} + +enum DifyBotType { + chatBot + textGenerator + agent + workflow +} + +model Instance { + id String @id @default(cuid()) + name String @unique @db.VarChar(255) + connectionStatus InstanceConnectionStatus @default(open) + ownerJid String? @db.VarChar(100) + profileName String? @db.VarChar(100) + profilePicUrl String? @db.VarChar(500) + integration String? @db.VarChar(100) + number String? @db.VarChar(100) + businessId String? @db.VarChar(100) + token String? @db.VarChar(255) + clientName String? @db.VarChar(100) + disconnectionReasonCode Int? @db.Integer + disconnectionObject Json? @db.JsonB + disconnectionAt DateTime? @db.Timestamp + createdAt DateTime? @default(now()) @db.Timestamp + updatedAt DateTime? @updatedAt @db.Timestamp + Chat Chat[] + Contact Contact[] + Message Message[] + Webhook Webhook? + Chatwoot Chatwoot? + Label Label[] + Proxy Proxy? + Setting Setting? + Rabbitmq Rabbitmq? + Sqs Sqs? + Websocket Websocket? + Typebot Typebot[] + Session Session? + MessageUpdate MessageUpdate[] + TypebotSetting TypebotSetting? + Media Media[] + OpenaiCreds OpenaiCreds[] + OpenaiBot OpenaiBot[] + OpenaiSetting OpenaiSetting? + Template Template[] + Dify Dify[] + DifySetting DifySetting? + integrationSessions IntegrationSession[] + EvolutionBot EvolutionBot[] + EvolutionBotSetting EvolutionBotSetting? + Flowise Flowise[] + FlowiseSetting FlowiseSetting? + Pusher Pusher? +} + +model Session { + id String @id @default(cuid()) + sessionId String @unique + creds String? @db.Text + createdAt DateTime @default(now()) @db.Timestamp + Instance Instance @relation(fields: [sessionId], references: [id], onDelete: Cascade) +} + +model Chat { + id String @id @default(cuid()) + remoteJid String @db.VarChar(100) + name String? @db.VarChar(100) + labels Json? @db.JsonB + createdAt DateTime? @default(now()) @db.Timestamp + updatedAt DateTime? @updatedAt @db.Timestamp + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String + unreadMessages Int @default(0) + @@index([instanceId]) + @@index([remoteJid]) +} + +model Contact { + id String @id @default(cuid()) + remoteJid String @db.VarChar(100) + pushName String? @db.VarChar(100) + profilePicUrl String? @db.VarChar(500) + createdAt DateTime? @default(now()) @db.Timestamp + updatedAt DateTime? @updatedAt @db.Timestamp + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String + + @@unique([remoteJid, instanceId]) + @@index([remoteJid]) + @@index([instanceId]) +} + +model Message { + id String @id @default(cuid()) + key Json @db.JsonB + pushName String? @db.VarChar(100) + participant String? @db.VarChar(100) + messageType String @db.VarChar(100) + message Json @db.JsonB + contextInfo Json? @db.JsonB + source DeviceMessage + messageTimestamp Int @db.Integer + chatwootMessageId Int? @db.Integer + chatwootInboxId Int? @db.Integer + chatwootConversationId Int? @db.Integer + chatwootContactInboxSourceId String? @db.VarChar(100) + chatwootIsRead Boolean? @db.Boolean + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String + MessageUpdate MessageUpdate[] + Media Media? + webhookUrl String? @db.VarChar(500) + status String? @db.VarChar(30) + + sessionId String? + session IntegrationSession? @relation(fields: [sessionId], references: [id]) + @@index([instanceId]) +} + +model MessageUpdate { + id String @id @default(cuid()) + keyId String @db.VarChar(100) + remoteJid String @db.VarChar(100) + fromMe Boolean @db.Boolean + participant String? @db.VarChar(100) + pollUpdates Json? @db.JsonB + status String @db.VarChar(30) + Message Message @relation(fields: [messageId], references: [id], onDelete: Cascade) + messageId String + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String + @@index([instanceId]) + @@index([messageId]) +} + +model Webhook { + id String @id @default(cuid()) + url String @db.VarChar(500) + headers Json? @db.JsonB + enabled Boolean? @default(true) @db.Boolean + events Json? @db.JsonB + webhookByEvents Boolean? @default(false) @db.Boolean + webhookBase64 Boolean? @default(false) @db.Boolean + createdAt DateTime? @default(now()) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String @unique + @@index([instanceId]) +} + +model Chatwoot { + id String @id @default(cuid()) + enabled Boolean? @default(true) @db.Boolean + accountId String? @db.VarChar(100) + token String? @db.VarChar(100) + url String? @db.VarChar(500) + nameInbox String? @db.VarChar(100) + signMsg Boolean? @default(false) @db.Boolean + signDelimiter String? @db.VarChar(100) + number String? @db.VarChar(100) + reopenConversation Boolean? @default(false) @db.Boolean + conversationPending Boolean? @default(false) @db.Boolean + mergeBrazilContacts Boolean? @default(false) @db.Boolean + importContacts Boolean? @default(false) @db.Boolean + importMessages Boolean? @default(false) @db.Boolean + daysLimitImportMessages Int? @db.Integer + organization String? @db.VarChar(100) + logo String? @db.VarChar(500) + ignoreJids Json? + createdAt DateTime? @default(now()) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String @unique +} + +model Label { + id String @id @default(cuid()) + labelId String? @db.VarChar(100) + name String @db.VarChar(100) + color String @db.VarChar(100) + predefinedId String? @db.VarChar(100) + createdAt DateTime? @default(now()) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String + + @@unique([labelId, instanceId]) +} + +model Proxy { + id String @id @default(cuid()) + enabled Boolean @default(false) @db.Boolean + host String @db.VarChar(100) + port String @db.VarChar(100) + protocol String @db.VarChar(100) + username String @db.VarChar(100) + password String @db.VarChar(100) + createdAt DateTime? @default(now()) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String @unique +} + +model Setting { + id String @id @default(cuid()) + rejectCall Boolean @default(false) @db.Boolean + msgCall String? @db.VarChar(100) + groupsIgnore Boolean @default(false) @db.Boolean + alwaysOnline Boolean @default(false) @db.Boolean + readMessages Boolean @default(false) @db.Boolean + readStatus Boolean @default(false) @db.Boolean + syncFullHistory Boolean @default(false) @db.Boolean + wavoipToken String? @db.VarChar(100) + createdAt DateTime? @default(now()) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String @unique + @@index([instanceId]) +} + +model Rabbitmq { + id String @id @default(cuid()) + enabled Boolean @default(false) @db.Boolean + events Json @db.JsonB + createdAt DateTime? @default(now()) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String @unique +} + +model Sqs { + id String @id @default(cuid()) + enabled Boolean @default(false) @db.Boolean + events Json @db.JsonB + createdAt DateTime? @default(now()) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String @unique +} + +model Websocket { + id String @id @default(cuid()) + enabled Boolean @default(false) @db.Boolean + events Json @db.JsonB + createdAt DateTime? @default(now()) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String @unique +} + +model Pusher { + id String @id @default(cuid()) + enabled Boolean @default(false) @db.Boolean + appId String @db.VarChar(100) + key String @db.VarChar(100) + secret String @db.VarChar(100) + cluster String @db.VarChar(100) + useTLS Boolean @default(false) @db.Boolean + events Json @db.JsonB + createdAt DateTime? @default(now()) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String @unique +} + +model Typebot { + id String @id @default(cuid()) + enabled Boolean @default(true) @db.Boolean + description String? @db.VarChar(255) + url String @db.VarChar(500) + typebot String @db.VarChar(100) + expire Int? @default(0) @db.Integer + keywordFinish String? @db.VarChar(100) + delayMessage Int? @db.Integer + unknownMessage String? @db.VarChar(100) + listeningFromMe Boolean? @default(false) @db.Boolean + stopBotFromMe Boolean? @default(false) @db.Boolean + keepOpen Boolean? @default(false) @db.Boolean + debounceTime Int? @db.Integer + createdAt DateTime? @default(now()) @db.Timestamp + updatedAt DateTime? @updatedAt @db.Timestamp + ignoreJids Json? + triggerType TriggerType? + triggerOperator TriggerOperator? + triggerValue String? + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String + TypebotSetting TypebotSetting[] +} + +model TypebotSetting { + id String @id @default(cuid()) + expire Int? @default(0) @db.Integer + keywordFinish String? @db.VarChar(100) + delayMessage Int? @db.Integer + unknownMessage String? @db.VarChar(100) + listeningFromMe Boolean? @default(false) @db.Boolean + stopBotFromMe Boolean? @default(false) @db.Boolean + keepOpen Boolean? @default(false) @db.Boolean + debounceTime Int? @db.Integer + typebotIdFallback String? @db.VarChar(100) + ignoreJids Json? + createdAt DateTime? @default(now()) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + Fallback Typebot? @relation(fields: [typebotIdFallback], references: [id]) + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String @unique +} + +model Media { + id String @id @default(cuid()) + fileName String @unique @db.VarChar(500) + type String @db.VarChar(100) + mimetype String @db.VarChar(100) + createdAt DateTime? @default(now()) @db.Date + Message Message @relation(fields: [messageId], references: [id], onDelete: Cascade) + messageId String @unique + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String +} + +model OpenaiCreds { + id String @id @default(cuid()) + name String? @unique @db.VarChar(255) + apiKey String? @unique @db.VarChar(255) + createdAt DateTime? @default(now()) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String + OpenaiAssistant OpenaiBot[] + OpenaiSetting OpenaiSetting? +} + +model OpenaiBot { + id String @id @default(cuid()) + enabled Boolean @default(true) @db.Boolean + description String? @db.VarChar(255) + botType OpenaiBotType + assistantId String? @db.VarChar(255) + functionUrl String? @db.VarChar(500) + model String? @db.VarChar(100) + systemMessages Json? @db.JsonB + assistantMessages Json? @db.JsonB + userMessages Json? @db.JsonB + maxTokens Int? @db.Integer + expire Int? @default(0) @db.Integer + keywordFinish String? @db.VarChar(100) + delayMessage Int? @db.Integer + unknownMessage String? @db.VarChar(100) + listeningFromMe Boolean? @default(false) @db.Boolean + stopBotFromMe Boolean? @default(false) @db.Boolean + keepOpen Boolean? @default(false) @db.Boolean + debounceTime Int? @db.Integer + splitMessages Boolean? @default(false) @db.Boolean + timePerChar Int? @default(50) @db.Integer + ignoreJids Json? + triggerType TriggerType? + triggerOperator TriggerOperator? + triggerValue String? + createdAt DateTime? @default(now()) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + OpenaiCreds OpenaiCreds @relation(fields: [openaiCredsId], references: [id], onDelete: Cascade) + openaiCredsId String + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String + OpenaiSetting OpenaiSetting[] +} + +model IntegrationSession { + id String @id @default(cuid()) + sessionId String @db.VarChar(255) + remoteJid String @db.VarChar(100) + pushName String? + status SessionStatus + awaitUser Boolean @default(false) @db.Boolean + context Json? + type String? @db.VarChar(100) + createdAt DateTime? @default(now()) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + Message Message[] + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String + parameters Json? @db.JsonB + + botId String? +} + +model OpenaiSetting { + id String @id @default(cuid()) + expire Int? @default(0) @db.Integer + keywordFinish String? @db.VarChar(100) + delayMessage Int? @db.Integer + unknownMessage String? @db.VarChar(100) + listeningFromMe Boolean? @default(false) @db.Boolean + stopBotFromMe Boolean? @default(false) @db.Boolean + keepOpen Boolean? @default(false) @db.Boolean + debounceTime Int? @db.Integer + ignoreJids Json? + splitMessages Boolean? @default(false) @db.Boolean + timePerChar Int? @default(50) @db.Integer + speechToText Boolean? @default(false) @db.Boolean + createdAt DateTime? @default(now()) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + OpenaiCreds OpenaiCreds? @relation(fields: [openaiCredsId], references: [id]) + openaiCredsId String @unique + Fallback OpenaiBot? @relation(fields: [openaiIdFallback], references: [id]) + openaiIdFallback String? @db.VarChar(100) + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String @unique +} + +model Template { + id String @id @default(cuid()) + templateId String @unique @db.VarChar(255) + name String @unique @db.VarChar(255) + template Json @db.JsonB + webhookUrl String? @db.VarChar(500) + createdAt DateTime? @default(now()) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String +} + +model Dify { + id String @id @default(cuid()) + enabled Boolean @default(true) @db.Boolean + description String? @db.VarChar(255) + botType DifyBotType + apiUrl String? @db.VarChar(255) + apiKey String? @db.VarChar(255) + expire Int? @default(0) @db.Integer + keywordFinish String? @db.VarChar(100) + delayMessage Int? @db.Integer + unknownMessage String? @db.VarChar(100) + listeningFromMe Boolean? @default(false) @db.Boolean + stopBotFromMe Boolean? @default(false) @db.Boolean + keepOpen Boolean? @default(false) @db.Boolean + debounceTime Int? @db.Integer + ignoreJids Json? + splitMessages Boolean? @default(false) @db.Boolean + timePerChar Int? @default(50) @db.Integer + triggerType TriggerType? + triggerOperator TriggerOperator? + triggerValue String? + createdAt DateTime? @default(now()) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String + DifySetting DifySetting[] +} + +model DifySetting { + id String @id @default(cuid()) + expire Int? @default(0) @db.Integer + keywordFinish String? @db.VarChar(100) + delayMessage Int? @db.Integer + unknownMessage String? @db.VarChar(100) + listeningFromMe Boolean? @default(false) @db.Boolean + stopBotFromMe Boolean? @default(false) @db.Boolean + keepOpen Boolean? @default(false) @db.Boolean + debounceTime Int? @db.Integer + ignoreJids Json? + splitMessages Boolean? @default(false) @db.Boolean + timePerChar Int? @default(50) @db.Integer + createdAt DateTime? @default(now()) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + Fallback Dify? @relation(fields: [difyIdFallback], references: [id]) + difyIdFallback String? @db.VarChar(100) + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String @unique +} + +model EvolutionBot { + id String @id @default(cuid()) + enabled Boolean @default(true) @db.Boolean + description String? @db.VarChar(255) + apiUrl String? @db.VarChar(255) + apiKey String? @db.VarChar(255) + expire Int? @default(0) @db.Integer + keywordFinish String? @db.VarChar(100) + delayMessage Int? @db.Integer + unknownMessage String? @db.VarChar(100) + listeningFromMe Boolean? @default(false) @db.Boolean + stopBotFromMe Boolean? @default(false) @db.Boolean + keepOpen Boolean? @default(false) @db.Boolean + debounceTime Int? @db.Integer + ignoreJids Json? + splitMessages Boolean? @default(false) @db.Boolean + timePerChar Int? @default(50) @db.Integer + triggerType TriggerType? + triggerOperator TriggerOperator? + triggerValue String? + createdAt DateTime? @default(now()) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String + EvolutionBotSetting EvolutionBotSetting[] +} + +model EvolutionBotSetting { + id String @id @default(cuid()) + expire Int? @default(0) @db.Integer + keywordFinish String? @db.VarChar(100) + delayMessage Int? @db.Integer + unknownMessage String? @db.VarChar(100) + listeningFromMe Boolean? @default(false) @db.Boolean + stopBotFromMe Boolean? @default(false) @db.Boolean + keepOpen Boolean? @default(false) @db.Boolean + debounceTime Int? @db.Integer + ignoreJids Json? + splitMessages Boolean? @default(false) @db.Boolean + timePerChar Int? @default(50) @db.Integer + createdAt DateTime? @default(now()) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + Fallback EvolutionBot? @relation(fields: [botIdFallback], references: [id]) + botIdFallback String? @db.VarChar(100) + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String @unique +} + +model Flowise { + id String @id @default(cuid()) + enabled Boolean @default(true) @db.Boolean + description String? @db.VarChar(255) + apiUrl String? @db.VarChar(255) + apiKey String? @db.VarChar(255) + expire Int? @default(0) @db.Integer + keywordFinish String? @db.VarChar(100) + delayMessage Int? @db.Integer + unknownMessage String? @db.VarChar(100) + listeningFromMe Boolean? @default(false) @db.Boolean + stopBotFromMe Boolean? @default(false) @db.Boolean + keepOpen Boolean? @default(false) @db.Boolean + debounceTime Int? @db.Integer + ignoreJids Json? + splitMessages Boolean? @default(false) @db.Boolean + timePerChar Int? @default(50) @db.Integer + triggerType TriggerType? + triggerOperator TriggerOperator? + triggerValue String? + createdAt DateTime? @default(now()) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String + FlowiseSetting FlowiseSetting[] +} + +model FlowiseSetting { + id String @id @default(cuid()) + expire Int? @default(0) @db.Integer + keywordFinish String? @db.VarChar(100) + delayMessage Int? @db.Integer + unknownMessage String? @db.VarChar(100) + listeningFromMe Boolean? @default(false) @db.Boolean + stopBotFromMe Boolean? @default(false) @db.Boolean + keepOpen Boolean? @default(false) @db.Boolean + debounceTime Int? @db.Integer + ignoreJids Json? + splitMessages Boolean? @default(false) @db.Boolean + timePerChar Int? @default(50) @db.Integer + createdAt DateTime? @default(now()) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp + Fallback Flowise? @relation(fields: [flowiseIdFallback], references: [id]) + flowiseIdFallback String? @db.VarChar(100) + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String @unique +} + +model IsOnWhatsapp { + id String @id @default(cuid()) + remoteJid String @unique @db.VarChar(100) + jidOptions String + createdAt DateTime @default(now()) @db.Timestamp + updatedAt DateTime @updatedAt @db.Timestamp +} diff --git a/public/images/cover.png b/public/images/cover.png index f3d48bc8..57a1994f 100644 Binary files a/public/images/cover.png and b/public/images/cover.png differ diff --git a/public/images/evolution-pro.png b/public/images/evolution-pro.png new file mode 100644 index 00000000..8813f6ee Binary files /dev/null and b/public/images/evolution-pro.png differ diff --git a/runWithProvider.js b/runWithProvider.js new file mode 100644 index 00000000..154538be --- /dev/null +++ b/runWithProvider.js @@ -0,0 +1,35 @@ +const dotenv = require('dotenv'); +const { execSync } = require('child_process'); +const { existsSync } = require('fs'); + +dotenv.config(); + +const { DATABASE_PROVIDER } = process.env; +const databaseProviderDefault = DATABASE_PROVIDER ?? 'postgresql'; + +if (!DATABASE_PROVIDER) { + console.warn(`DATABASE_PROVIDER is not set in the .env file, using default: ${databaseProviderDefault}`); +} + +let command = process.argv + .slice(2) + .join(' ') + .replace(/DATABASE_PROVIDER/g, databaseProviderDefault); + +if (command.includes('rmdir') && existsSync('prisma\\migrations')) { + try { + execSync('rmdir /S /Q prisma\\migrations', { stdio: 'inherit' }); + } catch (error) { + console.error(`Error removing directory: prisma\\migrations`); + process.exit(1); + } +} else if (command.includes('rmdir')) { + console.warn(`Directory 'prisma\\migrations' does not exist, skipping removal.`); +} + +try { + execSync(command, { stdio: 'inherit' }); +} catch (error) { + console.error(`Error executing command: ${command}`); + process.exit(1); +} diff --git a/src/@types/express.d.ts b/src/@types/express.d.ts new file mode 100644 index 00000000..4df23f80 --- /dev/null +++ b/src/@types/express.d.ts @@ -0,0 +1,9 @@ +import { Multer } from 'multer'; + +declare global { + namespace Express { + interface Request { + file?: Multer.File; + } + } +} diff --git a/src/api/abstract/abstract.repository.ts b/src/api/abstract/abstract.repository.ts index a5b7a841..16bf81f9 100644 --- a/src/api/abstract/abstract.repository.ts +++ b/src/api/abstract/abstract.repository.ts @@ -1,9 +1,8 @@ +import { ConfigService, Database } from '@config/env.config'; +import { ROOT_DIR } from '@config/path.config'; import { existsSync, mkdirSync, writeFileSync } from 'fs'; import { join } from 'path'; -import { ConfigService, Database } from '../../config/env.config'; -import { ROOT_DIR } from '../../config/path.config'; - export type IInsert = { insertCount: number }; export interface IRepository { diff --git a/src/api/abstract/abstract.router.ts b/src/api/abstract/abstract.router.ts index 18770ffa..e8449a8c 100644 --- a/src/api/abstract/abstract.router.ts +++ b/src/api/abstract/abstract.router.ts @@ -1,14 +1,13 @@ import 'express-async-errors'; +import { GetParticipant, GroupInvite } from '@api/dto/group.dto'; +import { InstanceDto } from '@api/dto/instance.dto'; +import { Logger } from '@config/logger.config'; +import { BadRequestException } from '@exceptions'; import { Request } from 'express'; import { JSONSchema7 } from 'json-schema'; import { validate } from 'jsonschema'; -import { Logger } from '../../config/logger.config'; -import { BadRequestException } from '../../exceptions'; -import { GetParticipant, GroupInvite } from '../dto/group.dto'; -import { InstanceDto } from '../dto/instance.dto'; - type DataValidate = { request: Request; schema: JSONSchema7; diff --git a/src/api/controllers/call.controller.ts b/src/api/controllers/call.controller.ts new file mode 100644 index 00000000..abc29804 --- /dev/null +++ b/src/api/controllers/call.controller.ts @@ -0,0 +1,11 @@ +import { OfferCallDto } from '@api/dto/call.dto'; +import { InstanceDto } from '@api/dto/instance.dto'; +import { WAMonitoringService } from '@api/services/monitor.service'; + +export class CallController { + constructor(private readonly waMonitor: WAMonitoringService) {} + + public async offerCall({ instanceName }: InstanceDto, data: OfferCallDto) { + return await this.waMonitor.waInstances[instanceName].offerCall(data); + } +} diff --git a/src/api/controllers/chat.controller.ts b/src/api/controllers/chat.controller.ts index 9d22a8f0..207d8ba5 100644 --- a/src/api/controllers/chat.controller.ts +++ b/src/api/controllers/chat.controller.ts @@ -1,4 +1,3 @@ -import { Logger } from '../../config/logger.config'; import { ArchiveChatDto, BlockUserDto, @@ -14,125 +13,100 @@ import { SendPresenceDto, UpdateMessageDto, WhatsAppNumberDto, -} from '../dto/chat.dto'; -import { InstanceDto } from '../dto/instance.dto'; -import { ContactQuery } from '../repository/contact.repository'; -import { MessageQuery } from '../repository/message.repository'; -import { MessageUpQuery } from '../repository/messageUp.repository'; -import { WAMonitoringService } from '../services/monitor.service'; - -const logger = new Logger('ChatController'); +} from '@api/dto/chat.dto'; +import { InstanceDto } from '@api/dto/instance.dto'; +import { Query } from '@api/repository/repository.service'; +import { WAMonitoringService } from '@api/services/monitor.service'; +import { Contact, Message, MessageUpdate } from '@prisma/client'; export class ChatController { constructor(private readonly waMonitor: WAMonitoringService) {} public async whatsappNumber({ instanceName }: InstanceDto, data: WhatsAppNumberDto) { - logger.verbose('requested whatsappNumber from ' + instanceName + ' instance'); return await this.waMonitor.waInstances[instanceName].whatsappNumber(data); } public async readMessage({ instanceName }: InstanceDto, data: ReadMessageDto) { - logger.verbose('requested readMessage from ' + instanceName + ' instance'); return await this.waMonitor.waInstances[instanceName].markMessageAsRead(data); } public async archiveChat({ instanceName }: InstanceDto, data: ArchiveChatDto) { - logger.verbose('requested archiveChat from ' + instanceName + ' instance'); return await this.waMonitor.waInstances[instanceName].archiveChat(data); } public async markChatUnread({ instanceName }: InstanceDto, data: MarkChatUnreadDto) { - logger.verbose('requested markChatUnread from ' + instanceName + ' instance'); return await this.waMonitor.waInstances[instanceName].markChatUnread(data); } public async deleteMessage({ instanceName }: InstanceDto, data: DeleteMessage) { - logger.verbose('requested deleteMessage from ' + instanceName + ' instance'); return await this.waMonitor.waInstances[instanceName].deleteMessage(data); } public async fetchProfilePicture({ instanceName }: InstanceDto, data: NumberDto) { - logger.verbose('requested fetchProfilePicture from ' + instanceName + ' instance'); return await this.waMonitor.waInstances[instanceName].profilePicture(data.number); } public async fetchProfile({ instanceName }: InstanceDto, data: NumberDto) { - logger.verbose('requested fetchProfile from ' + instanceName + ' instance'); return await this.waMonitor.waInstances[instanceName].fetchProfile(instanceName, data.number); } - public async fetchContacts({ instanceName }: InstanceDto, query: ContactQuery) { - logger.verbose('requested fetchContacts from ' + instanceName + ' instance'); + public async fetchContacts({ instanceName }: InstanceDto, query: Query) { return await this.waMonitor.waInstances[instanceName].fetchContacts(query); } public async getBase64FromMediaMessage({ instanceName }: InstanceDto, data: getBase64FromMediaMessageDto) { - logger.verbose('requested getBase64FromMediaMessage from ' + instanceName + ' instance'); return await this.waMonitor.waInstances[instanceName].getBase64FromMediaMessage(data); } - public async fetchMessages({ instanceName }: InstanceDto, query: MessageQuery) { - logger.verbose('requested fetchMessages from ' + instanceName + ' instance'); + public async fetchMessages({ instanceName }: InstanceDto, query: Query) { return await this.waMonitor.waInstances[instanceName].fetchMessages(query); } - public async fetchStatusMessage({ instanceName }: InstanceDto, query: MessageUpQuery) { - logger.verbose('requested fetchStatusMessage from ' + instanceName + ' instance'); + public async fetchStatusMessage({ instanceName }: InstanceDto, query: Query) { return await this.waMonitor.waInstances[instanceName].fetchStatusMessage(query); } - public async fetchChats({ instanceName }: InstanceDto) { - logger.verbose('requested fetchChats from ' + instanceName + ' instance'); - return await this.waMonitor.waInstances[instanceName].fetchChats(); + public async fetchChats({ instanceName }: InstanceDto, query: Query) { + return await this.waMonitor.waInstances[instanceName].fetchChats(query); } public async sendPresence({ instanceName }: InstanceDto, data: SendPresenceDto) { - logger.verbose('requested sendPresence from ' + instanceName + ' instance'); return await this.waMonitor.waInstances[instanceName].sendPresence(data); } public async fetchPrivacySettings({ instanceName }: InstanceDto) { - logger.verbose('requested fetchPrivacySettings from ' + instanceName + ' instance'); return await this.waMonitor.waInstances[instanceName].fetchPrivacySettings(); } public async updatePrivacySettings({ instanceName }: InstanceDto, data: PrivacySettingDto) { - logger.verbose('requested updatePrivacySettings from ' + instanceName + ' instance'); return await this.waMonitor.waInstances[instanceName].updatePrivacySettings(data); } public async fetchBusinessProfile({ instanceName }: InstanceDto, data: ProfilePictureDto) { - logger.verbose('requested fetchBusinessProfile from ' + instanceName + ' instance'); return await this.waMonitor.waInstances[instanceName].fetchBusinessProfile(data.number); } public async updateProfileName({ instanceName }: InstanceDto, data: ProfileNameDto) { - logger.verbose('requested updateProfileName from ' + instanceName + ' instance'); return await this.waMonitor.waInstances[instanceName].updateProfileName(data.name); } public async updateProfileStatus({ instanceName }: InstanceDto, data: ProfileStatusDto) { - logger.verbose('requested updateProfileStatus from ' + instanceName + ' instance'); return await this.waMonitor.waInstances[instanceName].updateProfileStatus(data.status); } public async updateProfilePicture({ instanceName }: InstanceDto, data: ProfilePictureDto) { - logger.verbose('requested updateProfilePicture from ' + instanceName + ' instance'); return await this.waMonitor.waInstances[instanceName].updateProfilePicture(data.picture); } public async removeProfilePicture({ instanceName }: InstanceDto) { - logger.verbose('requested removeProfilePicture from ' + instanceName + ' instance'); return await this.waMonitor.waInstances[instanceName].removeProfilePicture(); } public async updateMessage({ instanceName }: InstanceDto, data: UpdateMessageDto) { - logger.verbose('requested updateMessage from ' + instanceName + ' instance'); return await this.waMonitor.waInstances[instanceName].updateMessage(data); } public async blockUser({ instanceName }: InstanceDto, data: BlockUserDto) { - logger.verbose('requested blockUser from ' + instanceName + ' instance'); return await this.waMonitor.waInstances[instanceName].blockUser(data); } } diff --git a/src/api/controllers/group.controller.ts b/src/api/controllers/group.controller.ts index e452bc0c..ebe7c036 100644 --- a/src/api/controllers/group.controller.ts +++ b/src/api/controllers/group.controller.ts @@ -1,4 +1,3 @@ -import { Logger } from '../../config/logger.config'; import { AcceptGroupInvite, CreateGroupDto, @@ -12,92 +11,74 @@ import { GroupToggleEphemeralDto, GroupUpdateParticipantDto, GroupUpdateSettingDto, -} from '../dto/group.dto'; -import { InstanceDto } from '../dto/instance.dto'; -import { WAMonitoringService } from '../services/monitor.service'; - -const logger = new Logger('ChatController'); +} from '@api/dto/group.dto'; +import { InstanceDto } from '@api/dto/instance.dto'; +import { WAMonitoringService } from '@api/services/monitor.service'; export class GroupController { constructor(private readonly waMonitor: WAMonitoringService) {} public async createGroup(instance: InstanceDto, create: CreateGroupDto) { - logger.verbose('requested createGroup from ' + instance.instanceName + ' instance'); return await this.waMonitor.waInstances[instance.instanceName].createGroup(create); } public async updateGroupPicture(instance: InstanceDto, update: GroupPictureDto) { - logger.verbose('requested updateGroupPicture from ' + instance.instanceName + ' instance'); return await this.waMonitor.waInstances[instance.instanceName].updateGroupPicture(update); } public async updateGroupSubject(instance: InstanceDto, update: GroupSubjectDto) { - logger.verbose('requested updateGroupSubject from ' + instance.instanceName + ' instance'); return await this.waMonitor.waInstances[instance.instanceName].updateGroupSubject(update); } public async updateGroupDescription(instance: InstanceDto, update: GroupDescriptionDto) { - logger.verbose('requested updateGroupDescription from ' + instance.instanceName + ' instance'); return await this.waMonitor.waInstances[instance.instanceName].updateGroupDescription(update); } public async findGroupInfo(instance: InstanceDto, groupJid: GroupJid) { - logger.verbose('requested findGroupInfo from ' + instance.instanceName + ' instance'); return await this.waMonitor.waInstances[instance.instanceName].findGroup(groupJid); } public async fetchAllGroups(instance: InstanceDto, getPaticipants: GetParticipant) { - logger.verbose('requested fetchAllGroups from ' + instance.instanceName + ' instance'); return await this.waMonitor.waInstances[instance.instanceName].fetchAllGroups(getPaticipants); } public async inviteCode(instance: InstanceDto, groupJid: GroupJid) { - logger.verbose('requested inviteCode from ' + instance.instanceName + ' instance'); return await this.waMonitor.waInstances[instance.instanceName].inviteCode(groupJid); } public async inviteInfo(instance: InstanceDto, inviteCode: GroupInvite) { - logger.verbose('requested inviteInfo from ' + instance.instanceName + ' instance'); return await this.waMonitor.waInstances[instance.instanceName].inviteInfo(inviteCode); } public async sendInvite(instance: InstanceDto, data: GroupSendInvite) { - logger.verbose('requested sendInvite from ' + instance.instanceName + ' instance'); return await this.waMonitor.waInstances[instance.instanceName].sendInvite(data); } public async acceptInviteCode(instance: InstanceDto, inviteCode: AcceptGroupInvite) { - logger.verbose('requested acceptInviteCode from ' + instance.instanceName + ' instance'); return await this.waMonitor.waInstances[instance.instanceName].acceptInviteCode(inviteCode); } public async revokeInviteCode(instance: InstanceDto, groupJid: GroupJid) { - logger.verbose('requested revokeInviteCode from ' + instance.instanceName + ' instance'); return await this.waMonitor.waInstances[instance.instanceName].revokeInviteCode(groupJid); } public async findParticipants(instance: InstanceDto, groupJid: GroupJid) { - logger.verbose('requested findParticipants from ' + instance.instanceName + ' instance'); return await this.waMonitor.waInstances[instance.instanceName].findParticipants(groupJid); } public async updateGParticipate(instance: InstanceDto, update: GroupUpdateParticipantDto) { - logger.verbose('requested updateGParticipate from ' + instance.instanceName + ' instance'); return await this.waMonitor.waInstances[instance.instanceName].updateGParticipant(update); } public async updateGSetting(instance: InstanceDto, update: GroupUpdateSettingDto) { - logger.verbose('requested updateGSetting from ' + instance.instanceName + ' instance'); return await this.waMonitor.waInstances[instance.instanceName].updateGSetting(update); } public async toggleEphemeral(instance: InstanceDto, update: GroupToggleEphemeralDto) { - logger.verbose('requested toggleEphemeral from ' + instance.instanceName + ' instance'); return await this.waMonitor.waInstances[instance.instanceName].toggleEphemeral(update); } public async leaveGroup(instance: InstanceDto, groupJid: GroupJid) { - logger.verbose('requested leaveGroup from ' + instance.instanceName + ' instance'); return await this.waMonitor.waInstances[instance.instanceName].leaveGroup(groupJid); } } diff --git a/src/api/controllers/instance.controller.ts b/src/api/controllers/instance.controller.ts index 0ead0be1..874c7566 100644 --- a/src/api/controllers/instance.controller.ts +++ b/src/api/controllers/instance.controller.ts @@ -1,431 +1,149 @@ -import { delay } from '@whiskeysockets/baileys'; -import { isURL } from 'class-validator'; +import { InstanceDto, SetPresenceDto } from '@api/dto/instance.dto'; +import { ChatwootService } from '@api/integrations/chatbot/chatwoot/services/chatwoot.service'; +import { ProviderFiles } from '@api/provider/sessions'; +import { PrismaRepository } from '@api/repository/repository.service'; +import { channelController, eventManager } from '@api/server.module'; +import { CacheService } from '@api/services/cache.service'; +import { WAMonitoringService } from '@api/services/monitor.service'; +import { SettingsService } from '@api/services/settings.service'; +import { Events, Integration, wa } from '@api/types/wa.types'; +import { Auth, Chatwoot, ConfigService, HttpServer, WaBusiness } from '@config/env.config'; +import { Logger } from '@config/logger.config'; +import { BadRequestException, InternalServerErrorException, UnauthorizedException } from '@exceptions'; +import { delay } from 'baileys'; +import { isArray, isURL } from 'class-validator'; import EventEmitter2 from 'eventemitter2'; import { v4 } from 'uuid'; -import { Auth, ConfigService, HttpServer, WaBusiness } from '../../config/env.config'; -import { Logger } from '../../config/logger.config'; -import { BadRequestException, InternalServerErrorException, UnauthorizedException } from '../../exceptions'; -import { InstanceDto, SetPresenceDto } from '../dto/instance.dto'; -import { ChatwootService } from '../integrations/chatwoot/services/chatwoot.service'; -import { RabbitmqService } from '../integrations/rabbitmq/services/rabbitmq.service'; -import { SqsService } from '../integrations/sqs/services/sqs.service'; -import { TypebotService } from '../integrations/typebot/services/typebot.service'; -import { WebsocketService } from '../integrations/websocket/services/websocket.service'; -import { RepositoryBroker } from '../repository/repository.manager'; -import { AuthService, OldToken } from '../services/auth.service'; -import { CacheService } from '../services/cache.service'; -import { BaileysStartupService } from '../services/channels/whatsapp.baileys.service'; -import { BusinessStartupService } from '../services/channels/whatsapp.business.service'; -import { IntegrationService } from '../services/integration.service'; -import { WAMonitoringService } from '../services/monitor.service'; -import { SettingsService } from '../services/settings.service'; -import { WebhookService } from '../services/webhook.service'; -import { Events, Integration, wa } from '../types/wa.types'; import { ProxyController } from './proxy.controller'; export class InstanceController { constructor( private readonly waMonitor: WAMonitoringService, private readonly configService: ConfigService, - private readonly repository: RepositoryBroker, + private readonly prismaRepository: PrismaRepository, private readonly eventEmitter: EventEmitter2, - private readonly authService: AuthService, - private readonly webhookService: WebhookService, private readonly chatwootService: ChatwootService, private readonly settingsService: SettingsService, - private readonly websocketService: WebsocketService, - private readonly rabbitmqService: RabbitmqService, - private readonly sqsService: SqsService, - private readonly typebotService: TypebotService, - private readonly integrationService: IntegrationService, private readonly proxyService: ProxyController, private readonly cache: CacheService, private readonly chatwootCache: CacheService, - private readonly messagesLostCache: CacheService, + private readonly baileysCache: CacheService, + private readonly providerFiles: ProviderFiles, ) {} - private readonly logger = new Logger(InstanceController.name); + private readonly logger = new Logger('InstanceController'); - public async createInstance({ - instanceName, - webhook, - webhook_by_events, - webhook_base64, - events, - qrcode, - number, - mobile, - integration, - token, - chatwoot_account_id, - chatwoot_token, - chatwoot_url, - chatwoot_sign_msg, - chatwoot_reopen_conversation, - chatwoot_conversation_pending, - chatwoot_import_contacts, - chatwoot_name_inbox, - chatwoot_merge_brazil_contacts, - chatwoot_import_messages, - chatwoot_days_limit_import_messages, - reject_call, - msg_call, - groups_ignore, - always_online, - read_messages, - read_status, - sync_full_history, - websocket_enabled, - websocket_events, - rabbitmq_enabled, - rabbitmq_events, - sqs_enabled, - sqs_events, - typebot_url, - typebot, - typebot_expire, - typebot_keyword_finish, - typebot_delay_message, - typebot_unknown_message, - typebot_listening_from_me, - proxy, - }: InstanceDto) { + public async createInstance(instanceData: InstanceDto) { try { - this.logger.verbose('requested createInstance from ' + instanceName + ' instance'); + const instance = channelController.init(instanceData, { + configService: this.configService, + eventEmitter: this.eventEmitter, + prismaRepository: this.prismaRepository, + cache: this.cache, + chatwootCache: this.chatwootCache, + baileysCache: this.baileysCache, + providerFiles: this.providerFiles, + }); - this.logger.verbose('checking duplicate token'); - await this.authService.checkDuplicateToken(token); - - if (!token && integration === Integration.WHATSAPP_BUSINESS) { - throw new BadRequestException('token is required'); + if (!instance) { + throw new BadRequestException('Invalid integration'); } - this.logger.verbose('creating instance'); - let instance: BaileysStartupService | BusinessStartupService; - if (integration === Integration.WHATSAPP_BUSINESS) { - instance = new BusinessStartupService( - this.configService, - this.eventEmitter, - this.repository, - this.cache, - this.chatwootCache, - this.messagesLostCache, - ); - } else { - instance = new BaileysStartupService( - this.configService, - this.eventEmitter, - this.repository, - this.cache, - this.chatwootCache, - this.messagesLostCache, - ); - } - - await this.waMonitor.saveInstance({ integration, instanceName, token, number, mobile }); - - instance.instanceName = instanceName; - const instanceId = v4(); - instance.sendDataWebhook(Events.INSTANCE_CREATE, { - instanceName, - instanceId: instanceId, + instanceData.instanceId = instanceId; + + let hash: string; + + if (!instanceData.token) hash = v4().toUpperCase(); + else hash = instanceData.token; + + await this.waMonitor.saveInstance({ + instanceId, + integration: instanceData.integration, + instanceName: instanceData.instanceName, + ownerJid: instanceData.ownerJid, + profileName: instanceData.profileName, + profilePicUrl: instanceData.profilePicUrl, + hash, + number: instanceData.number, + businessId: instanceData.businessId, + status: instanceData.status, }); - this.logger.verbose('instance: ' + instance.instanceName + ' created'); + instance.setInstance({ + instanceName: instanceData.instanceName, + instanceId, + integration: instanceData.integration, + token: hash, + number: instanceData.number, + businessId: instanceData.businessId, + }); this.waMonitor.waInstances[instance.instanceName] = instance; this.waMonitor.delInstanceTime(instance.instanceName); - this.logger.verbose('generating hash'); - const hash = await this.authService.generateHash( - { - instanceName: instance.instanceName, - instanceId: instanceId, - }, - token, - ); + // set events + await eventManager.setInstance(instance.instanceName, instanceData); - this.logger.verbose('hash: ' + hash + ' generated'); + instance.sendDataWebhook(Events.INSTANCE_CREATE, { + instanceName: instanceData.instanceName, + instanceId: instanceId, + }); - let webhookEvents: string[]; - - if (webhook) { - if (!isURL(webhook, { require_tld: false })) { - throw new BadRequestException('Invalid "url" property in webhook'); - } - - this.logger.verbose('creating webhook'); - try { - let newEvents: string[] = []; - if (events.length === 0) { - newEvents = [ - 'APPLICATION_STARTUP', - 'QRCODE_UPDATED', - 'MESSAGES_SET', - 'MESSAGES_UPSERT', - 'MESSAGES_UPDATE', - 'MESSAGES_DELETE', - 'SEND_MESSAGE', - 'CONTACTS_SET', - 'CONTACTS_UPSERT', - 'CONTACTS_UPDATE', - 'PRESENCE_UPDATE', - 'CHATS_SET', - 'CHATS_UPSERT', - 'CHATS_UPDATE', - 'CHATS_DELETE', - 'GROUPS_UPSERT', - 'GROUP_UPDATE', - 'GROUP_PARTICIPANTS_UPDATE', - 'CONNECTION_UPDATE', - 'LABELS_EDIT', - 'LABELS_ASSOCIATION', - 'CALL', - 'NEW_JWT_TOKEN', - 'TYPEBOT_START', - 'TYPEBOT_CHANGE_STATUS', - 'CHAMA_AI_ACTION', - ]; - } else { - newEvents = events; - } - this.webhookService.create(instance, { - enabled: true, - url: webhook, - events: newEvents, - webhook_by_events, - webhook_base64, - }); - - webhookEvents = (await this.webhookService.find(instance)).events; - } catch (error) { - this.logger.log(error); - } - } - - let websocketEvents: string[]; - - if (websocket_enabled) { - this.logger.verbose('creating websocket'); - try { - let newEvents: string[] = []; - if (websocket_events.length === 0) { - newEvents = [ - 'APPLICATION_STARTUP', - 'QRCODE_UPDATED', - 'MESSAGES_SET', - 'MESSAGES_UPSERT', - 'MESSAGES_UPDATE', - 'MESSAGES_DELETE', - 'SEND_MESSAGE', - 'CONTACTS_SET', - 'CONTACTS_UPSERT', - 'CONTACTS_UPDATE', - 'PRESENCE_UPDATE', - 'CHATS_SET', - 'CHATS_UPSERT', - 'CHATS_UPDATE', - 'CHATS_DELETE', - 'GROUPS_UPSERT', - 'GROUP_UPDATE', - 'GROUP_PARTICIPANTS_UPDATE', - 'CONNECTION_UPDATE', - 'LABELS_EDIT', - 'LABELS_ASSOCIATION', - 'CALL', - 'NEW_JWT_TOKEN', - 'TYPEBOT_START', - 'TYPEBOT_CHANGE_STATUS', - 'CHAMA_AI_ACTION', - ]; - } else { - newEvents = websocket_events; - } - this.websocketService.create(instance, { - enabled: true, - events: newEvents, - }); - - websocketEvents = (await this.websocketService.find(instance)).events; - } catch (error) { - this.logger.log(error); - } - } - - let rabbitmqEvents: string[]; - - if (rabbitmq_enabled) { - this.logger.verbose('creating rabbitmq'); - try { - let newEvents: string[] = []; - if (rabbitmq_events.length === 0) { - newEvents = [ - 'APPLICATION_STARTUP', - 'QRCODE_UPDATED', - 'MESSAGES_SET', - 'MESSAGES_UPSERT', - 'MESSAGES_UPDATE', - 'MESSAGES_DELETE', - 'SEND_MESSAGE', - 'CONTACTS_SET', - 'CONTACTS_UPSERT', - 'CONTACTS_UPDATE', - 'PRESENCE_UPDATE', - 'CHATS_SET', - 'CHATS_UPSERT', - 'CHATS_UPDATE', - 'CHATS_DELETE', - 'GROUPS_UPSERT', - 'GROUP_UPDATE', - 'GROUP_PARTICIPANTS_UPDATE', - 'CONNECTION_UPDATE', - 'LABELS_EDIT', - 'LABELS_ASSOCIATION', - 'CALL', - 'NEW_JWT_TOKEN', - 'TYPEBOT_START', - 'TYPEBOT_CHANGE_STATUS', - 'CHAMA_AI_ACTION', - ]; - } else { - newEvents = rabbitmq_events; - } - this.rabbitmqService.create(instance, { - enabled: true, - events: newEvents, - }); - - rabbitmqEvents = (await this.rabbitmqService.find(instance)).events; - } catch (error) { - this.logger.log(error); - } - } - - let sqsEvents: string[]; - - if (sqs_enabled) { - this.logger.verbose('creating sqs'); - try { - let newEvents: string[] = []; - if (sqs_events.length === 0) { - newEvents = [ - 'APPLICATION_STARTUP', - 'QRCODE_UPDATED', - 'MESSAGES_SET', - 'MESSAGES_UPSERT', - 'MESSAGES_UPDATE', - 'MESSAGES_DELETE', - 'SEND_MESSAGE', - 'CONTACTS_SET', - 'CONTACTS_UPSERT', - 'CONTACTS_UPDATE', - 'PRESENCE_UPDATE', - 'CHATS_SET', - 'CHATS_UPSERT', - 'CHATS_UPDATE', - 'CHATS_DELETE', - 'GROUPS_UPSERT', - 'GROUP_UPDATE', - 'GROUP_PARTICIPANTS_UPDATE', - 'CONNECTION_UPDATE', - 'LABELS_EDIT', - 'LABELS_ASSOCIATION', - 'CALL', - 'NEW_JWT_TOKEN', - 'TYPEBOT_START', - 'TYPEBOT_CHANGE_STATUS', - 'CHAMA_AI_ACTION', - ]; - } else { - newEvents = sqs_events; - } - this.sqsService.create(instance, { - enabled: true, - events: newEvents, - }); - - sqsEvents = (await this.sqsService.find(instance)).events; - } catch (error) { - this.logger.log(error); - } - } - - if (proxy) { - const testProxy = await this.proxyService.testProxy(proxy); + if (instanceData.proxyHost && instanceData.proxyPort && instanceData.proxyProtocol) { + const testProxy = await this.proxyService.testProxy({ + host: instanceData.proxyHost, + port: instanceData.proxyPort, + protocol: instanceData.proxyProtocol, + username: instanceData.proxyUsername, + password: instanceData.proxyPassword, + }); if (!testProxy) { throw new BadRequestException('Invalid proxy'); } await this.proxyService.createProxy(instance, { enabled: true, - proxy, + host: instanceData.proxyHost, + port: instanceData.proxyPort, + protocol: instanceData.proxyProtocol, + username: instanceData.proxyUsername, + password: instanceData.proxyPassword, }); } - if (typebot_url) { - try { - if (!isURL(typebot_url, { require_tld: false })) { - throw new BadRequestException('Invalid "url" property in typebot_url'); - } - - this.logger.verbose('creating typebot'); - - this.typebotService.create(instance, { - enabled: true, - url: typebot_url, - typebot: typebot, - expire: typebot_expire, - keyword_finish: typebot_keyword_finish, - delay_message: typebot_delay_message, - unknown_message: typebot_unknown_message, - listening_from_me: typebot_listening_from_me, - }); - } catch (error) { - this.logger.log(error); - } - } - - this.logger.verbose('creating settings'); const settings: wa.LocalSettings = { - reject_call: reject_call || false, - msg_call: msg_call || '', - groups_ignore: groups_ignore || true, - always_online: always_online || false, - read_messages: read_messages || false, - read_status: read_status || false, - sync_full_history: sync_full_history ?? false, + rejectCall: instanceData.rejectCall === true, + msgCall: instanceData.msgCall || '', + groupsIgnore: instanceData.groupsIgnore === true, + alwaysOnline: instanceData.alwaysOnline === true, + readMessages: instanceData.readMessages === true, + readStatus: instanceData.readStatus === true, + syncFullHistory: instanceData.syncFullHistory === true, + wavoipToken: instanceData.wavoipToken || '', }; - this.logger.verbose('settings: ' + JSON.stringify(settings)); + await this.settingsService.create(instance, settings); - this.settingsService.create(instance, settings); + let webhookWaBusiness = null, + accessTokenWaBusiness = ''; - let webhook_wa_business = null, - access_token_wa_business = ''; - - if (integration === Integration.WHATSAPP_BUSINESS) { - if (!number) { + if (instanceData.integration === Integration.WHATSAPP_BUSINESS) { + if (!instanceData.number) { throw new BadRequestException('number is required'); } const urlServer = this.configService.get('SERVER').URL; - webhook_wa_business = `${urlServer}/webhook/whatsapp/${encodeURIComponent(instance.instanceName)}`; - access_token_wa_business = this.configService.get('WA_BUSINESS').TOKEN_WEBHOOK; + webhookWaBusiness = `${urlServer}/webhook/meta`; + accessTokenWaBusiness = this.configService.get('WA_BUSINESS').TOKEN_WEBHOOK; } - this.integrationService.create(instance, { - integration, - number, - token, - }); - if (!chatwoot_account_id || !chatwoot_token || !chatwoot_url) { + if (!instanceData.chatwootAccountId || !instanceData.chatwootToken || !instanceData.chatwootUrl) { let getQrcode: wa.QrCode; - if (qrcode) { - this.logger.verbose('creating qrcode'); - await instance.connectToWhatsapp(number, mobile); + if (instanceData.qrcode && instanceData.integration === Integration.WHATSAPP_BAILEYS) { + await instance.connectToWhatsapp(instanceData.number); await delay(5000); getQrcode = instance.qrCode; } @@ -434,76 +152,63 @@ export class InstanceController { instance: { instanceName: instance.instanceName, instanceId: instanceId, - integration: integration, - webhook_wa_business, - access_token_wa_business, - status: 'created', + integration: instanceData.integration, + webhookWaBusiness, + accessTokenWaBusiness, + status: instance.connectionStatus.state, }, hash, webhook: { - webhook, - webhook_by_events, - webhook_base64, - events: webhookEvents, + webhookUrl: instanceData?.webhook?.url, + webhookHeaders: instanceData?.webhook?.headers, + webhookByEvents: instanceData?.webhook?.byEvents, + webhookBase64: instanceData?.webhook?.base64, }, websocket: { - enabled: websocket_enabled, - events: websocketEvents, + enabled: instanceData?.websocket?.enabled, }, rabbitmq: { - enabled: rabbitmq_enabled, - events: rabbitmqEvents, + enabled: instanceData?.rabbitmq?.enabled, }, sqs: { - enabled: sqs_enabled, - events: sqsEvents, - }, - typebot: { - enabled: typebot_url ? true : false, - url: typebot_url, - typebot, - expire: typebot_expire, - keyword_finish: typebot_keyword_finish, - delay_message: typebot_delay_message, - unknown_message: typebot_unknown_message, - listening_from_me: typebot_listening_from_me, + enabled: instanceData?.sqs?.enabled, }, settings, qrcode: getQrcode, }; - this.logger.verbose('instance created'); - this.logger.verbose(result); - return result; } - if (!chatwoot_account_id) { - throw new BadRequestException('account_id is required'); + if (!this.configService.get('CHATWOOT').ENABLED) + throw new BadRequestException('Chatwoot is not enabled'); + + if (!instanceData.chatwootAccountId) { + throw new BadRequestException('accountId is required'); } - if (!chatwoot_token) { + if (!instanceData.chatwootToken) { throw new BadRequestException('token is required'); } - if (!chatwoot_url) { + if (!instanceData.chatwootUrl) { throw new BadRequestException('url is required'); } - if (!isURL(chatwoot_url, { require_tld: false })) { + if (!isURL(instanceData.chatwootUrl, { require_tld: false })) { throw new BadRequestException('Invalid "url" property in chatwoot'); } - if (chatwoot_sign_msg !== true && chatwoot_sign_msg !== false) { - throw new BadRequestException('sign_msg is required'); + if (instanceData.chatwootSignMsg !== true && instanceData.chatwootSignMsg !== false) { + throw new BadRequestException('signMsg is required'); } - if (chatwoot_reopen_conversation !== true && chatwoot_reopen_conversation !== false) { - throw new BadRequestException('reopen_conversation is required'); + if (instanceData.chatwootReopenConversation !== true && instanceData.chatwootReopenConversation !== false) { + throw new BadRequestException('reopenConversation is required'); } - if (chatwoot_conversation_pending !== true && chatwoot_conversation_pending !== false) { - throw new BadRequestException('conversation_pending is required'); + if (instanceData.chatwootConversationPending !== true && instanceData.chatwootConversationPending !== false) { + throw new BadRequestException('conversationPending is required'); } const urlServer = this.configService.get('SERVER').URL; @@ -511,19 +216,21 @@ export class InstanceController { try { this.chatwootService.create(instance, { enabled: true, - account_id: chatwoot_account_id, - token: chatwoot_token, - url: chatwoot_url, - sign_msg: chatwoot_sign_msg || false, - name_inbox: chatwoot_name_inbox ?? instance.instanceName.split('-cwId-')[0], - number, - reopen_conversation: chatwoot_reopen_conversation || false, - conversation_pending: chatwoot_conversation_pending || false, - import_contacts: chatwoot_import_contacts ?? true, - merge_brazil_contacts: chatwoot_merge_brazil_contacts ?? false, - import_messages: chatwoot_import_messages ?? true, - days_limit_import_messages: chatwoot_days_limit_import_messages ?? 60, - auto_create: true, + accountId: instanceData.chatwootAccountId, + token: instanceData.chatwootToken, + url: instanceData.chatwootUrl, + signMsg: instanceData.chatwootSignMsg || false, + nameInbox: instanceData.chatwootNameInbox ?? instance.instanceName.split('-cwId-')[0], + number: instanceData.number, + reopenConversation: instanceData.chatwootReopenConversation || false, + conversationPending: instanceData.chatwootConversationPending || false, + importContacts: instanceData.chatwootImportContacts ?? true, + mergeBrazilContacts: instanceData.chatwootMergeBrazilContacts ?? false, + importMessages: instanceData.chatwootImportMessages ?? true, + daysLimitImportMessages: instanceData.chatwootDaysLimitImportMessages ?? 60, + organization: instanceData.chatwootOrganization, + logo: instanceData.chatwootLogo, + autoCreate: instanceData.chatwootAutoCreate !== false, }); } catch (error) { this.logger.log(error); @@ -533,73 +240,57 @@ export class InstanceController { instance: { instanceName: instance.instanceName, instanceId: instanceId, - integration: integration, - webhook_wa_business, - access_token_wa_business, - status: 'created', + integration: instanceData.integration, + webhookWaBusiness, + accessTokenWaBusiness, + status: instance.connectionStatus.state, }, hash, webhook: { - webhook, - webhook_by_events, - webhook_base64, - events: webhookEvents, + webhookUrl: instanceData?.webhook?.url, + webhookHeaders: instanceData?.webhook?.headers, + webhookByEvents: instanceData?.webhook?.byEvents, + webhookBase64: instanceData?.webhook?.base64, }, websocket: { - enabled: websocket_enabled, - events: websocketEvents, + enabled: instanceData?.websocket?.enabled, }, rabbitmq: { - enabled: rabbitmq_enabled, - events: rabbitmqEvents, + enabled: instanceData?.rabbitmq?.enabled, }, sqs: { - enabled: sqs_enabled, - events: sqsEvents, - }, - typebot: { - enabled: typebot_url ? true : false, - url: typebot_url, - typebot, - expire: typebot_expire, - keyword_finish: typebot_keyword_finish, - delay_message: typebot_delay_message, - unknown_message: typebot_unknown_message, - listening_from_me: typebot_listening_from_me, + enabled: instanceData?.sqs?.enabled, }, settings, chatwoot: { enabled: true, - account_id: chatwoot_account_id, - token: chatwoot_token, - url: chatwoot_url, - sign_msg: chatwoot_sign_msg || false, - reopen_conversation: chatwoot_reopen_conversation || false, - conversation_pending: chatwoot_conversation_pending || false, - merge_brazil_contacts: chatwoot_merge_brazil_contacts ?? false, - import_contacts: chatwoot_import_contacts ?? true, - import_messages: chatwoot_import_messages ?? true, - days_limit_import_messages: chatwoot_days_limit_import_messages || 60, - number, - name_inbox: chatwoot_name_inbox ?? instance.instanceName, - webhook_url: `${urlServer}/chatwoot/webhook/${encodeURIComponent(instance.instanceName)}`, + accountId: instanceData.chatwootAccountId, + token: instanceData.chatwootToken, + url: instanceData.chatwootUrl, + signMsg: instanceData.chatwootSignMsg || false, + reopenConversation: instanceData.chatwootReopenConversation || false, + conversationPending: instanceData.chatwootConversationPending || false, + mergeBrazilContacts: instanceData.chatwootMergeBrazilContacts ?? false, + importContacts: instanceData.chatwootImportContacts ?? true, + importMessages: instanceData.chatwootImportMessages ?? true, + daysLimitImportMessages: instanceData.chatwootDaysLimitImportMessages || 60, + number: instanceData.number, + nameInbox: instanceData.chatwootNameInbox ?? instance.instanceName, + webhookUrl: `${urlServer}/chatwoot/webhook/${encodeURIComponent(instance.instanceName)}`, }, }; } catch (error) { - this.logger.error(error.message[0]); - throw new BadRequestException(error.message[0]); + this.waMonitor.deleteInstance(instanceData.instanceName); + this.logger.error(isArray(error.message) ? error.message[0] : error.message); + throw new BadRequestException(isArray(error.message) ? error.message[0] : error.message); } } - public async connectToWhatsapp({ instanceName, number = null, mobile = null }: InstanceDto) { + public async connectToWhatsapp({ instanceName, number = null }: InstanceDto) { try { - this.logger.verbose('requested connectToWhatsapp from ' + instanceName + ' instance'); - const instance = this.waMonitor.waInstances[instanceName]; const state = instance?.connectionStatus?.state; - this.logger.verbose('state: ' + state); - if (!state) { throw new BadRequestException('The "' + instanceName + '" instance does not exist'); } @@ -613,10 +304,9 @@ export class InstanceController { } if (state == 'close') { - this.logger.verbose('connecting'); - await instance.connectToWhatsapp(number, mobile); + await instance.connectToWhatsapp(number); - await delay(5000); + await delay(2000); return instance.qrCode; } @@ -629,48 +319,40 @@ export class InstanceController { }; } catch (error) { this.logger.error(error); + return { error: true, message: error.toString() }; } } public async restartInstance({ instanceName }: InstanceDto) { try { - this.logger.verbose('requested restartInstance from ' + instanceName + ' instance'); - const instance = this.waMonitor.waInstances[instanceName]; const state = instance?.connectionStatus?.state; - switch (state) { - case 'open': - this.logger.verbose('logging out instance: ' + instanceName); - instance.clearCacheChatwoot(); - await instance.reloadConnection(); - await delay(2000); + if (!state) { + throw new BadRequestException('The "' + instanceName + '" instance does not exist'); + } - return await this.connectionState({ instanceName }); - default: - return await this.connectionState({ instanceName }); + if (state == 'close') { + throw new BadRequestException('The "' + instanceName + '" instance is not connected'); + } else if (state == 'open') { + if (this.configService.get('CHATWOOT').ENABLED) instance.clearCacheChatwoot(); + this.logger.info('restarting instance' + instanceName); + + instance.client?.ws?.close(); + instance.client?.end(new Error('restart')); + return await this.connectToWhatsapp({ instanceName }); + } else if (state == 'connecting') { + instance.client?.ws?.close(); + instance.client?.end(new Error('restart')); + return await this.connectToWhatsapp({ instanceName }); } } catch (error) { this.logger.error(error); - } - } - - public async registerMobileCode({ instanceName }: InstanceDto, { mobileCode }: any) { - try { - this.logger.verbose('requested registerMobileCode from ' + instanceName + ' instance'); - - const instance = this.waMonitor.waInstances[instanceName]; - - console.log('mobileCode', mobileCode); - await instance.receiveMobileCode(mobileCode); - return { status: 'SUCCESS', error: false, response: { message: 'Mobile code registered' } }; - } catch (error) { - this.logger.error(error); + return { error: true, message: error.toString() }; } } public async connectionState({ instanceName }: InstanceDto) { - this.logger.verbose('requested connectionState from ' + instanceName + ' instance'); return { instance: { instanceName: instanceName, @@ -682,38 +364,38 @@ export class InstanceController { public async fetchInstances({ instanceName, instanceId, number }: InstanceDto, key: string) { const env = this.configService.get('AUTHENTICATION').API_KEY; - let name = instanceName; - let arrayReturn = false; - if (env.KEY !== key) { - const instanceByKey = await this.repository.auth.findByKey(key); - if (instanceByKey) { - name = instanceByKey._id; - arrayReturn = true; + const instancesByKey = await this.prismaRepository.instance.findMany({ + where: { + token: key, + name: instanceName || undefined, + id: instanceId || undefined, + }, + }); + + if (instancesByKey.length > 0) { + const names = instancesByKey.map((instance) => instance.name); + + return this.waMonitor.instanceInfo(names); } else { throw new UnauthorizedException(); } } - if (name) { - this.logger.verbose('requested fetchInstances from ' + name + ' instance'); - this.logger.verbose('instanceName: ' + name); - return this.waMonitor.instanceInfo(name, arrayReturn); - } else if (instanceId || number) { + if (instanceId || number) { return this.waMonitor.instanceInfoById(instanceId, number); } - this.logger.verbose('requested fetchInstances (all instances)'); - return this.waMonitor.instanceInfo(); + const instanceNames = instanceName ? [instanceName] : null; + + return this.waMonitor.instanceInfo(instanceNames); } public async setPresence({ instanceName }: InstanceDto, data: SetPresenceDto) { - this.logger.verbose('requested sendPresence from ' + instanceName + ' instance'); return await this.waMonitor.waInstances[instanceName].setPresence(data); } public async logout({ instanceName }: InstanceDto) { - this.logger.verbose('requested logout from ' + instanceName + ' instance'); const { instance } = await this.connectionState({ instanceName }); if (instance.state === 'close') { @@ -730,43 +412,28 @@ export class InstanceController { } public async deleteInstance({ instanceName }: InstanceDto) { - this.logger.verbose('requested deleteInstance from ' + instanceName + ' instance'); const { instance } = await this.connectionState({ instanceName }); - - if (instance.state === 'open') { - throw new BadRequestException('The "' + instanceName + '" instance needs to be disconnected'); - } try { - this.waMonitor.waInstances[instanceName]?.removeRabbitmqQueues(); - this.waMonitor.waInstances[instanceName]?.clearCacheChatwoot(); - - if (instance.state === 'connecting') { - this.logger.verbose('logging out instance: ' + instanceName); + const waInstances = this.waMonitor.waInstances[instanceName]; + if (this.configService.get('CHATWOOT').ENABLED) waInstances?.clearCacheChatwoot(); + if (instance.state === 'connecting' || instance.state === 'open') { await this.logout({ instanceName }); } - this.logger.verbose('deleting instance: ' + instanceName); - try { - this.waMonitor.waInstances[instanceName].sendDataWebhook(Events.INSTANCE_DELETE, { + waInstances?.sendDataWebhook(Events.INSTANCE_DELETE, { instanceName, - instanceId: (await this.repository.auth.find(instanceName))?.instanceId, + instanceId: waInstances.instanceId, }); } catch (error) { this.logger.error(error); } - delete this.waMonitor.waInstances[instanceName]; this.eventEmitter.emit('remove.instance', instanceName, 'inner'); return { status: 'SUCCESS', error: false, response: { message: 'Instance deleted' } }; } catch (error) { throw new BadRequestException(error.toString()); } } - - public async refreshToken(_: InstanceDto, oldToken: OldToken) { - this.logger.verbose('requested refreshToken'); - return await this.authService.refreshToken(oldToken); - } } diff --git a/src/api/controllers/label.controller.ts b/src/api/controllers/label.controller.ts index 6fd91d86..2df112f7 100644 --- a/src/api/controllers/label.controller.ts +++ b/src/api/controllers/label.controller.ts @@ -1,20 +1,15 @@ -import { Logger } from '../../config/logger.config'; -import { InstanceDto } from '../dto/instance.dto'; -import { HandleLabelDto } from '../dto/label.dto'; -import { WAMonitoringService } from '../services/monitor.service'; - -const logger = new Logger('LabelController'); +import { InstanceDto } from '@api/dto/instance.dto'; +import { HandleLabelDto } from '@api/dto/label.dto'; +import { WAMonitoringService } from '@api/services/monitor.service'; export class LabelController { constructor(private readonly waMonitor: WAMonitoringService) {} public async fetchLabels({ instanceName }: InstanceDto) { - logger.verbose('requested fetchLabels from ' + instanceName + ' instance'); return await this.waMonitor.waInstances[instanceName].fetchLabels(); } public async handleLabel({ instanceName }: InstanceDto, data: HandleLabelDto) { - logger.verbose('requested chat label change from ' + instanceName + ' instance'); return await this.waMonitor.waInstances[instanceName].handleLabel(data); } } diff --git a/src/api/controllers/proxy.controller.ts b/src/api/controllers/proxy.controller.ts index 7b34a9d9..fac00375 100644 --- a/src/api/controllers/proxy.controller.ts +++ b/src/api/controllers/proxy.controller.ts @@ -1,44 +1,44 @@ +import { InstanceDto } from '@api/dto/instance.dto'; +import { ProxyDto } from '@api/dto/proxy.dto'; +import { WAMonitoringService } from '@api/services/monitor.service'; +import { ProxyService } from '@api/services/proxy.service'; +import { Logger } from '@config/logger.config'; +import { BadRequestException, NotFoundException } from '@exceptions'; +import { makeProxyAgent } from '@utils/makeProxyAgent'; import axios from 'axios'; -import { Logger } from '../../config/logger.config'; -import { BadRequestException, NotFoundException } from '../../exceptions'; -import { makeProxyAgent } from '../../utils/makeProxyAgent'; -import { InstanceDto } from '../dto/instance.dto'; -import { ProxyDto } from '../dto/proxy.dto'; -import { WAMonitoringService } from '../services/monitor.service'; -import { ProxyService } from '../services/proxy.service'; - const logger = new Logger('ProxyController'); export class ProxyController { - constructor(private readonly proxyService: ProxyService, private readonly waMonitor: WAMonitoringService) {} + constructor( + private readonly proxyService: ProxyService, + private readonly waMonitor: WAMonitoringService, + ) {} public async createProxy(instance: InstanceDto, data: ProxyDto) { - logger.verbose('requested createProxy from ' + instance.instanceName + ' instance'); - if (!this.waMonitor.waInstances[instance.instanceName]) { throw new NotFoundException(`The "${instance.instanceName}" instance does not exist`); } - if (!data.enabled) { - logger.verbose('proxy disabled'); - data.proxy = null; + if (!data?.enabled) { + data.host = ''; + data.port = ''; + data.protocol = ''; + data.username = ''; + data.password = ''; } - if (data.proxy) { - const testProxy = await this.testProxy(data.proxy); + if (data.host) { + const testProxy = await this.testProxy(data); if (!testProxy) { throw new BadRequestException('Invalid proxy'); } - logger.verbose('proxy enabled'); } return this.proxyService.create(instance, data); } public async findProxy(instance: InstanceDto) { - logger.verbose('requested findProxy from ' + instance.instanceName + ' instance'); - if (!this.waMonitor.waInstances[instance.instanceName]) { throw new NotFoundException(`The "${instance.instanceName}" instance does not exist`); } @@ -46,25 +46,21 @@ export class ProxyController { return this.proxyService.find(instance); } - public async testProxy(proxy: ProxyDto['proxy']) { - logger.verbose('requested testProxy'); + public async testProxy(proxy: ProxyDto) { try { const serverIp = await axios.get('https://icanhazip.com/'); const response = await axios.get('https://icanhazip.com/', { httpsAgent: makeProxyAgent(proxy), }); - logger.verbose('[testProxy] from IP: ' + response?.data + ' To IP: ' + serverIp?.data); return response?.data !== serverIp?.data; } catch (error) { if (axios.isAxiosError(error) && error.response?.data) { logger.error('testProxy error: ' + error.response.data); } else if (axios.isAxiosError(error)) { logger.error('testProxy error: '); - logger.verbose(error.cause ?? error.message); } else { logger.error('testProxy error: '); - logger.verbose(error); } return false; } diff --git a/src/api/controllers/sendMessage.controller.ts b/src/api/controllers/sendMessage.controller.ts index d23ba345..ac40562c 100644 --- a/src/api/controllers/sendMessage.controller.ts +++ b/src/api/controllers/sendMessage.controller.ts @@ -1,117 +1,97 @@ -import { isBase64, isURL } from 'class-validator'; - -import { Logger } from '../../config/logger.config'; -import { BadRequestException } from '../../exceptions'; -import { InstanceDto } from '../dto/instance.dto'; +import { InstanceDto } from '@api/dto/instance.dto'; import { SendAudioDto, - SendButtonDto, + SendButtonsDto, SendContactDto, SendListDto, SendLocationDto, SendMediaDto, SendPollDto, + SendPtvDto, SendReactionDto, SendStatusDto, SendStickerDto, SendTemplateDto, SendTextDto, -} from '../dto/sendMessage.dto'; -import { WAMonitoringService } from '../services/monitor.service'; - -const logger = new Logger('MessageRouter'); +} from '@api/dto/sendMessage.dto'; +import { WAMonitoringService } from '@api/services/monitor.service'; +import { BadRequestException } from '@exceptions'; +import { isBase64, isURL } from 'class-validator'; export class SendMessageController { constructor(private readonly waMonitor: WAMonitoringService) {} - public async sendText({ instanceName }: InstanceDto, data: SendTextDto) { - logger.verbose('requested sendText from ' + instanceName + ' instance'); - return await this.waMonitor.waInstances[instanceName].textMessage(data); - } - public async sendTemplate({ instanceName }: InstanceDto, data: SendTemplateDto) { - logger.verbose('requested sendList from ' + instanceName + ' instance'); return await this.waMonitor.waInstances[instanceName].templateMessage(data); } - public async sendMedia({ instanceName }: InstanceDto, data: SendMediaDto) { - logger.verbose('requested sendMedia from ' + instanceName + ' instance'); + public async sendText({ instanceName }: InstanceDto, data: SendTextDto) { + return await this.waMonitor.waInstances[instanceName].textMessage(data); + } - if ( - isBase64(data?.mediaMessage?.media) && - !data?.mediaMessage?.fileName && - data?.mediaMessage?.mediatype === 'document' - ) { + public async sendMedia({ instanceName }: InstanceDto, data: SendMediaDto, file?: any) { + if (isBase64(data?.media) && !data?.fileName && data?.mediatype === 'document') { throw new BadRequestException('For base64 the file name must be informed.'); } - logger.verbose('isURL: ' + isURL(data?.mediaMessage?.media) + ', isBase64: ' + isBase64(data?.mediaMessage?.media)); - if (isURL(data?.mediaMessage?.media) || isBase64(data?.mediaMessage?.media)) { - return await this.waMonitor.waInstances[instanceName].mediaMessage(data); + if (file || isURL(data?.media) || isBase64(data?.media)) { + return await this.waMonitor.waInstances[instanceName].mediaMessage(data, file); } throw new BadRequestException('Owned media must be a url or base64'); } - public async sendSticker({ instanceName }: InstanceDto, data: SendStickerDto) { - logger.verbose('requested sendSticker from ' + instanceName + ' instance'); - - logger.verbose( - 'isURL: ' + isURL(data?.stickerMessage?.image) + ', isBase64: ' + isBase64(data?.stickerMessage?.image), - ); - if (isURL(data.stickerMessage.image) || isBase64(data.stickerMessage.image)) { - return await this.waMonitor.waInstances[instanceName].mediaSticker(data); + public async sendPtv({ instanceName }: InstanceDto, data: SendPtvDto, file?: any) { + if (file || isURL(data?.video) || isBase64(data?.video)) { + return await this.waMonitor.waInstances[instanceName].ptvMessage(data, file); } throw new BadRequestException('Owned media must be a url or base64'); } - public async sendWhatsAppAudio({ instanceName }: InstanceDto, data: SendAudioDto) { - logger.verbose('requested sendWhatsAppAudio from ' + instanceName + ' instance'); - - logger.verbose('isURL: ' + isURL(data?.audioMessage?.audio) + ', isBase64: ' + isBase64(data?.audioMessage?.audio)); - if (isURL(data.audioMessage.audio) || isBase64(data.audioMessage.audio)) { - return await this.waMonitor.waInstances[instanceName].audioWhatsapp(data); + public async sendSticker({ instanceName }: InstanceDto, data: SendStickerDto, file?: any) { + if (file || isURL(data.sticker) || isBase64(data.sticker)) { + return await this.waMonitor.waInstances[instanceName].mediaSticker(data, file); } throw new BadRequestException('Owned media must be a url or base64'); } - public async sendButtons({ instanceName }: InstanceDto, data: SendButtonDto) { - logger.verbose('requested sendButtons from ' + instanceName + ' instance'); - if (isBase64(data.buttonMessage.mediaMessage?.media) && !data.buttonMessage.mediaMessage?.fileName) { - throw new BadRequestException('For bse64 the file name must be informed.'); + public async sendWhatsAppAudio({ instanceName }: InstanceDto, data: SendAudioDto, file?: any) { + if (file?.buffer || isURL(data.audio) || isBase64(data.audio)) { + // Si file existe y tiene buffer, o si es una URL o Base64, continúa + return await this.waMonitor.waInstances[instanceName].audioWhatsapp(data, file); + } else { + console.error('El archivo no tiene buffer o el audio no es una URL o Base64 válida'); + throw new BadRequestException('Owned media must be a url, base64, or valid file with buffer'); } + } + + public async sendButtons({ instanceName }: InstanceDto, data: SendButtonsDto) { return await this.waMonitor.waInstances[instanceName].buttonMessage(data); } public async sendLocation({ instanceName }: InstanceDto, data: SendLocationDto) { - logger.verbose('requested sendLocation from ' + instanceName + ' instance'); return await this.waMonitor.waInstances[instanceName].locationMessage(data); } public async sendList({ instanceName }: InstanceDto, data: SendListDto) { - logger.verbose('requested sendList from ' + instanceName + ' instance'); return await this.waMonitor.waInstances[instanceName].listMessage(data); } public async sendContact({ instanceName }: InstanceDto, data: SendContactDto) { - logger.verbose('requested sendContact from ' + instanceName + ' instance'); return await this.waMonitor.waInstances[instanceName].contactMessage(data); } public async sendReaction({ instanceName }: InstanceDto, data: SendReactionDto) { - logger.verbose('requested sendReaction from ' + instanceName + ' instance'); - if (!data.reactionMessage.reaction.match(/[^()\w\sà-ú"-+]+/)) { + if (!data.reaction.match(/[^()\w\sà-ú"-+]+/)) { throw new BadRequestException('"reaction" must be an emoji'); } return await this.waMonitor.waInstances[instanceName].reactionMessage(data); } public async sendPoll({ instanceName }: InstanceDto, data: SendPollDto) { - logger.verbose('requested sendPoll from ' + instanceName + ' instance'); return await this.waMonitor.waInstances[instanceName].pollMessage(data); } - public async sendStatus({ instanceName }: InstanceDto, data: SendStatusDto) { - logger.verbose('requested sendStatus from ' + instanceName + ' instance'); - return await this.waMonitor.waInstances[instanceName].statusMessage(data); + public async sendStatus({ instanceName }: InstanceDto, data: SendStatusDto, file?: any) { + return await this.waMonitor.waInstances[instanceName].statusMessage(data, file); } } diff --git a/src/api/controllers/settings.controller.ts b/src/api/controllers/settings.controller.ts index 15563647..8a600a24 100644 --- a/src/api/controllers/settings.controller.ts +++ b/src/api/controllers/settings.controller.ts @@ -1,21 +1,15 @@ -import { Logger } from '../../config/logger.config'; -import { InstanceDto } from '../dto/instance.dto'; -import { SettingsDto } from '../dto/settings.dto'; -import { SettingsService } from '../services/settings.service'; - -const logger = new Logger('SettingsController'); +import { InstanceDto } from '@api/dto/instance.dto'; +import { SettingsDto } from '@api/dto/settings.dto'; +import { SettingsService } from '@api/services/settings.service'; export class SettingsController { constructor(private readonly settingsService: SettingsService) {} public async createSettings(instance: InstanceDto, data: SettingsDto) { - logger.verbose('requested createSettings from ' + instance.instanceName + ' instance'); - return this.settingsService.create(instance, data); } public async findSettings(instance: InstanceDto) { - logger.verbose('requested findSettings from ' + instance.instanceName + ' instance'); const settings = this.settingsService.find(instance); return settings; } diff --git a/src/api/controllers/template.controller.ts b/src/api/controllers/template.controller.ts new file mode 100644 index 00000000..d9b62045 --- /dev/null +++ b/src/api/controllers/template.controller.ts @@ -0,0 +1,15 @@ +import { InstanceDto } from '@api/dto/instance.dto'; +import { TemplateDto } from '@api/dto/template.dto'; +import { TemplateService } from '@api/services/template.service'; + +export class TemplateController { + constructor(private readonly templateService: TemplateService) {} + + public async createTemplate(instance: InstanceDto, data: TemplateDto) { + return this.templateService.create(instance, data); + } + + public async findTemplate(instance: InstanceDto) { + return this.templateService.find(instance); + } +} diff --git a/src/api/controllers/webhook.controller.ts b/src/api/controllers/webhook.controller.ts deleted file mode 100644 index 660d9235..00000000 --- a/src/api/controllers/webhook.controller.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { isURL } from 'class-validator'; - -import { Logger } from '../../config/logger.config'; -import { BadRequestException } from '../../exceptions'; -import { InstanceDto } from '../dto/instance.dto'; -import { WebhookDto } from '../dto/webhook.dto'; -import { WAMonitoringService } from '../services/monitor.service'; -import { WebhookService } from '../services/webhook.service'; - -const logger = new Logger('WebhookController'); - -export class WebhookController { - constructor(private readonly webhookService: WebhookService, private readonly waMonitor: WAMonitoringService) {} - - public async createWebhook(instance: InstanceDto, data: WebhookDto) { - logger.verbose('requested createWebhook from ' + instance.instanceName + ' instance'); - - if (!isURL(data.url, { require_tld: false })) { - throw new BadRequestException('Invalid "url" property'); - } - - data.enabled = data.enabled ?? true; - - if (!data.enabled) { - logger.verbose('webhook disabled'); - data.url = ''; - data.events = []; - } else if (data.events.length === 0) { - logger.verbose('webhook events empty'); - data.events = [ - 'APPLICATION_STARTUP', - 'QRCODE_UPDATED', - 'MESSAGES_SET', - 'MESSAGES_UPSERT', - 'MESSAGES_UPDATE', - 'MESSAGES_DELETE', - 'SEND_MESSAGE', - 'CONTACTS_SET', - 'CONTACTS_UPSERT', - 'CONTACTS_UPDATE', - 'PRESENCE_UPDATE', - 'CHATS_SET', - 'CHATS_UPSERT', - 'CHATS_UPDATE', - 'CHATS_DELETE', - 'GROUPS_UPSERT', - 'GROUP_UPDATE', - 'GROUP_PARTICIPANTS_UPDATE', - 'CONNECTION_UPDATE', - 'LABELS_EDIT', - 'LABELS_ASSOCIATION', - 'CALL', - 'NEW_JWT_TOKEN', - 'TYPEBOT_START', - 'TYPEBOT_CHANGE_STATUS', - 'CHAMA_AI_ACTION', - ]; - } - - return this.webhookService.create(instance, data); - } - - public async findWebhook(instance: InstanceDto) { - logger.verbose('requested findWebhook from ' + instance.instanceName + ' instance'); - return this.webhookService.find(instance); - } - - public async receiveWebhook(instance: InstanceDto, data: any) { - logger.verbose('requested receiveWebhook from ' + instance.instanceName + ' instance'); - return await this.waMonitor.waInstances[instance.instanceName].connectToWhatsapp(data); - } -} diff --git a/src/api/dto/call.dto.ts b/src/api/dto/call.dto.ts new file mode 100644 index 00000000..310b3779 --- /dev/null +++ b/src/api/dto/call.dto.ts @@ -0,0 +1,8 @@ +export class Metadata { + number: string; +} + +export class OfferCallDto extends Metadata { + isVideo?: boolean; + callDuration?: number; +} diff --git a/src/api/dto/chat.dto.ts b/src/api/dto/chat.dto.ts index 3ed55d52..00da7fdd 100644 --- a/src/api/dto/chat.dto.ts +++ b/src/api/dto/chat.dto.ts @@ -1,4 +1,11 @@ -import { proto, WAPresence, WAPrivacyOnlineValue, WAPrivacyValue, WAReadReceiptsValue } from '@whiskeysockets/baileys'; +import { + proto, + WAPresence, + WAPrivacyGroupAddValue, + WAPrivacyOnlineValue, + WAPrivacyValue, + WAReadReceiptsValue, +} from 'baileys'; export class OnWhatsAppDto { constructor( @@ -59,7 +66,7 @@ class Key { remoteJid: string; } export class ReadMessageDto { - read_messages: Key[]; + readMessages: Key[]; } export class LastMessage { @@ -78,17 +85,13 @@ export class MarkChatUnreadDto { chat?: string; } -class PrivacySetting { +export class PrivacySettingDto { readreceipts: WAReadReceiptsValue; profile: WAPrivacyValue; status: WAPrivacyValue; online: WAPrivacyOnlineValue; last: WAPrivacyValue; - groupadd: WAPrivacyValue; -} - -export class PrivacySettingDto { - privacySettings: PrivacySetting; + groupadd: WAPrivacyGroupAddValue; } export class DeleteMessage { @@ -109,10 +112,8 @@ export class Metadata extends OptionsMessage { } export class SendPresenceDto extends Metadata { - options: { - presence: WAPresence; - delay: number; - }; + presence: WAPresence; + delay: number; } export class UpdateMessageDto extends Metadata { diff --git a/src/api/dto/chatbot.dto.ts b/src/api/dto/chatbot.dto.ts new file mode 100644 index 00000000..e1515483 --- /dev/null +++ b/src/api/dto/chatbot.dto.ts @@ -0,0 +1,12 @@ +export class Session { + remoteJid?: string; + sessionId?: string; + status?: string; + createdAt?: number; + updateAt?: number; +} + +export class IgnoreJidDto { + remoteJid?: string; + action?: string; +} diff --git a/src/api/dto/instance.dto.ts b/src/api/dto/instance.dto.ts index d9a4d87a..1da3bf1c 100644 --- a/src/api/dto/instance.dto.ts +++ b/src/api/dto/instance.dto.ts @@ -1,51 +1,56 @@ -import { WAPresence } from '@whiskeysockets/baileys'; +import { IntegrationDto } from '@api/integrations/integration.dto'; +import { JsonValue } from '@prisma/client/runtime/library'; +import { WAPresence } from 'baileys'; -import { ProxyDto } from './proxy.dto'; - -export class InstanceDto { +export class InstanceDto extends IntegrationDto { instanceName: string; instanceId?: string; qrcode?: boolean; + businessId?: string; number?: string; - mobile?: boolean; integration?: string; token?: string; - webhook?: string; - webhook_by_events?: boolean; - webhook_base64?: boolean; - events?: string[]; - reject_call?: boolean; - msg_call?: string; - groups_ignore?: boolean; - always_online?: boolean; - read_messages?: boolean; - read_status?: boolean; - sync_full_history?: boolean; - chatwoot_account_id?: string; - chatwoot_token?: string; - chatwoot_url?: string; - chatwoot_sign_msg?: boolean; - chatwoot_reopen_conversation?: boolean; - chatwoot_conversation_pending?: boolean; - chatwoot_merge_brazil_contacts?: boolean; - chatwoot_import_contacts?: boolean; - chatwoot_import_messages?: boolean; - chatwoot_days_limit_import_messages?: number; - chatwoot_name_inbox?: string; - websocket_enabled?: boolean; - websocket_events?: string[]; - rabbitmq_enabled?: boolean; - rabbitmq_events?: string[]; - sqs_enabled?: boolean; - sqs_events?: string[]; - typebot_url?: string; - typebot?: string; - typebot_expire?: number; - typebot_keyword_finish?: string; - typebot_delay_message?: number; - typebot_unknown_message?: string; - typebot_listening_from_me?: boolean; - proxy?: ProxyDto['proxy']; + status?: string; + ownerJid?: string; + profileName?: string; + profilePicUrl?: string; + // settings + rejectCall?: boolean; + msgCall?: string; + groupsIgnore?: boolean; + alwaysOnline?: boolean; + readMessages?: boolean; + readStatus?: boolean; + syncFullHistory?: boolean; + wavoipToken?: string; + // proxy + proxyHost?: string; + proxyPort?: string; + proxyProtocol?: string; + proxyUsername?: string; + proxyPassword?: string; + webhook?: { + enabled?: boolean; + events?: string[]; + headers?: JsonValue; + url?: string; + byEvents?: boolean; + base64?: boolean; + }; + chatwootAccountId?: string; + chatwootConversationPending?: boolean; + chatwootAutoCreate?: boolean; + chatwootDaysLimitImportMessages?: number; + chatwootImportContacts?: boolean; + chatwootImportMessages?: boolean; + chatwootLogo?: string; + chatwootMergeBrazilContacts?: boolean; + chatwootNameInbox?: string; + chatwootOrganization?: string; + chatwootReopenConversation?: boolean; + chatwootSignMsg?: boolean; + chatwootToken?: string; + chatwootUrl?: string; } export class SetPresenceDto { diff --git a/src/api/dto/integration.dto.ts b/src/api/dto/integration.dto.ts deleted file mode 100644 index a4cb67a0..00000000 --- a/src/api/dto/integration.dto.ts +++ /dev/null @@ -1,5 +0,0 @@ -export class IntegrationDto { - integration: string; - number: string; - token: string; -} diff --git a/src/api/dto/label.dto.ts b/src/api/dto/label.dto.ts index 23ff47bb..706474a0 100644 --- a/src/api/dto/label.dto.ts +++ b/src/api/dto/label.dto.ts @@ -1,7 +1,7 @@ export class LabelDto { id?: string; name: string; - color: number; + color: string; predefinedId?: string; } diff --git a/src/api/dto/proxy.dto.ts b/src/api/dto/proxy.dto.ts index 7f3e7c06..2e5b2f4d 100644 --- a/src/api/dto/proxy.dto.ts +++ b/src/api/dto/proxy.dto.ts @@ -1,12 +1,8 @@ -class Proxy { +export class ProxyDto { + enabled?: boolean; host: string; port: string; protocol: string; username?: string; password?: string; } - -export class ProxyDto { - enabled: boolean; - proxy: Proxy; -} diff --git a/src/api/dto/sendMessage.dto.ts b/src/api/dto/sendMessage.dto.ts index 7bb33074..1c9b1154 100644 --- a/src/api/dto/sendMessage.dto.ts +++ b/src/api/dto/sendMessage.dto.ts @@ -1,33 +1,29 @@ -import { proto, WAPresence } from '@whiskeysockets/baileys'; +import { proto, WAPresence } from 'baileys'; export class Quoted { key: proto.IMessageKey; message: proto.IMessage; } -export class Mentions { - everyOne: boolean; - mentioned: string[]; -} - export class Options { delay?: number; presence?: WAPresence; quoted?: Quoted; - mentions?: Mentions; linkPreview?: boolean; encoding?: boolean; -} -class OptionsMessage { - options: Options; + mentionsEveryOne?: boolean; + mentioned?: string[]; + webhookUrl?: string; } -export class Metadata extends OptionsMessage { - number: string; -} - -class TextMessage { - text: string; +export class MediaMessage { + mediatype: MediaType; + mimetype?: string; + caption?: string; + // for document + fileName?: string; + // url or base64 + media: string; } export class StatusMessage { @@ -40,30 +36,43 @@ export class StatusMessage { font?: number; } -class PollMessage { +export class Metadata { + number: string; + delay?: number; + quoted?: Quoted; + linkPreview?: boolean; + mentionsEveryOne?: boolean; + mentioned?: string[]; + encoding?: boolean; +} + +export class SendTextDto extends Metadata { + text: string; +} +export class SendPresence extends Metadata { + text: string; +} + +export class SendStatusDto extends Metadata { + type: string; + content: string; + statusJidList?: string[]; + allContacts?: boolean; + caption?: string; + backgroundColor?: string; + font?: number; +} + +export class SendPollDto extends Metadata { name: string; selectableCount: number; values: string[]; messageSecret?: Uint8Array; } -export class SendTextDto extends Metadata { - textMessage: TextMessage; -} -export class SendPresence extends Metadata { - textMessage: TextMessage; -} +export type MediaType = 'image' | 'document' | 'video' | 'audio' | 'ptv'; -export class SendStatusDto extends Metadata { - statusMessage: StatusMessage; -} - -export class SendPollDto extends Metadata { - pollMessage: PollMessage; -} - -export type MediaType = 'image' | 'document' | 'video' | 'audio'; -export class MediaMessage { +export class SendMediaDto extends Metadata { mediatype: MediaType; mimetype?: string; caption?: string; @@ -72,47 +81,50 @@ export class MediaMessage { // url or base64 media: string; } -export class SendMediaDto extends Metadata { - mediaMessage: MediaMessage; -} -class Sticker { - image: string; -} -export class SendStickerDto extends Metadata { - stickerMessage: Sticker; + +export class SendPtvDto extends Metadata { + video: string; } -class Audio { +export class SendStickerDto extends Metadata { + sticker: string; +} + +export class SendAudioDto extends Metadata { audio: string; } -export class SendAudioDto extends Metadata { - audioMessage: Audio; + +export type TypeButton = 'reply' | 'copy' | 'url' | 'call' | 'pix'; + +export type KeyType = 'phone' | 'email' | 'cpf' | 'cnpj' | 'random'; + +export class Button { + type: TypeButton; + displayText?: string; + id?: string; + url?: string; + copyCode?: string; + phoneNumber?: string; + currency?: string; + name?: string; + keyType?: KeyType; + key?: string; } -class Button { - buttonText: string; - buttonId: string; -} -class ButtonMessage { +export class SendButtonsDto extends Metadata { + thumbnailUrl?: string; title: string; - description: string; - footerText?: string; + description?: string; + footer?: string; buttons: Button[]; - mediaMessage?: MediaMessage; -} -export class SendButtonDto extends Metadata { - buttonMessage: ButtonMessage; } -class LocationMessage { +export class SendLocationDto extends Metadata { latitude: number; longitude: number; name?: string; address?: string; } -export class SendLocationDto extends Metadata { - locationMessage: LocationMessage; -} class Row { title: string; @@ -123,16 +135,13 @@ class Section { title: string; rows: Row[]; } -class ListMessage { +export class SendListDto extends Metadata { title: string; - description: string; + description?: string; footerText?: string; buttonText: string; sections: Section[]; } -export class SendListDto extends Metadata { - listMessage: ListMessage; -} export class ContactMessage { fullName: string; @@ -143,23 +152,17 @@ export class ContactMessage { url?: string; } -export class TemplateMessage { +export class SendTemplateDto extends Metadata { name: string; language: string; components: any; -} - -export class SendTemplateDto extends Metadata { - templateMessage: TemplateMessage; + webhookUrl?: string; } export class SendContactDto extends Metadata { - contactMessage: ContactMessage[]; + contact: ContactMessage[]; } -class ReactionMessage { +export class SendReactionDto { key: proto.IMessageKey; reaction: string; } -export class SendReactionDto { - reactionMessage: ReactionMessage; -} diff --git a/src/api/dto/settings.dto.ts b/src/api/dto/settings.dto.ts index 8cd67948..4779ef49 100644 --- a/src/api/dto/settings.dto.ts +++ b/src/api/dto/settings.dto.ts @@ -1,9 +1,10 @@ export class SettingsDto { - reject_call?: boolean; - msg_call?: string; - groups_ignore?: boolean; - always_online?: boolean; - read_messages?: boolean; - read_status?: boolean; - sync_full_history?: boolean; + rejectCall?: boolean; + msgCall?: string; + groupsIgnore?: boolean; + alwaysOnline?: boolean; + readMessages?: boolean; + readStatus?: boolean; + syncFullHistory?: boolean; + wavoipToken?: string; } diff --git a/src/api/dto/template.dto.ts b/src/api/dto/template.dto.ts new file mode 100644 index 00000000..cec7d6c5 --- /dev/null +++ b/src/api/dto/template.dto.ts @@ -0,0 +1,8 @@ +export class TemplateDto { + name: string; + category: string; + allowCategoryChange: boolean; + language: string; + components: any; + webhookUrl?: string; +} diff --git a/src/api/dto/webhook.dto.ts b/src/api/dto/webhook.dto.ts deleted file mode 100644 index 87a21883..00000000 --- a/src/api/dto/webhook.dto.ts +++ /dev/null @@ -1,7 +0,0 @@ -export class WebhookDto { - enabled?: boolean; - url?: string; - events?: string[]; - webhook_by_events?: boolean; - webhook_base64?: boolean; -} diff --git a/src/api/guards/auth.guard.ts b/src/api/guards/auth.guard.ts index 4ed0898b..9ad20b61 100644 --- a/src/api/guards/auth.guard.ts +++ b/src/api/guards/auth.guard.ts @@ -1,60 +1,12 @@ -import { isJWT } from 'class-validator'; +import { InstanceDto } from '@api/dto/instance.dto'; +import { prismaRepository } from '@api/server.module'; +import { Auth, configService, Database } from '@config/env.config'; +import { Logger } from '@config/logger.config'; +import { ForbiddenException, UnauthorizedException } from '@exceptions'; import { NextFunction, Request, Response } from 'express'; -import jwt from 'jsonwebtoken'; - -import { name } from '../../../package.json'; -import { Auth, configService, Database } from '../../config/env.config'; -import { Logger } from '../../config/logger.config'; -import { ForbiddenException, UnauthorizedException } from '../../exceptions'; -import { InstanceDto } from '../dto/instance.dto'; -import { repository } from '../server.module'; -import { JwtPayload } from '../services/auth.service'; const logger = new Logger('GUARD'); -async function jwtGuard(req: Request, res: Response, next: NextFunction) { - const key = req.get('apikey'); - - if (key && configService.get('AUTHENTICATION').API_KEY.KEY !== key) { - throw new UnauthorizedException(); - } - - if (configService.get('AUTHENTICATION').API_KEY.KEY === key) { - return next(); - } - - if ((req.originalUrl.includes('/instance/create') || req.originalUrl.includes('/instance/fetchInstances')) && !key) { - throw new ForbiddenException('Missing global api key', 'The global api key must be set'); - } - - const jwtOpts = configService.get('AUTHENTICATION').JWT; - try { - const [bearer, token] = req.get('authorization').split(' '); - - if (bearer.toLowerCase() !== 'bearer') { - throw new UnauthorizedException(); - } - - if (!isJWT(token)) { - throw new UnauthorizedException(); - } - - const param = req.params as unknown as InstanceDto; - const decode = jwt.verify(token, jwtOpts.SECRET, { - ignoreExpiration: jwtOpts.EXPIRIN_IN === 0, - }) as JwtPayload; - - if (param.instanceName !== decode.instanceName || name !== decode.apiName) { - throw new UnauthorizedException(); - } - - return next(); - } catch (error) { - logger.error(error); - throw new UnauthorizedException(); - } -} - async function apikey(req: Request, _: Response, next: NextFunction) { const env = configService.get('AUTHENTICATION').API_KEY; const key = req.get('apikey'); @@ -75,13 +27,17 @@ async function apikey(req: Request, _: Response, next: NextFunction) { try { if (param?.instanceName) { - const instanceKey = await repository.auth.find(param.instanceName); - if (instanceKey?.apikey === key) { + const instance = await prismaRepository.instance.findUnique({ + where: { name: param.instanceName }, + }); + if (instance.token === key) { return next(); } } else { - if (req.originalUrl.includes('/instance/fetchInstances') && db.ENABLED) { - const instanceByKey = await repository.auth.findByKey(key); + if (req.originalUrl.includes('/instance/fetchInstances') && db.SAVE_DATA.INSTANCE) { + const instanceByKey = await prismaRepository.instance.findFirst({ + where: { token: key }, + }); if (instanceByKey) { return next(); } @@ -94,4 +50,4 @@ async function apikey(req: Request, _: Response, next: NextFunction) { throw new UnauthorizedException(); } -export const authGuard = { jwt: jwtGuard, apikey }; +export const authGuard = { apikey }; diff --git a/src/api/guards/instance.guard.ts b/src/api/guards/instance.guard.ts index 84cabb12..e692f362 100644 --- a/src/api/guards/instance.guard.ts +++ b/src/api/guards/instance.guard.ts @@ -1,22 +1,11 @@ +import { InstanceDto } from '@api/dto/instance.dto'; +import { cache, prismaRepository, waMonitor } from '@api/server.module'; +import { CacheConf, configService } from '@config/env.config'; +import { BadRequestException, ForbiddenException, InternalServerErrorException, NotFoundException } from '@exceptions'; import { NextFunction, Request, Response } from 'express'; -import { existsSync } from 'fs'; -import { join } from 'path'; - -import { CacheConf, configService, Database } from '../../config/env.config'; -import { INSTANCE_DIR } from '../../config/path.config'; -import { - BadRequestException, - ForbiddenException, - InternalServerErrorException, - NotFoundException, -} from '../../exceptions'; -import { dbserver } from '../../libs/db.connect'; -import { InstanceDto } from '../dto/instance.dto'; -import { cache, waMonitor } from '../server.module'; async function getInstance(instanceName: string) { try { - const db = configService.get('DATABASE'); const cacheConf = configService.get('CACHE'); const exists = !!waMonitor.waInstances[instanceName]; @@ -27,15 +16,7 @@ async function getInstance(instanceName: string) { return exists || keyExists; } - if (db.ENABLED) { - const collection = dbserver - .getClient() - .db(db.CONNECTION.DB_PREFIX_NAME + '-instances') - .collection(instanceName); - return exists || (await collection.find({}).toArray()).length > 0; - } - - return exists || existsSync(join(INSTANCE_DIR, instanceName)); + return exists || (await prismaRepository.instance.findMany({ where: { name: instanceName } })).length > 0; } catch (error) { throw new InternalServerErrorException(error?.toString()); } @@ -66,7 +47,6 @@ export async function instanceLoggedGuard(req: Request, _: Response, next: NextF } if (waMonitor.waInstances[instance.instanceName]) { - waMonitor.waInstances[instance.instanceName]?.removeRabbitmqQueues(); delete waMonitor.waInstances[instance.instanceName]; } } diff --git a/src/api/guards/telemetry.guard.ts b/src/api/guards/telemetry.guard.ts new file mode 100644 index 00000000..f82c01ed --- /dev/null +++ b/src/api/guards/telemetry.guard.ts @@ -0,0 +1,12 @@ +import { sendTelemetry } from '@utils/sendTelemetry'; +import { NextFunction, Request, Response } from 'express'; + +class Telemetry { + public collectTelemetry(req: Request, res: Response, next: NextFunction): void { + sendTelemetry(req.path); + + next(); + } +} + +export default Telemetry; diff --git a/src/api/integrations/chamaai/controllers/chamaai.controller.ts b/src/api/integrations/chamaai/controllers/chamaai.controller.ts deleted file mode 100644 index 91b33cd1..00000000 --- a/src/api/integrations/chamaai/controllers/chamaai.controller.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { Logger } from '../../../../config/logger.config'; -import { InstanceDto } from '../../../dto/instance.dto'; -import { ChamaaiDto } from '../dto/chamaai.dto'; -import { ChamaaiService } from '../services/chamaai.service'; - -const logger = new Logger('ChamaaiController'); - -export class ChamaaiController { - constructor(private readonly chamaaiService: ChamaaiService) {} - - public async createChamaai(instance: InstanceDto, data: ChamaaiDto) { - logger.verbose('requested createChamaai from ' + instance.instanceName + ' instance'); - - if (!data.enabled) { - logger.verbose('chamaai disabled'); - data.url = ''; - data.token = ''; - data.waNumber = ''; - data.answerByAudio = false; - } - - return this.chamaaiService.create(instance, data); - } - - public async findChamaai(instance: InstanceDto) { - logger.verbose('requested findChamaai from ' + instance.instanceName + ' instance'); - return this.chamaaiService.find(instance); - } -} diff --git a/src/api/integrations/chamaai/dto/chamaai.dto.ts b/src/api/integrations/chamaai/dto/chamaai.dto.ts deleted file mode 100644 index 2c71a07d..00000000 --- a/src/api/integrations/chamaai/dto/chamaai.dto.ts +++ /dev/null @@ -1,7 +0,0 @@ -export class ChamaaiDto { - enabled: boolean; - url: string; - token: string; - waNumber: string; - answerByAudio: boolean; -} diff --git a/src/api/integrations/chamaai/models/chamaai.model.ts b/src/api/integrations/chamaai/models/chamaai.model.ts deleted file mode 100644 index ef4f252b..00000000 --- a/src/api/integrations/chamaai/models/chamaai.model.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Schema } from 'mongoose'; - -import { dbserver } from '../../../../libs/db.connect'; - -export class ChamaaiRaw { - _id?: string; - enabled?: boolean; - url?: string; - token?: string; - waNumber?: string; - answerByAudio?: boolean; -} - -const chamaaiSchema = new Schema({ - _id: { type: String, _id: true }, - enabled: { type: Boolean, required: true }, - url: { type: String, required: true }, - token: { type: String, required: true }, - waNumber: { type: String, required: true }, - answerByAudio: { type: Boolean, required: true }, -}); - -export const ChamaaiModel = dbserver?.model(ChamaaiRaw.name, chamaaiSchema, 'chamaai'); -export type IChamaaiModel = typeof ChamaaiModel; diff --git a/src/api/integrations/chamaai/repository/chamaai.repository.ts b/src/api/integrations/chamaai/repository/chamaai.repository.ts deleted file mode 100644 index 17ff8dcd..00000000 --- a/src/api/integrations/chamaai/repository/chamaai.repository.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { readFileSync } from 'fs'; -import { join } from 'path'; - -import { ConfigService } from '../../../../config/env.config'; -import { Logger } from '../../../../config/logger.config'; -import { IInsert, Repository } from '../../../abstract/abstract.repository'; -import { ChamaaiRaw, IChamaaiModel } from '../../../models'; - -export class ChamaaiRepository extends Repository { - constructor(private readonly chamaaiModel: IChamaaiModel, private readonly configService: ConfigService) { - super(configService); - } - - private readonly logger = new Logger('ChamaaiRepository'); - - public async create(data: ChamaaiRaw, instance: string): Promise { - try { - this.logger.verbose('creating chamaai'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('saving chamaai to db'); - const insert = await this.chamaaiModel.replaceOne({ _id: instance }, { ...data }, { upsert: true }); - - this.logger.verbose('chamaai saved to db: ' + insert.modifiedCount + ' chamaai'); - return { insertCount: insert.modifiedCount }; - } - - this.logger.verbose('saving chamaai to store'); - - this.writeStore({ - path: join(this.storePath, 'chamaai'), - fileName: instance, - data, - }); - - this.logger.verbose('chamaai saved to store in path: ' + join(this.storePath, 'chamaai') + '/' + instance); - - this.logger.verbose('chamaai created'); - return { insertCount: 1 }; - } catch (error) { - return error; - } - } - - public async find(instance: string): Promise { - try { - this.logger.verbose('finding chamaai'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding chamaai in db'); - return await this.chamaaiModel.findOne({ _id: instance }); - } - - this.logger.verbose('finding chamaai in store'); - return JSON.parse( - readFileSync(join(this.storePath, 'chamaai', instance + '.json'), { - encoding: 'utf-8', - }), - ) as ChamaaiRaw; - } catch (error) { - return {}; - } - } -} diff --git a/src/api/integrations/chamaai/routes/chamaai.router.ts b/src/api/integrations/chamaai/routes/chamaai.router.ts deleted file mode 100644 index 3ade4b43..00000000 --- a/src/api/integrations/chamaai/routes/chamaai.router.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { RequestHandler, Router } from 'express'; - -import { Logger } from '../../../../config/logger.config'; -import { chamaaiSchema, instanceNameSchema } from '../../../../validate/validate.schema'; -import { RouterBroker } from '../../../abstract/abstract.router'; -import { InstanceDto } from '../../../dto/instance.dto'; -import { HttpStatus } from '../../../routes/index.router'; -import { chamaaiController } from '../../../server.module'; -import { ChamaaiDto } from '../dto/chamaai.dto'; - -const logger = new Logger('ChamaaiRouter'); - -export class ChamaaiRouter extends RouterBroker { - constructor(...guards: RequestHandler[]) { - super(); - this.router - .post(this.routerPath('set'), ...guards, async (req, res) => { - logger.verbose('request received in setChamaai'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - const response = await this.dataValidate({ - request: req, - schema: chamaaiSchema, - ClassRef: ChamaaiDto, - execute: (instance, data) => chamaaiController.createChamaai(instance, data), - }); - - res.status(HttpStatus.CREATED).json(response); - }) - .get(this.routerPath('find'), ...guards, async (req, res) => { - logger.verbose('request received in findChamaai'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - const response = await this.dataValidate({ - request: req, - schema: instanceNameSchema, - ClassRef: InstanceDto, - execute: (instance) => chamaaiController.findChamaai(instance), - }); - - res.status(HttpStatus.OK).json(response); - }); - } - - public readonly router = Router(); -} diff --git a/src/api/integrations/chamaai/services/chamaai.service.ts b/src/api/integrations/chamaai/services/chamaai.service.ts deleted file mode 100644 index 911732a8..00000000 --- a/src/api/integrations/chamaai/services/chamaai.service.ts +++ /dev/null @@ -1,230 +0,0 @@ -import axios from 'axios'; -import { writeFileSync } from 'fs'; -import path from 'path'; - -import { ConfigService, HttpServer } from '../../../../config/env.config'; -import { Logger } from '../../../../config/logger.config'; -import { InstanceDto } from '../../../dto/instance.dto'; -import { ChamaaiRaw } from '../../../models'; -import { WAMonitoringService } from '../../../services/monitor.service'; -import { Events } from '../../../types/wa.types'; -import { ChamaaiDto } from '../dto/chamaai.dto'; - -export class ChamaaiService { - constructor(private readonly waMonitor: WAMonitoringService, private readonly configService: ConfigService) {} - - private readonly logger = new Logger(ChamaaiService.name); - - public create(instance: InstanceDto, data: ChamaaiDto) { - this.logger.verbose('create chamaai: ' + instance.instanceName); - this.waMonitor.waInstances[instance.instanceName].setChamaai(data); - - return { chamaai: { ...instance, chamaai: data } }; - } - - public async find(instance: InstanceDto): Promise { - try { - this.logger.verbose('find chamaai: ' + instance.instanceName); - const result = await this.waMonitor.waInstances[instance.instanceName].findChamaai(); - - if (Object.keys(result).length === 0) { - throw new Error('Chamaai not found'); - } - - return result; - } catch (error) { - return { enabled: false, url: '', token: '', waNumber: '', answerByAudio: false }; - } - } - - private getTypeMessage(msg: any) { - this.logger.verbose('get type message'); - - const types = { - conversation: msg.conversation, - extendedTextMessage: msg.extendedTextMessage?.text, - }; - - this.logger.verbose('type message: ' + types); - - return types; - } - - private getMessageContent(types: any) { - this.logger.verbose('get message content'); - const typeKey = Object.keys(types).find((key) => types[key] !== undefined); - - const result = typeKey ? types[typeKey] : undefined; - - this.logger.verbose('message content: ' + result); - - return result; - } - - private getConversationMessage(msg: any) { - this.logger.verbose('get conversation message'); - - const types = this.getTypeMessage(msg); - - const messageContent = this.getMessageContent(types); - - this.logger.verbose('conversation message: ' + messageContent); - - return messageContent; - } - - private calculateTypingTime(text: string) { - const wordsPerMinute = 100; - - const wordCount = text.split(' ').length; - const typingTimeInMinutes = wordCount / wordsPerMinute; - const typingTimeInMilliseconds = typingTimeInMinutes * 60; - return typingTimeInMilliseconds; - } - - private convertToMilliseconds(count: number) { - const averageCharactersPerSecond = 15; - const characterCount = count; - const speakingTimeInSeconds = characterCount / averageCharactersPerSecond; - return speakingTimeInSeconds; - } - - private getRegexPatterns() { - const patternsToCheck = [ - '.*atend.*humano.*', - '.*falar.*com.*um.*humano.*', - '.*fala.*humano.*', - '.*atend.*humano.*', - '.*fala.*atend.*', - '.*preciso.*ajuda.*', - '.*quero.*suporte.*', - '.*preciso.*assiste.*', - '.*ajuda.*atend.*', - '.*chama.*atendente.*', - '.*suporte.*urgente.*', - '.*atend.*por.*favor.*', - '.*quero.*falar.*com.*alguém.*', - '.*falar.*com.*um.*humano.*', - '.*transfer.*humano.*', - '.*transfer.*atend.*', - '.*equipe.*humano.*', - '.*suporte.*humano.*', - ]; - - const regexPatterns = patternsToCheck.map((pattern) => new RegExp(pattern, 'iu')); - return regexPatterns; - } - - public async sendChamaai(instance: InstanceDto, remoteJid: string, msg: any) { - const content = this.getConversationMessage(msg.message); - const msgType = msg.messageType; - const find = await this.find(instance); - const url = find.url; - const token = find.token; - const waNumber = find.waNumber; - const answerByAudio = find.answerByAudio; - - if (!content && msgType !== 'audioMessage') { - return; - } - - let data; - let endpoint; - - if (msgType === 'audioMessage') { - const downloadBase64 = await this.waMonitor.waInstances[instance.instanceName].getBase64FromMediaMessage({ - message: { - ...msg, - }, - }); - - const random = Math.random().toString(36).substring(7); - const nameFile = `${random}.ogg`; - - const fileData = Buffer.from(downloadBase64.base64, 'base64'); - - const fileName = `${path.join( - this.waMonitor.waInstances[instance.instanceName].storePath, - 'temp', - `${nameFile}`, - )}`; - - writeFileSync(fileName, fileData, 'utf8'); - - const urlServer = this.configService.get('SERVER').URL; - - const url = `${urlServer}/store/temp/${nameFile}`; - - data = { - waNumber: waNumber, - audioUrl: url, - queryNumber: remoteJid.split('@')[0], - answerByAudio: answerByAudio, - }; - endpoint = 'processMessageAudio'; - } else { - data = { - waNumber: waNumber, - question: content, - queryNumber: remoteJid.split('@')[0], - answerByAudio: answerByAudio, - }; - endpoint = 'processMessageText'; - } - - const request = await axios.post(`${url}/${endpoint}`, data, { - headers: { - Authorization: `${token}`, - }, - }); - - const answer = request.data?.answer; - - const type = request.data?.type; - - const characterCount = request.data?.characterCount; - - if (answer) { - if (type === 'text') { - this.waMonitor.waInstances[instance.instanceName].textMessage({ - number: remoteJid.split('@')[0], - options: { - delay: this.calculateTypingTime(answer) * 1000 || 1000, - presence: 'composing', - linkPreview: false, - quoted: { - key: msg.key, - message: msg.message, - }, - }, - textMessage: { - text: answer, - }, - }); - } - - if (type === 'audio') { - this.waMonitor.waInstances[instance.instanceName].audioWhatsapp({ - number: remoteJid.split('@')[0], - options: { - delay: characterCount ? this.convertToMilliseconds(characterCount) * 1000 || 1000 : 1000, - presence: 'recording', - encoding: true, - }, - audioMessage: { - audio: answer, - }, - }); - } - - if (this.getRegexPatterns().some((pattern) => pattern.test(answer))) { - this.waMonitor.waInstances[instance.instanceName].sendDataWebhook(Events.CHAMA_AI_ACTION, { - remoteJid: remoteJid, - message: msg, - answer: answer, - action: 'transfer', - }); - } - } - } -} diff --git a/src/api/integrations/channel/channel.controller.ts b/src/api/integrations/channel/channel.controller.ts new file mode 100644 index 00000000..051be726 --- /dev/null +++ b/src/api/integrations/channel/channel.controller.ts @@ -0,0 +1,95 @@ +import { InstanceDto } from '@api/dto/instance.dto'; +import { ProviderFiles } from '@api/provider/sessions'; +import { PrismaRepository } from '@api/repository/repository.service'; +import { CacheService } from '@api/services/cache.service'; +import { WAMonitoringService } from '@api/services/monitor.service'; +import { Integration } from '@api/types/wa.types'; +import { ConfigService } from '@config/env.config'; +import { BadRequestException } from '@exceptions'; +import EventEmitter2 from 'eventemitter2'; + +import { EvolutionStartupService } from './evolution/evolution.channel.service'; +import { BusinessStartupService } from './meta/whatsapp.business.service'; +import { BaileysStartupService } from './whatsapp/whatsapp.baileys.service'; + +type ChannelDataType = { + configService: ConfigService; + eventEmitter: EventEmitter2; + prismaRepository: PrismaRepository; + cache: CacheService; + chatwootCache: CacheService; + baileysCache: CacheService; + providerFiles: ProviderFiles; +}; + +export interface ChannelControllerInterface { + receiveWebhook(data: any): Promise; +} + +export class ChannelController { + public prismaRepository: PrismaRepository; + public waMonitor: WAMonitoringService; + + constructor(prismaRepository: PrismaRepository, waMonitor: WAMonitoringService) { + this.prisma = prismaRepository; + this.monitor = waMonitor; + } + + public set prisma(prisma: PrismaRepository) { + this.prismaRepository = prisma; + } + + public get prisma() { + return this.prismaRepository; + } + + public set monitor(waMonitor: WAMonitoringService) { + this.waMonitor = waMonitor; + } + + public get monitor() { + return this.waMonitor; + } + + public init(instanceData: InstanceDto, data: ChannelDataType) { + if (!instanceData.token && instanceData.integration === Integration.WHATSAPP_BUSINESS) { + throw new BadRequestException('token is required'); + } + + if (instanceData.integration === Integration.WHATSAPP_BUSINESS) { + return new BusinessStartupService( + data.configService, + data.eventEmitter, + data.prismaRepository, + data.cache, + data.chatwootCache, + data.baileysCache, + data.providerFiles, + ); + } + + if (instanceData.integration === Integration.EVOLUTION) { + return new EvolutionStartupService( + data.configService, + data.eventEmitter, + data.prismaRepository, + data.cache, + data.chatwootCache, + ); + } + + if (instanceData.integration === Integration.WHATSAPP_BAILEYS) { + return new BaileysStartupService( + data.configService, + data.eventEmitter, + data.prismaRepository, + data.cache, + data.chatwootCache, + data.baileysCache, + data.providerFiles, + ); + } + + return null; + } +} diff --git a/src/api/integrations/channel/channel.router.ts b/src/api/integrations/channel/channel.router.ts new file mode 100644 index 00000000..5d878471 --- /dev/null +++ b/src/api/integrations/channel/channel.router.ts @@ -0,0 +1,17 @@ +import { Router } from 'express'; + +import { EvolutionRouter } from './evolution/evolution.router'; +import { MetaRouter } from './meta/meta.router'; +import { BaileysRouter } from './whatsapp/baileys.router'; + +export class ChannelRouter { + public readonly router: Router; + + constructor(configService: any, ...guards: any[]) { + this.router = Router(); + + this.router.use('/', new EvolutionRouter(configService).router); + this.router.use('/', new MetaRouter(configService).router); + this.router.use('/baileys', new BaileysRouter(...guards).router); + } +} diff --git a/src/api/integrations/channel/evolution/evolution.channel.service.ts b/src/api/integrations/channel/evolution/evolution.channel.service.ts new file mode 100644 index 00000000..dba02751 --- /dev/null +++ b/src/api/integrations/channel/evolution/evolution.channel.service.ts @@ -0,0 +1,881 @@ +import { InstanceDto } from '@api/dto/instance.dto'; +import { + MediaMessage, + Options, + SendAudioDto, + SendButtonsDto, + SendMediaDto, + SendTextDto, +} from '@api/dto/sendMessage.dto'; +import * as s3Service from '@api/integrations/storage/s3/libs/minio.server'; +import { PrismaRepository } from '@api/repository/repository.service'; +import { chatbotController } from '@api/server.module'; +import { CacheService } from '@api/services/cache.service'; +import { ChannelStartupService } from '@api/services/channel.service'; +import { Events, wa } from '@api/types/wa.types'; +import { Chatwoot, ConfigService, Openai, S3 } from '@config/env.config'; +import { BadRequestException, InternalServerErrorException } from '@exceptions'; +import { createJid } from '@utils/createJid'; +import axios from 'axios'; +import { isBase64, isURL } from 'class-validator'; +import EventEmitter2 from 'eventemitter2'; +import FormData from 'form-data'; +import mimeTypes from 'mime-types'; +import { join } from 'path'; +import { v4 } from 'uuid'; + +export class EvolutionStartupService extends ChannelStartupService { + constructor( + public readonly configService: ConfigService, + public readonly eventEmitter: EventEmitter2, + public readonly prismaRepository: PrismaRepository, + public readonly cache: CacheService, + public readonly chatwootCache: CacheService, + ) { + super(configService, eventEmitter, prismaRepository, chatwootCache); + + this.client = null; + } + + public client: any; + + public stateConnection: wa.StateConnection = { state: 'open' }; + + public phoneNumber: string; + public mobile: boolean; + + public get connectionStatus() { + return this.stateConnection; + } + + public async closeClient() { + this.stateConnection = { state: 'close' }; + } + + public get qrCode(): wa.QrCode { + return { + pairingCode: this.instance.qrcode?.pairingCode, + code: this.instance.qrcode?.code, + base64: this.instance.qrcode?.base64, + count: this.instance.qrcode?.count, + }; + } + + public async logoutInstance() { + await this.closeClient(); + } + + public setInstance(instance: InstanceDto) { + this.logger.setInstance(instance.instanceId); + + this.instance.name = instance.instanceName; + this.instance.id = instance.instanceId; + this.instance.integration = instance.integration; + this.instance.number = instance.number; + this.instance.token = instance.token; + this.instance.businessId = instance.businessId; + + if (this.configService.get('CHATWOOT').ENABLED && this.localChatwoot?.enabled) { + this.chatwootService.eventWhatsapp( + Events.STATUS_INSTANCE, + { + instanceName: this.instance.name, + instanceId: this.instance.id, + integration: instance.integration, + }, + { + instance: this.instance.name, + status: 'created', + }, + ); + } + } + + public async profilePicture(number: string) { + const jid = createJid(number); + + return { + wuid: jid, + profilePictureUrl: null, + }; + } + + public async getProfileName() { + return null; + } + + public async profilePictureUrl() { + return null; + } + + public async getProfileStatus() { + return null; + } + + public async connectToWhatsapp(data?: any): Promise { + if (!data) { + this.loadChatwoot(); + return; + } + + try { + this.eventHandler(data); + } catch (error) { + this.logger.error(error); + throw new InternalServerErrorException(error?.toString()); + } + } + + protected async eventHandler(received: any) { + try { + let messageRaw: any; + + if (received.message) { + const key = { + id: received.key.id || v4(), + remoteJid: received.key.remoteJid, + fromMe: received.key.fromMe, + profilePicUrl: received.profilePicUrl, + }; + messageRaw = { + key, + pushName: received.pushName, + message: received.message, + messageType: received.messageType, + messageTimestamp: Math.round(new Date().getTime() / 1000), + source: 'unknown', + instanceId: this.instanceId, + }; + + const isAudio = received?.message?.audioMessage; + + if (this.configService.get('OPENAI').ENABLED && isAudio) { + const openAiDefaultSettings = await this.prismaRepository.openaiSetting.findFirst({ + where: { + instanceId: this.instanceId, + }, + include: { + OpenaiCreds: true, + }, + }); + + if ( + openAiDefaultSettings && + openAiDefaultSettings.openaiCredsId && + openAiDefaultSettings.speechToText && + received?.message?.audioMessage + ) { + messageRaw.message.speechToText = await this.openaiService.speechToText( + openAiDefaultSettings.OpenaiCreds, + received, + this.client.updateMediaMessage, + ); + } + } + + this.logger.log(messageRaw); + + this.sendDataWebhook(Events.MESSAGES_UPSERT, messageRaw); + + await chatbotController.emit({ + instance: { instanceName: this.instance.name, instanceId: this.instanceId }, + remoteJid: messageRaw.key.remoteJid, + msg: messageRaw, + pushName: messageRaw.pushName, + }); + + if (this.configService.get('CHATWOOT').ENABLED && this.localChatwoot?.enabled) { + const chatwootSentMessage = await this.chatwootService.eventWhatsapp( + Events.MESSAGES_UPSERT, + { instanceName: this.instance.name, instanceId: this.instanceId }, + messageRaw, + ); + + if (chatwootSentMessage?.id) { + messageRaw.chatwootMessageId = chatwootSentMessage.id; + messageRaw.chatwootInboxId = chatwootSentMessage.id; + messageRaw.chatwootConversationId = chatwootSentMessage.id; + } + } + + await this.prismaRepository.message.create({ + data: messageRaw, + }); + + await this.updateContact({ + remoteJid: messageRaw.key.remoteJid, + pushName: messageRaw.pushName, + profilePicUrl: received.profilePicUrl, + }); + } + } catch (error) { + this.logger.error(error); + } + } + + private async updateContact(data: { remoteJid: string; pushName?: string; profilePicUrl?: string }) { + const contactRaw: any = { + remoteJid: data.remoteJid, + pushName: data?.pushName, + instanceId: this.instanceId, + profilePicUrl: data?.profilePicUrl, + }; + + const existingContact = await this.prismaRepository.contact.findFirst({ + where: { + remoteJid: data.remoteJid, + instanceId: this.instanceId, + }, + }); + + if (existingContact) { + await this.prismaRepository.contact.updateMany({ + where: { + remoteJid: data.remoteJid, + instanceId: this.instanceId, + }, + data: contactRaw, + }); + } else { + await this.prismaRepository.contact.create({ + data: contactRaw, + }); + } + + this.sendDataWebhook(Events.CONTACTS_UPSERT, contactRaw); + + if (this.configService.get('CHATWOOT').ENABLED && this.localChatwoot?.enabled) { + await this.chatwootService.eventWhatsapp( + Events.CONTACTS_UPDATE, + { + instanceName: this.instance.name, + instanceId: this.instanceId, + integration: this.instance.integration, + }, + contactRaw, + ); + } + + const chat = await this.prismaRepository.chat.findFirst({ + where: { instanceId: this.instanceId, remoteJid: data.remoteJid }, + }); + + if (chat) { + const chatRaw: any = { + remoteJid: data.remoteJid, + instanceId: this.instanceId, + }; + + this.sendDataWebhook(Events.CHATS_UPDATE, chatRaw); + + await this.prismaRepository.chat.updateMany({ + where: { remoteJid: chat.remoteJid }, + data: chatRaw, + }); + } + + const chatRaw: any = { + remoteJid: data.remoteJid, + instanceId: this.instanceId, + }; + + this.sendDataWebhook(Events.CHATS_UPSERT, chatRaw); + + await this.prismaRepository.chat.create({ + data: chatRaw, + }); + } + + protected async sendMessageWithTyping( + number: string, + message: any, + options?: Options, + file?: any, + isIntegration = false, + ) { + try { + let quoted: any; + let webhookUrl: any; + + if (options?.quoted) { + const m = options?.quoted; + + const msg = m?.key; + + if (!msg) { + throw 'Message not found'; + } + + quoted = msg; + } + + if (options.delay) { + await new Promise((resolve) => setTimeout(resolve, options.delay)); + } + + if (options?.webhookUrl) { + webhookUrl = options.webhookUrl; + } + + let audioFile; + + const messageId = v4(); + + let messageRaw: any; + + if (message?.mediaType === 'image') { + messageRaw = { + key: { fromMe: true, id: messageId, remoteJid: number }, + message: { + base64: isBase64(message.media) ? message.media : undefined, + mediaUrl: isURL(message.media) ? message.media : undefined, + quoted, + }, + messageType: 'imageMessage', + messageTimestamp: Math.round(new Date().getTime() / 1000), + webhookUrl, + source: 'unknown', + instanceId: this.instanceId, + }; + } else if (message?.mediaType === 'video') { + messageRaw = { + key: { fromMe: true, id: messageId, remoteJid: number }, + message: { + base64: isBase64(message.media) ? message.media : undefined, + mediaUrl: isURL(message.media) ? message.media : undefined, + quoted, + }, + messageType: 'videoMessage', + messageTimestamp: Math.round(new Date().getTime() / 1000), + webhookUrl, + source: 'unknown', + instanceId: this.instanceId, + }; + } else if (message?.mediaType === 'audio') { + messageRaw = { + key: { fromMe: true, id: messageId, remoteJid: number }, + message: { + base64: isBase64(message.media) ? message.media : undefined, + mediaUrl: isURL(message.media) ? message.media : undefined, + quoted, + }, + messageType: 'audioMessage', + messageTimestamp: Math.round(new Date().getTime() / 1000), + webhookUrl, + source: 'unknown', + instanceId: this.instanceId, + }; + + const buffer = Buffer.from(message.media, 'base64'); + audioFile = { + buffer, + mimetype: 'audio/mp4', + originalname: `${messageId}.mp4`, + }; + } else if (message?.mediaType === 'document') { + messageRaw = { + key: { fromMe: true, id: messageId, remoteJid: number }, + message: { + base64: isBase64(message.media) ? message.media : undefined, + mediaUrl: isURL(message.media) ? message.media : undefined, + quoted, + }, + messageType: 'documentMessage', + messageTimestamp: Math.round(new Date().getTime() / 1000), + webhookUrl, + source: 'unknown', + instanceId: this.instanceId, + }; + } else if (message.buttonMessage) { + messageRaw = { + key: { fromMe: true, id: messageId, remoteJid: number }, + message: { + ...message.buttonMessage, + buttons: message.buttonMessage.buttons, + footer: message.buttonMessage.footer, + body: message.buttonMessage.body, + quoted, + }, + messageType: 'buttonMessage', + messageTimestamp: Math.round(new Date().getTime() / 1000), + webhookUrl, + source: 'unknown', + instanceId: this.instanceId, + }; + } else if (message.listMessage) { + messageRaw = { + key: { fromMe: true, id: messageId, remoteJid: number }, + message: { + ...message.listMessage, + quoted, + }, + messageType: 'listMessage', + messageTimestamp: Math.round(new Date().getTime() / 1000), + webhookUrl, + source: 'unknown', + instanceId: this.instanceId, + }; + } else { + messageRaw = { + key: { fromMe: true, id: messageId, remoteJid: number }, + message: { + ...message, + quoted, + }, + messageType: 'conversation', + messageTimestamp: Math.round(new Date().getTime() / 1000), + webhookUrl, + source: 'unknown', + instanceId: this.instanceId, + }; + } + + if (messageRaw.message.contextInfo) { + messageRaw.contextInfo = { + ...messageRaw.message.contextInfo, + }; + } + + if (messageRaw.contextInfo?.stanzaId) { + const key: any = { + id: messageRaw.contextInfo.stanzaId, + }; + + const findMessage = await this.prismaRepository.message.findFirst({ + where: { + instanceId: this.instanceId, + key, + }, + }); + + if (findMessage) { + messageRaw.contextInfo.quotedMessage = findMessage.message; + } + } + + const base64 = messageRaw.message.base64; + delete messageRaw.message.base64; + + if (base64 || file || audioFile) { + if (this.configService.get('S3').ENABLE) { + try { + const fileBuffer = audioFile?.buffer || file?.buffer; + const buffer = base64 ? Buffer.from(base64, 'base64') : fileBuffer; + + let mediaType: string; + let mimetype = audioFile?.mimetype || file.mimetype; + + if (messageRaw.messageType === 'documentMessage') { + mediaType = 'document'; + mimetype = !mimetype ? 'application/pdf' : mimetype; + } else if (messageRaw.messageType === 'imageMessage') { + mediaType = 'image'; + mimetype = !mimetype ? 'image/png' : mimetype; + } else if (messageRaw.messageType === 'audioMessage') { + mediaType = 'audio'; + mimetype = !mimetype ? 'audio/mp4' : mimetype; + } else if (messageRaw.messageType === 'videoMessage') { + mediaType = 'video'; + mimetype = !mimetype ? 'video/mp4' : mimetype; + } + + const fileName = `${messageRaw.key.id}.${mimetype.split('/')[1]}`; + + const size = buffer.byteLength; + + const fullName = join(`${this.instance.id}`, messageRaw.key.remoteJid, mediaType, fileName); + + await s3Service.uploadFile(fullName, buffer, size, { + 'Content-Type': mimetype, + }); + + const mediaUrl = await s3Service.getObjectUrl(fullName); + + messageRaw.message.mediaUrl = mediaUrl; + } catch (error) { + this.logger.error(['Error on upload file to minio', error?.message, error?.stack]); + } + } + } + + this.logger.log(messageRaw); + + this.sendDataWebhook(Events.SEND_MESSAGE, messageRaw); + + if (this.configService.get('CHATWOOT').ENABLED && this.localChatwoot?.enabled && !isIntegration) { + this.chatwootService.eventWhatsapp( + Events.SEND_MESSAGE, + { instanceName: this.instance.name, instanceId: this.instanceId }, + messageRaw, + ); + } + + if (this.configService.get('CHATWOOT').ENABLED && this.localChatwoot?.enabled && isIntegration) + await chatbotController.emit({ + instance: { instanceName: this.instance.name, instanceId: this.instanceId }, + remoteJid: messageRaw.key.remoteJid, + msg: messageRaw, + pushName: messageRaw.pushName, + }); + + await this.prismaRepository.message.create({ + data: messageRaw, + }); + + return messageRaw; + } catch (error) { + this.logger.error(error); + throw new BadRequestException(error.toString()); + } + } + + public async textMessage(data: SendTextDto, isIntegration = false) { + const res = await this.sendMessageWithTyping( + data.number, + { + conversation: data.text, + }, + { + delay: data?.delay, + presence: 'composing', + quoted: data?.quoted, + linkPreview: data?.linkPreview, + mentionsEveryOne: data?.mentionsEveryOne, + mentioned: data?.mentioned, + }, + null, + isIntegration, + ); + return res; + } + + protected async prepareMediaMessage(mediaMessage: MediaMessage) { + try { + if (mediaMessage.mediatype === 'document' && !mediaMessage.fileName) { + const regex = new RegExp(/.*\/(.+?)\./); + const arrayMatch = regex.exec(mediaMessage.media); + mediaMessage.fileName = arrayMatch[1]; + } + + if (mediaMessage.mediatype === 'image' && !mediaMessage.fileName) { + mediaMessage.fileName = 'image.png'; + } + + if (mediaMessage.mediatype === 'video' && !mediaMessage.fileName) { + mediaMessage.fileName = 'video.mp4'; + } + + let mimetype: string | false; + + const prepareMedia: any = { + caption: mediaMessage?.caption, + fileName: mediaMessage.fileName, + mediaType: mediaMessage.mediatype, + media: mediaMessage.media, + gifPlayback: false, + }; + + if (isURL(mediaMessage.media)) { + mimetype = mimeTypes.lookup(mediaMessage.media); + } else { + mimetype = mimeTypes.lookup(mediaMessage.fileName); + } + + prepareMedia.mimetype = mimetype; + + return prepareMedia; + } catch (error) { + this.logger.error(error); + throw new InternalServerErrorException(error?.toString() || error); + } + } + + public async mediaMessage(data: SendMediaDto, file?: any, isIntegration = false) { + const mediaData: SendMediaDto = { ...data }; + + if (file) mediaData.media = file.buffer.toString('base64'); + + const message = await this.prepareMediaMessage(mediaData); + + const mediaSent = await this.sendMessageWithTyping( + data.number, + { ...message }, + { + delay: data?.delay, + presence: 'composing', + quoted: data?.quoted, + linkPreview: data?.linkPreview, + mentionsEveryOne: data?.mentionsEveryOne, + mentioned: data?.mentioned, + }, + file, + isIntegration, + ); + + return mediaSent; + } + + public async processAudio(audio: string, number: string, file: any) { + number = number.replace(/\D/g, ''); + const hash = `${number}-${new Date().getTime()}`; + + if (process.env.API_AUDIO_CONVERTER) { + try { + this.logger.verbose('Using audio converter API'); + const formData = new FormData(); + + if (file) { + formData.append('file', file.buffer, { + filename: file.originalname, + contentType: file.mimetype, + }); + } else if (isURL(audio)) { + formData.append('url', audio); + } else { + formData.append('base64', audio); + } + + formData.append('format', 'mp4'); + + const response = await axios.post(process.env.API_AUDIO_CONVERTER, formData, { + headers: { + ...formData.getHeaders(), + apikey: process.env.API_AUDIO_CONVERTER_KEY, + }, + }); + + if (!response?.data?.audio) { + throw new InternalServerErrorException('Failed to convert audio'); + } + + const prepareMedia: any = { + fileName: `${hash}.mp4`, + mediaType: 'audio', + media: response?.data?.audio, + mimetype: 'audio/mpeg', + }; + + return prepareMedia; + } catch (error) { + this.logger.error(error?.response?.data || error); + throw new InternalServerErrorException(error?.response?.data?.message || error?.toString() || error); + } + } else { + let mimetype: string; + + const prepareMedia: any = { + fileName: `${hash}.mp3`, + mediaType: 'audio', + media: audio, + mimetype: 'audio/mpeg', + }; + + if (isURL(audio)) { + mimetype = mimeTypes.lookup(audio).toString(); + } else { + mimetype = mimeTypes.lookup(prepareMedia.fileName).toString(); + } + + prepareMedia.mimetype = mimetype; + + return prepareMedia; + } + } + + public async audioWhatsapp(data: SendAudioDto, file?: any, isIntegration = false) { + const mediaData: SendAudioDto = { ...data }; + + if (file?.buffer) { + mediaData.audio = file.buffer.toString('base64'); + } else { + console.error('El archivo o buffer no est� definido correctamente.'); + throw new Error('File or buffer is undefined.'); + } + + const message = await this.processAudio(mediaData.audio, data.number, file); + + const audioSent = await this.sendMessageWithTyping( + data.number, + { ...message }, + { + delay: data?.delay, + presence: 'composing', + quoted: data?.quoted, + linkPreview: data?.linkPreview, + mentionsEveryOne: data?.mentionsEveryOne, + mentioned: data?.mentioned, + }, + file, + isIntegration, + ); + + return audioSent; + } + + public async buttonMessage(data: SendButtonsDto, isIntegration = false) { + return await this.sendMessageWithTyping( + data.number, + { + buttonMessage: { + title: data.title, + description: data.description, + footer: data.footer, + buttons: data.buttons, + }, + }, + { + delay: data?.delay, + presence: 'composing', + quoted: data?.quoted, + mentionsEveryOne: data?.mentionsEveryOne, + mentioned: data?.mentioned, + }, + null, + isIntegration, + ); + } + public async locationMessage() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async listMessage() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async templateMessage() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async contactMessage() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async reactionMessage() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async getBase64FromMediaMessage() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async deleteMessage() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async mediaSticker() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async pollMessage() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async statusMessage() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async reloadConnection() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async whatsappNumber() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async markMessageAsRead() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async archiveChat() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async markChatUnread() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async fetchProfile() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async offerCall() { + throw new BadRequestException('Method not available on WhatsApp Business API'); + } + public async sendPresence() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async setPresence() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async fetchPrivacySettings() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async updatePrivacySettings() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async fetchBusinessProfile() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async updateProfileName() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async updateProfileStatus() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async updateProfilePicture() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async removeProfilePicture() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async blockUser() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async updateMessage() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async createGroup() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async updateGroupPicture() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async updateGroupSubject() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async updateGroupDescription() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async findGroup() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async fetchAllGroups() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async inviteCode() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async inviteInfo() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async sendInvite() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async acceptInviteCode() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async revokeInviteCode() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async findParticipants() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async updateGParticipant() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async updateGSetting() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async toggleEphemeral() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async leaveGroup() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async fetchLabels() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async handleLabel() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async receiveMobileCode() { + throw new BadRequestException('Method not available on Evolution Channel'); + } + public async fakeCall() { + throw new BadRequestException('Method not available on Evolution Channel'); + } +} diff --git a/src/api/integrations/channel/evolution/evolution.controller.ts b/src/api/integrations/channel/evolution/evolution.controller.ts new file mode 100644 index 00000000..c9f36585 --- /dev/null +++ b/src/api/integrations/channel/evolution/evolution.controller.ts @@ -0,0 +1,39 @@ +import { PrismaRepository } from '@api/repository/repository.service'; +import { WAMonitoringService } from '@api/services/monitor.service'; +import { Logger } from '@config/logger.config'; + +import { ChannelController, ChannelControllerInterface } from '../channel.controller'; + +export class EvolutionController extends ChannelController implements ChannelControllerInterface { + private readonly logger = new Logger('EvolutionController'); + + constructor(prismaRepository: PrismaRepository, waMonitor: WAMonitoringService) { + super(prismaRepository, waMonitor); + } + + integrationEnabled: boolean; + + public async receiveWebhook(data: any) { + const numberId = data.numberId; + + if (!numberId) { + this.logger.error('WebhookService -> receiveWebhookEvolution -> numberId not found'); + return; + } + + const instance = await this.prismaRepository.instance.findFirst({ + where: { number: numberId }, + }); + + if (!instance) { + this.logger.error('WebhookService -> receiveWebhook -> instance not found'); + return; + } + + await this.waMonitor.waInstances[instance.name].connectToWhatsapp(data); + + return { + status: 'success', + }; + } +} diff --git a/src/api/integrations/channel/evolution/evolution.router.ts b/src/api/integrations/channel/evolution/evolution.router.ts new file mode 100644 index 00000000..1ab0ec00 --- /dev/null +++ b/src/api/integrations/channel/evolution/evolution.router.ts @@ -0,0 +1,18 @@ +import { RouterBroker } from '@api/abstract/abstract.router'; +import { evolutionController } from '@api/server.module'; +import { ConfigService } from '@config/env.config'; +import { Router } from 'express'; + +export class EvolutionRouter extends RouterBroker { + constructor(readonly configService: ConfigService) { + super(); + this.router.post(this.routerPath('webhook/evolution', false), async (req, res) => { + const { body } = req; + const response = await evolutionController.receiveWebhook(body); + + return res.status(200).json(response); + }); + } + + public readonly router: Router = Router(); +} diff --git a/src/api/integrations/channel/meta/meta.controller.ts b/src/api/integrations/channel/meta/meta.controller.ts new file mode 100644 index 00000000..558a22e9 --- /dev/null +++ b/src/api/integrations/channel/meta/meta.controller.ts @@ -0,0 +1,72 @@ +import { PrismaRepository } from '@api/repository/repository.service'; +import { WAMonitoringService } from '@api/services/monitor.service'; +import { Logger } from '@config/logger.config'; +import axios from 'axios'; + +import { ChannelController, ChannelControllerInterface } from '../channel.controller'; + +export class MetaController extends ChannelController implements ChannelControllerInterface { + private readonly logger = new Logger('MetaController'); + + constructor(prismaRepository: PrismaRepository, waMonitor: WAMonitoringService) { + super(prismaRepository, waMonitor); + } + + integrationEnabled: boolean; + + public async receiveWebhook(data: any) { + if (data.object === 'whatsapp_business_account') { + if (data.entry[0]?.changes[0]?.field === 'message_template_status_update') { + const template = await this.prismaRepository.template.findFirst({ + where: { templateId: `${data.entry[0].changes[0].value.message_template_id}` }, + }); + + if (!template) { + console.log('template not found'); + return; + } + + const { webhookUrl } = template; + + await axios.post(webhookUrl, data.entry[0].changes[0].value, { + headers: { + 'Content-Type': 'application/json', + }, + }); + return; + } + + data.entry?.forEach(async (entry: any) => { + const numberId = entry.changes[0].value.metadata.phone_number_id; + + if (!numberId) { + this.logger.error('WebhookService -> receiveWebhookMeta -> numberId not found'); + return { + status: 'success', + }; + } + + const instance = await this.prismaRepository.instance.findFirst({ + where: { number: numberId }, + }); + + if (!instance) { + this.logger.error('WebhookService -> receiveWebhookMeta -> instance not found'); + return { + status: 'success', + }; + } + + await this.waMonitor.waInstances[instance.name].connectToWhatsapp(data); + + return { + status: 'success', + }; + }); + } + + return { + status: 'success', + }; + } +} diff --git a/src/api/integrations/channel/meta/meta.router.ts b/src/api/integrations/channel/meta/meta.router.ts new file mode 100644 index 00000000..b0fc43ce --- /dev/null +++ b/src/api/integrations/channel/meta/meta.router.ts @@ -0,0 +1,24 @@ +import { RouterBroker } from '@api/abstract/abstract.router'; +import { metaController } from '@api/server.module'; +import { ConfigService, WaBusiness } from '@config/env.config'; +import { Router } from 'express'; + +export class MetaRouter extends RouterBroker { + constructor(readonly configService: ConfigService) { + super(); + this.router + .get(this.routerPath('webhook/meta', false), async (req, res) => { + if (req.query['hub.verify_token'] === configService.get('WA_BUSINESS').TOKEN_WEBHOOK) + res.send(req.query['hub.challenge']); + else res.send('Error, wrong validation token'); + }) + .post(this.routerPath('webhook/meta', false), async (req, res) => { + const { body } = req; + const response = await metaController.receiveWebhook(body); + + return res.status(200).json(response); + }); + } + + public readonly router: Router = Router(); +} diff --git a/src/api/services/channels/whatsapp.business.service.ts b/src/api/integrations/channel/meta/whatsapp.business.service.ts similarity index 61% rename from src/api/services/channels/whatsapp.business.service.ts rename to src/api/integrations/channel/meta/whatsapp.business.service.ts index 09ddd2a0..5360b9e4 100644 --- a/src/api/services/channels/whatsapp.business.service.ts +++ b/src/api/integrations/channel/meta/whatsapp.business.service.ts @@ -1,19 +1,10 @@ -import axios from 'axios'; -import { arrayUnique, isURL } from 'class-validator'; -import EventEmitter2 from 'eventemitter2'; -import FormData from 'form-data'; -import fs from 'fs/promises'; -import { getMIMEType } from 'node-mime-types'; - -import { ConfigService, Database, WaBusiness } from '../../../config/env.config'; -import { BadRequestException, InternalServerErrorException } from '../../../exceptions'; -import { NumberBusiness } from '../../dto/chat.dto'; +import { NumberBusiness } from '@api/dto/chat.dto'; import { ContactMessage, MediaMessage, Options, SendAudioDto, - SendButtonDto, + SendButtonsDto, SendContactDto, SendListDto, SendLocationDto, @@ -21,25 +12,37 @@ import { SendReactionDto, SendTemplateDto, SendTextDto, -} from '../../dto/sendMessage.dto'; -import { ContactRaw, MessageRaw, MessageUpdateRaw, SettingsRaw } from '../../models'; -import { RepositoryBroker } from '../../repository/repository.manager'; -import { Events, wa } from '../../types/wa.types'; -import { CacheService } from './../cache.service'; -import { ChannelStartupService } from './../channel.service'; +} from '@api/dto/sendMessage.dto'; +import * as s3Service from '@api/integrations/storage/s3/libs/minio.server'; +import { ProviderFiles } from '@api/provider/sessions'; +import { PrismaRepository } from '@api/repository/repository.service'; +import { chatbotController } from '@api/server.module'; +import { CacheService } from '@api/services/cache.service'; +import { ChannelStartupService } from '@api/services/channel.service'; +import { Events, wa } from '@api/types/wa.types'; +import { Chatwoot, ConfigService, Database, Openai, S3, WaBusiness } from '@config/env.config'; +import { BadRequestException, InternalServerErrorException } from '@exceptions'; +import { createJid } from '@utils/createJid'; +import { status } from '@utils/renderStatus'; +import axios from 'axios'; +import { arrayUnique, isURL } from 'class-validator'; +import EventEmitter2 from 'eventemitter2'; +import FormData from 'form-data'; +import { createReadStream } from 'fs'; +import mimeTypes from 'mime-types'; +import { join } from 'path'; export class BusinessStartupService extends ChannelStartupService { constructor( public readonly configService: ConfigService, public readonly eventEmitter: EventEmitter2, - public readonly repository: RepositoryBroker, + public readonly prismaRepository: PrismaRepository, public readonly cache: CacheService, public readonly chatwootCache: CacheService, - public readonly messagesLostCache: CacheService, + public readonly baileysCache: CacheService, + private readonly providerFiles: ProviderFiles, ) { - super(configService, eventEmitter, repository, chatwootCache); - this.logger.verbose('BusinessStartupService initialized'); - this.cleanStore(); + super(configService, eventEmitter, prismaRepository, chatwootCache); } public stateConnection: wa.StateConnection = { state: 'open' }; @@ -48,7 +51,6 @@ export class BusinessStartupService extends ChannelStartupService { public mobile: boolean; public get connectionStatus() { - this.logger.verbose('Getting connection status'); return this.stateConnection; } @@ -57,8 +59,6 @@ export class BusinessStartupService extends ChannelStartupService { } public get qrCode(): wa.QrCode { - this.logger.verbose('Getting qrcode'); - return { pairingCode: this.instance.qrcode?.pairingCode, code: this.instance.qrcode?.code, @@ -68,43 +68,33 @@ export class BusinessStartupService extends ChannelStartupService { } public async logoutInstance() { - this.logger.verbose('Logging out instance'); await this.closeClient(); } + private isMediaMessage(message: any) { + return message.document || message.image || message.audio || message.video; + } + private async post(message: any, params: string) { try { - const integration = await this.findIntegration(); - let urlServer = this.configService.get('WA_BUSINESS').URL; const version = this.configService.get('WA_BUSINESS').VERSION; - urlServer = `${urlServer}/${version}/${integration.number}/${params}`; - const headers = { 'Content-Type': 'application/json', Authorization: `Bearer ${integration.token}` }; + urlServer = `${urlServer}/${version}/${this.number}/${params}`; + const headers = { 'Content-Type': 'application/json', Authorization: `Bearer ${this.token}` }; const result = await axios.post(urlServer, message, { headers }); return result.data; } catch (e) { - this.logger.error(e); - return e.response.data; + return e.response?.data?.error; } } public async profilePicture(number: string) { - const jid = this.createJid(number); + const jid = createJid(number); - this.logger.verbose('Getting profile picture with jid: ' + jid); - try { - this.logger.verbose('Getting profile picture url'); - return { - wuid: jid, - profilePictureUrl: await this.client.profilePictureUrl(jid, 'image'), - }; - } catch (error) { - this.logger.verbose('Profile picture not found'); - return { - wuid: jid, - profilePictureUrl: null, - }; - } + return { + wuid: jid, + profilePictureUrl: null, + }; } public async getProfileName() { @@ -120,7 +110,6 @@ export class BusinessStartupService extends ChannelStartupService { } public async setWhatsappBusinessProfile(data: NumberBusiness): Promise { - this.logger.verbose('set profile'); const content = { messaging_product: 'whatsapp', about: data.about, @@ -136,27 +125,15 @@ export class BusinessStartupService extends ChannelStartupService { public async connectToWhatsapp(data?: any): Promise { if (!data) return; + const content = data.entry[0].changes[0].value; + try { - this.loadWebhook(); this.loadChatwoot(); - this.loadWebsocket(); - this.loadRabbitmq(); - this.loadSqs(); - this.loadTypebot(); - this.loadChamaai(); - - this.logger.verbose('Creating socket'); - - this.logger.verbose('Socket created'); this.eventHandler(content); - this.logger.verbose('Socket event handler initialized'); - - this.phoneNumber = this.createJid( - content.messages ? content.messages[0].from : content.statuses[0]?.recipient_id, - ); + this.phoneNumber = createJid(content.messages ? content.messages[0].from : content.statuses[0]?.recipient_id); } catch (error) { this.logger.error(error); throw new InternalServerErrorException(error?.toString()); @@ -165,13 +142,11 @@ export class BusinessStartupService extends ChannelStartupService { private async downloadMediaMessage(message: any) { try { - const integration = await this.findIntegration(); - const id = message[message.type].id; let urlServer = this.configService.get('WA_BUSINESS').URL; const version = this.configService.get('WA_BUSINESS').VERSION; urlServer = `${urlServer}/${version}/${id}`; - const headers = { 'Content-Type': 'application/json', Authorization: `Bearer ${integration.token}` }; + const headers = { 'Content-Type': 'application/json', Authorization: `Bearer ${this.token}` }; let result = await axios.get(urlServer, { headers }); result = await axios.get(result.data.url, { headers, responseType: 'arraybuffer' }); return result.data; @@ -195,6 +170,13 @@ export class BusinessStartupService extends ChannelStartupService { return content; } + private messageButtonJson(received: any) { + const message = received.messages[0]; + let content: any = { conversation: received.messages[0].button?.text }; + message.context ? (content = { ...content, contextInfo: { stanzaId: message.context.id } }) : content; + return content; + } + private messageReactionJson(received: any) { const message = received.messages[0]; let content: any = { @@ -229,7 +211,6 @@ export class BusinessStartupService extends ChannelStartupService { let content: any = {}; const vcard = (contact: any) => { - this.logger.verbose('Creating vcard'); let result = 'BEGIN:VCARD\n' + 'VERSION:3.0\n' + @@ -237,23 +218,19 @@ export class BusinessStartupService extends ChannelStartupService { `FN:${contact.name.formatted_name}\n`; if (contact.org) { - this.logger.verbose('Organization defined'); result += `ORG:${contact.org.company};\n`; } if (contact.emails) { - this.logger.verbose('Email defined'); result += `EMAIL:${contact.emails[0].email}\n`; } if (contact.urls) { - this.logger.verbose('Url defined'); result += `URL:${contact.urls[0].url}\n`; } if (!contact.phones[0]?.wa_id) { - this.logger.verbose('Wuid defined'); - contact.phones[0].wa_id = this.createJid(contact.phones[0].phone); + contact.phones[0].wa_id = createJid(contact.phones[0].phone); } result += @@ -261,7 +238,6 @@ export class BusinessStartupService extends ChannelStartupService { 'item1.X-ABLabel:Celular\n' + 'END:VCARD'; - this.logger.verbose('Vcard created'); return result; }; @@ -315,9 +291,9 @@ export class BusinessStartupService extends ChannelStartupService { return messageType; } - protected async messageHandle(received: any, database: Database, settings: SettingsRaw) { + protected async messageHandle(received: any, database: Database, settings: any) { try { - let messageRaw: MessageRaw; + let messageRaw: any; let pushName: any; if (received.contacts) pushName = received.contacts[0].profile.name; @@ -328,25 +304,88 @@ export class BusinessStartupService extends ChannelStartupService { remoteJid: this.phoneNumber, fromMe: received.messages[0].from === received.metadata.phone_number_id, }; - if ( - received?.messages[0].document || - received?.messages[0].image || - received?.messages[0].audio || - received?.messages[0].video - ) { - const buffer = await this.downloadMediaMessage(received?.messages[0]); + if (this.isMediaMessage(received?.messages[0])) { messageRaw = { key, pushName, - message: { - ...this.messageMediaJson(received), - base64: buffer ? buffer.toString('base64') : undefined, - }, + message: this.messageMediaJson(received), + contextInfo: this.messageMediaJson(received)?.contextInfo, messageType: this.renderMessageType(received.messages[0].type), - messageTimestamp: received.messages[0].timestamp as number, - owner: this.instance.name, - // source: getDevice(received.key.id), + messageTimestamp: parseInt(received.messages[0].timestamp) as number, + source: 'unknown', + instanceId: this.instanceId, }; + + if (this.configService.get('S3').ENABLE) { + try { + const message: any = received; + + const id = message.messages[0][message.messages[0].type].id; + let urlServer = this.configService.get('WA_BUSINESS').URL; + const version = this.configService.get('WA_BUSINESS').VERSION; + urlServer = `${urlServer}/${version}/${id}`; + const headers = { 'Content-Type': 'application/json', Authorization: `Bearer ${this.token}` }; + const result = await axios.get(urlServer, { headers }); + + const buffer = await axios.get(result.data.url, { headers, responseType: 'arraybuffer' }); + + let mediaType; + + if (message.messages[0].document) { + mediaType = 'document'; + } else if (message.messages[0].image) { + mediaType = 'image'; + } else if (message.messages[0].audio) { + mediaType = 'audio'; + } else { + mediaType = 'video'; + } + + const mimetype = result.data?.mime_type || result.headers['content-type']; + + const contentDisposition = result.headers['content-disposition']; + let fileName = `${message.messages[0].id}.${mimetype.split('/')[1]}`; + if (contentDisposition) { + const match = contentDisposition.match(/filename="(.+?)"/); + if (match) { + fileName = match[1]; + } + } + + const size = result.headers['content-length'] || buffer.data.byteLength; + + const fullName = join(`${this.instance.id}`, key.remoteJid, mediaType, fileName); + + await s3Service.uploadFile(fullName, buffer.data, size, { + 'Content-Type': mimetype, + }); + + const createdMessage = await this.prismaRepository.message.create({ + data: messageRaw, + }); + + await this.prismaRepository.media.create({ + data: { + messageId: createdMessage.id, + instanceId: this.instanceId, + type: mediaType, + fileName: fullName, + mimetype, + }, + }); + + const mediaUrl = await s3Service.getObjectUrl(fullName); + + messageRaw.message.mediaUrl = mediaUrl; + messageRaw.message.base64 = buffer.data.toString('base64'); + } catch (error) { + this.logger.error(['Error on upload file to minio', error?.message, error?.stack]); + } + } else { + const buffer = await this.downloadMediaMessage(received?.messages[0]); + + messageRaw.message.base64 = buffer.toString('base64'); + } } else if (received?.messages[0].interactive) { messageRaw = { key, @@ -354,10 +393,24 @@ export class BusinessStartupService extends ChannelStartupService { message: { ...this.messageInteractiveJson(received), }, - messageType: 'conversation', - messageTimestamp: received.messages[0].timestamp as number, - owner: this.instance.name, - // source: getDevice(received.key.id), + contextInfo: this.messageInteractiveJson(received)?.contextInfo, + messageType: 'interactiveMessage', + messageTimestamp: parseInt(received.messages[0].timestamp) as number, + source: 'unknown', + instanceId: this.instanceId, + }; + } else if (received?.messages[0].button) { + messageRaw = { + key, + pushName, + message: { + ...this.messageButtonJson(received), + }, + contextInfo: this.messageButtonJson(received)?.contextInfo, + messageType: 'buttonMessage', + messageTimestamp: parseInt(received.messages[0].timestamp) as number, + source: 'unknown', + instanceId: this.instanceId, }; } else if (received?.messages[0].reaction) { messageRaw = { @@ -366,10 +419,11 @@ export class BusinessStartupService extends ChannelStartupService { message: { ...this.messageReactionJson(received), }, + contextInfo: this.messageReactionJson(received)?.contextInfo, messageType: 'reactionMessage', - messageTimestamp: received.messages[0].timestamp as number, - owner: this.instance.name, - // source: getDevice(received.key.id), + messageTimestamp: parseInt(received.messages[0].timestamp) as number, + source: 'unknown', + instanceId: this.instanceId, }; } else if (received?.messages[0].contacts) { messageRaw = { @@ -378,130 +432,137 @@ export class BusinessStartupService extends ChannelStartupService { message: { ...this.messageContactsJson(received), }, - messageType: 'conversation', - messageTimestamp: received.messages[0].timestamp as number, - owner: this.instance.name, - // source: getDevice(received.key.id), + contextInfo: this.messageContactsJson(received)?.contextInfo, + messageType: 'contactMessage', + messageTimestamp: parseInt(received.messages[0].timestamp) as number, + source: 'unknown', + instanceId: this.instanceId, }; } else { messageRaw = { key, pushName, message: this.messageTextJson(received), + contextInfo: this.messageTextJson(received)?.contextInfo, messageType: this.renderMessageType(received.messages[0].type), - messageTimestamp: received.messages[0].timestamp as number, - owner: this.instance.name, - //source: getDevice(received.key.id), + messageTimestamp: parseInt(received.messages[0].timestamp) as number, + source: 'unknown', + instanceId: this.instanceId, }; } - if (this.localSettings.read_messages && received.key.id !== 'status@broadcast') { + if (this.localSettings.readMessages) { // await this.client.readMessages([received.key]); } - if (this.localSettings.read_status && received.key.id === 'status@broadcast') { - // await this.client.readMessages([received.key]); + if (this.configService.get('OPENAI').ENABLED) { + const openAiDefaultSettings = await this.prismaRepository.openaiSetting.findFirst({ + where: { + instanceId: this.instanceId, + }, + include: { + OpenaiCreds: true, + }, + }); + + const audioMessage = received?.messages[0]?.audio; + + if ( + openAiDefaultSettings && + openAiDefaultSettings.openaiCredsId && + openAiDefaultSettings.speechToText && + audioMessage + ) { + messageRaw.message.speechToText = await this.openaiService.speechToText( + openAiDefaultSettings.OpenaiCreds, + { + message: { + mediaUrl: messageRaw.message.mediaUrl, + ...messageRaw, + }, + }, + () => {}, + ); + } } this.logger.log(messageRaw); - this.logger.verbose('Sending data to webhook in event MESSAGES_UPSERT'); - this.sendDataWebhook(Events.MESSAGES_UPSERT, messageRaw); - if (this.localChatwoot.enabled) { + await chatbotController.emit({ + instance: { instanceName: this.instance.name, instanceId: this.instanceId }, + remoteJid: messageRaw.key.remoteJid, + msg: messageRaw, + pushName: messageRaw.pushName, + }); + + if (this.configService.get('CHATWOOT').ENABLED && this.localChatwoot?.enabled) { const chatwootSentMessage = await this.chatwootService.eventWhatsapp( Events.MESSAGES_UPSERT, - { instanceName: this.instance.name }, + { instanceName: this.instance.name, instanceId: this.instanceId }, messageRaw, ); if (chatwootSentMessage?.id) { - messageRaw.chatwoot = { - messageId: chatwootSentMessage.id, - inboxId: chatwootSentMessage.inbox_id, - conversationId: chatwootSentMessage.conversation_id, - }; + messageRaw.chatwootMessageId = chatwootSentMessage.id; + messageRaw.chatwootInboxId = chatwootSentMessage.id; + messageRaw.chatwootConversationId = chatwootSentMessage.id; } } - const typebotSessionRemoteJid = this.localTypebot.sessions?.find( - (session) => session.remoteJid === key.remoteJid, - ); - - if (this.localTypebot.enabled || typebotSessionRemoteJid) { - if (!(this.localTypebot.listening_from_me === false && key.fromMe === true)) { - if (messageRaw.messageType !== 'reactionMessage') - await this.typebotService.sendTypebot( - { instanceName: this.instance.name }, - messageRaw.key.remoteJid, - messageRaw, - ); - } + if (!this.isMediaMessage(received?.messages[0])) { + await this.prismaRepository.message.create({ + data: messageRaw, + }); } - if (this.localChamaai.enabled && messageRaw.key.fromMe === false && received?.message.type === 'notify') { - await this.chamaaiService.sendChamaai( - { instanceName: this.instance.name }, - messageRaw.key.remoteJid, - messageRaw, - ); - } - - this.logger.verbose('Inserting message in database'); - await this.repository.message.insert([messageRaw], this.instance.name, database.SAVE_DATA.NEW_MESSAGE); - - this.logger.verbose('Verifying contact from message'); - const contact = await this.repository.contact.find({ - where: { owner: this.instance.name, id: key.remoteJid }, + const contact = await this.prismaRepository.contact.findFirst({ + where: { instanceId: this.instanceId, remoteJid: key.remoteJid }, }); - const contactRaw: ContactRaw = { - id: received.contacts[0].profile.phone, + const contactRaw: any = { + remoteJid: received.contacts[0].profile.phone, pushName, - //profilePictureUrl: (await this.profilePicture(received.key.remoteJid)).profilePictureUrl, - owner: this.instance.name, + // profilePicUrl: '', + instanceId: this.instanceId, }; - if (contactRaw.id === 'status@broadcast') { - this.logger.verbose('Contact is status@broadcast'); + if (contactRaw.remoteJid === 'status@broadcast') { return; } - if (contact?.length) { - this.logger.verbose('Contact found in database'); - const contactRaw: ContactRaw = { - id: received.contacts[0].profile.phone, + if (contact) { + const contactRaw: any = { + remoteJid: received.contacts[0].profile.phone, pushName, - //profilePictureUrl: (await this.profilePicture(received.key.remoteJid)).profilePictureUrl, - owner: this.instance.name, + // profilePicUrl: '', + instanceId: this.instanceId, }; - this.logger.verbose('Sending data to webhook in event CONTACTS_UPDATE'); this.sendDataWebhook(Events.CONTACTS_UPDATE, contactRaw); - if (this.localChatwoot.enabled) { + if (this.configService.get('CHATWOOT').ENABLED && this.localChatwoot?.enabled) { await this.chatwootService.eventWhatsapp( Events.CONTACTS_UPDATE, - { instanceName: this.instance.name }, + { instanceName: this.instance.name, instanceId: this.instanceId }, contactRaw, ); } - this.logger.verbose('Updating contact in database'); - await this.repository.contact.update([contactRaw], this.instance.name, database.SAVE_DATA.CONTACTS); + await this.prismaRepository.contact.updateMany({ + where: { remoteJid: contact.remoteJid }, + data: contactRaw, + }); return; } - this.logger.verbose('Contact not found in database'); - - this.logger.verbose('Sending data to webhook in event CONTACTS_UPSERT'); this.sendDataWebhook(Events.CONTACTS_UPSERT, contactRaw); - this.logger.verbose('Inserting contact in database'); - this.repository.contact.insert([contactRaw], this.instance.name, database.SAVE_DATA.CONTACTS); + this.prismaRepository.contact.create({ + data: contactRaw, + }); } - this.logger.verbose('Event received: messages.update'); if (received.statuses) { for await (const item of received.statuses) { const key = { @@ -510,40 +571,44 @@ export class BusinessStartupService extends ChannelStartupService { fromMe: this.phoneNumber === received.metadata.phone_number_id, }; if (settings?.groups_ignore && key.remoteJid.includes('@g.us')) { - this.logger.verbose('group ignored'); return; } if (key.remoteJid !== 'status@broadcast' && !key?.remoteJid?.match(/(:\d+)/)) { - this.logger.verbose('Message update is valid'); + const findMessage = await this.prismaRepository.message.findFirst({ + where: { + instanceId: this.instanceId, + key: { + path: ['id'], + equals: key.id, + }, + }, + }); - if (item.status === 'read' && !key.fromMe) return; + if (!findMessage) { + return; + } if (item.message === null && item.status === undefined) { - this.logger.verbose('Message deleted'); - - this.logger.verbose('Sending data to webhook in event MESSAGE_DELETE'); this.sendDataWebhook(Events.MESSAGES_DELETE, key); - const message: MessageUpdateRaw = { - ...key, + const message: any = { + messageId: findMessage.id, + keyId: key.id, + remoteJid: key.remoteJid, + fromMe: key.fromMe, + participant: key?.remoteJid, status: 'DELETED', - datetime: Date.now(), - owner: this.instance.name, + instanceId: this.instanceId, }; - this.logger.verbose(message); + await this.prismaRepository.messageUpdate.create({ + data: message, + }); - this.logger.verbose('Inserting message in database'); - await this.repository.messageUpdate.insert( - [message], - this.instance.name, - database.SAVE_DATA.MESSAGE_UPDATE, - ); - - if (this.localChatwoot.enabled) { + if (this.configService.get('CHATWOOT').ENABLED && this.localChatwoot?.enabled) { this.chatwootService.eventWhatsapp( Events.MESSAGES_DELETE, - { instanceName: this.instance.name }, + { instanceName: this.instance.name, instanceId: this.instanceId }, { key: key }, ); } @@ -551,20 +616,25 @@ export class BusinessStartupService extends ChannelStartupService { return; } - const message: MessageUpdateRaw = { - ...key, + const message: any = { + messageId: findMessage.id, + keyId: key.id, + remoteJid: key.remoteJid, + fromMe: key.fromMe, + participant: key?.remoteJid, status: item.status.toUpperCase(), - datetime: Date.now(), - owner: this.instance.name, + instanceId: this.instanceId, }; - this.logger.verbose(message); - - this.logger.verbose('Sending data to webhook in event MESSAGES_UPDATE'); this.sendDataWebhook(Events.MESSAGES_UPDATE, message); - this.logger.verbose('Inserting message in database'); - this.repository.messageUpdate.insert([message], this.instance.name, database.SAVE_DATA.MESSAGE_UPDATE); + await this.prismaRepository.messageUpdate.create({ + data: message, + }); + + if (findMessage.webhookUrl) { + await axios.post(findMessage.webhookUrl, message); + } } } } @@ -639,21 +709,21 @@ export class BusinessStartupService extends ChannelStartupService { documentMessage: message, }; } + + return message; } protected async eventHandler(content: any) { - this.logger.verbose('Initializing event handler'); const database = this.configService.get('DATABASE'); const settings = await this.findSettings(); - this.logger.verbose('Listening event: messages.statuses'); this.messageHandle(content, database, settings); } - protected async sendMessageWithTyping(number: string, message: any, options?: Options, isChatwoot = false) { - this.logger.verbose('Sending message with typing'); + protected async sendMessageWithTyping(number: string, message: any, options?: Options, isIntegration = false) { try { let quoted: any; + let webhookUrl: any; const linkPreview = options?.linkPreview != false ? undefined : false; if (options?.quoted) { const m = options?.quoted; @@ -665,13 +735,14 @@ export class BusinessStartupService extends ChannelStartupService { } quoted = msg; - this.logger.verbose('Quoted message'); + } + if (options?.webhookUrl) { + webhookUrl = options.webhookUrl; } let content: any; const messageSent = await (async () => { if (message['reactionMessage']) { - this.logger.verbose('Sending reaction'); content = { messaging_product: 'whatsapp', recipient_type: 'individual', @@ -686,7 +757,6 @@ export class BusinessStartupService extends ChannelStartupService { return await this.post(content, 'messages'); } if (message['locationMessage']) { - this.logger.verbose('Sending message'); content = { messaging_product: 'whatsapp', recipient_type: 'individual', @@ -703,7 +773,6 @@ export class BusinessStartupService extends ChannelStartupService { return await this.post(content, 'messages'); } if (message['contacts']) { - this.logger.verbose('Sending message'); content = { messaging_product: 'whatsapp', recipient_type: 'individual', @@ -716,7 +785,6 @@ export class BusinessStartupService extends ChannelStartupService { return await this.post(content, 'messages'); } if (message['conversation']) { - this.logger.verbose('Sending message'); content = { messaging_product: 'whatsapp', recipient_type: 'individual', @@ -731,7 +799,8 @@ export class BusinessStartupService extends ChannelStartupService { return await this.post(content, 'messages'); } if (message['media']) { - this.logger.verbose('Sending message'); + const isImage = message['mimetype']?.startsWith('image/'); + content = { messaging_product: 'whatsapp', recipient_type: 'individual', @@ -740,6 +809,7 @@ export class BusinessStartupService extends ChannelStartupService { [message['mediaType']]: { [message['type']]: message['id'], preview_url: linkPreview, + ...(message['fileName'] && !isImage && { filename: message['fileName'] }), caption: message['caption'], }, }; @@ -747,7 +817,6 @@ export class BusinessStartupService extends ChannelStartupService { return await this.post(content, 'messages'); } if (message['audio']) { - this.logger.verbose('Sending message'); content = { messaging_product: 'whatsapp', recipient_type: 'individual', @@ -761,7 +830,6 @@ export class BusinessStartupService extends ChannelStartupService { return await this.post(content, 'messages'); } if (message['buttons']) { - this.logger.verbose('Sending message'); content = { messaging_product: 'whatsapp', recipient_type: 'individual', @@ -785,8 +853,7 @@ export class BusinessStartupService extends ChannelStartupService { message = { conversation: `${message['text'] || 'Select'}\n` + formattedText }; return await this.post(content, 'messages'); } - if (message['sections']) { - this.logger.verbose('Sending message'); + if (message['listMessage']) { content = { messaging_product: 'whatsapp', recipient_type: 'individual', @@ -796,33 +863,32 @@ export class BusinessStartupService extends ChannelStartupService { type: 'list', header: { type: 'text', - text: message['title'], + text: message['listMessage']['title'], }, body: { - text: message['text'], + text: message['listMessage']['description'], }, footer: { - text: message['footerText'], + text: message['listMessage']['footerText'], }, action: { - button: message['buttonText'], - sections: message['sections'], + button: message['listMessage']['buttonText'], + sections: message['listMessage']['sections'], }, }, }; quoted ? (content.context = { message_id: quoted.id }) : content; let formattedText = ''; - for (const section of message['sections']) { + for (const section of message['listMessage']['sections']) { formattedText += `${section?.title}\n`; for (const row of section.rows) { formattedText += `${row?.title}\n`; } } - message = { conversation: `${message['title']}\n` + formattedText }; + message = { conversation: `${message['listMessage']['title']}\n` + formattedText }; return await this.post(content, 'messages'); } if (message['template']) { - this.logger.verbose('Sending message'); content = { messaging_product: 'whatsapp', recipient_type: 'individual', @@ -842,38 +908,45 @@ export class BusinessStartupService extends ChannelStartupService { } })(); - if (messageSent?.error?.message) { - this.logger.error(messageSent.error.message); - throw messageSent.error.message.toString(); + if (messageSent?.error_data) { + this.logger.error(messageSent); + return messageSent; } - console.log(content); - - const messageRaw: MessageRaw = { - key: { fromMe: true, id: messageSent?.messages[0]?.id, remoteJid: this.createJid(number) }, - //pushName: messageSent.pushName, + const messageRaw: any = { + key: { fromMe: true, id: messageSent?.messages[0]?.id, remoteJid: createJid(number) }, message: this.convertMessageToRaw(message, content), messageType: this.renderMessageType(content.type), messageTimestamp: (messageSent?.messages[0]?.timestamp as number) || Math.round(new Date().getTime() / 1000), - owner: this.instance.name, - //ource: getDevice(messageSent.key.id), + instanceId: this.instanceId, + webhookUrl, + status: status[1], + source: 'unknown', }; this.logger.log(messageRaw); - this.logger.verbose('Sending data to webhook in event SEND_MESSAGE'); this.sendDataWebhook(Events.SEND_MESSAGE, messageRaw); - if (this.localChatwoot.enabled && !isChatwoot) { - this.chatwootService.eventWhatsapp(Events.SEND_MESSAGE, { instanceName: this.instance.name }, messageRaw); + if (this.configService.get('CHATWOOT').ENABLED && this.localChatwoot?.enabled && !isIntegration) { + this.chatwootService.eventWhatsapp( + Events.SEND_MESSAGE, + { instanceName: this.instance.name, instanceId: this.instanceId }, + messageRaw, + ); } - this.logger.verbose('Inserting message in database'); - await this.repository.message.insert( - [messageRaw], - this.instance.name, - this.configService.get('DATABASE').SAVE_DATA.NEW_MESSAGE, - ); + if (this.configService.get('CHATWOOT').ENABLED && this.localChatwoot?.enabled && isIntegration) + await chatbotController.emit({ + instance: { instanceName: this.instance.name, instanceId: this.instanceId }, + remoteJid: messageRaw.key.remoteJid, + msg: messageRaw, + pushName: messageRaw.pushName, + }); + + await this.prismaRepository.message.create({ + data: messageRaw, + }); return messageRaw; } catch (error) { @@ -883,33 +956,44 @@ export class BusinessStartupService extends ChannelStartupService { } // Send Message Controller - public async textMessage(data: SendTextDto, isChatwoot = false) { - this.logger.verbose('Sending text message'); + public async textMessage(data: SendTextDto, isIntegration = false) { const res = await this.sendMessageWithTyping( data.number, { - conversation: data.textMessage.text, + conversation: data.text, }, - data?.options, - isChatwoot, + { + delay: data?.delay, + presence: 'composing', + quoted: data?.quoted, + linkPreview: data?.linkPreview, + mentionsEveryOne: data?.mentionsEveryOne, + mentioned: data?.mentioned, + }, + isIntegration, ); return res; } private async getIdMedia(mediaMessage: any) { - const integration = await this.findIntegration(); - const formData = new FormData(); - const fileBuffer = await fs.readFile(mediaMessage.media); + const fileStream = createReadStream(mediaMessage.media); - const fileBlob = new Blob([fileBuffer], { type: mediaMessage.mimetype }); - formData.append('file', fileBlob); + formData.append('file', fileStream, { filename: 'media', contentType: mediaMessage.mimetype }); formData.append('typeFile', mediaMessage.mimetype); formData.append('messaging_product', 'whatsapp'); - const headers = { Authorization: `Bearer ${integration.token}` }; + + // const fileBuffer = await fs.readFile(mediaMessage.media); + + // const fileBlob = new Blob([fileBuffer], { type: mediaMessage.mimetype }); + // formData.append('file', fileBlob); + // formData.append('typeFile', mediaMessage.mimetype); + // formData.append('messaging_product', 'whatsapp'); + + const headers = { Authorization: `Bearer ${this.token}` }; const res = await axios.post( - process.env.API_URL + '/' + process.env.VERSION + '/' + integration.number + '/media', + process.env.API_URL + '/' + process.env.VERSION + '/' + this.number + '/media', formData, { headers }, ); @@ -918,17 +1002,10 @@ export class BusinessStartupService extends ChannelStartupService { protected async prepareMediaMessage(mediaMessage: MediaMessage) { try { - this.logger.verbose('Preparing media message'); - - const mediaType = mediaMessage.mediatype + 'Message'; - this.logger.verbose('Media type: ' + mediaType); - if (mediaMessage.mediatype === 'document' && !mediaMessage.fileName) { - this.logger.verbose('If media type is document and file name is not defined then'); const regex = new RegExp(/.*\/(.+?)\./); const arrayMatch = regex.exec(mediaMessage.media); mediaMessage.fileName = arrayMatch[1]; - this.logger.verbose('File name: ' + mediaMessage.fileName); } if (mediaMessage.mediatype === 'image' && !mediaMessage.fileName) { @@ -939,7 +1016,7 @@ export class BusinessStartupService extends ChannelStartupService { mediaMessage.fileName = 'video.mp4'; } - let mimetype: string; + let mimetype: string | false; const prepareMedia: any = { caption: mediaMessage?.caption, @@ -949,24 +1026,19 @@ export class BusinessStartupService extends ChannelStartupService { gifPlayback: false, }; - if (mediaMessage.mimetype) { - mimetype = mediaMessage.mimetype; + if (isURL(mediaMessage.media)) { + mimetype = mimeTypes.lookup(mediaMessage.media); + prepareMedia.id = mediaMessage.media; + prepareMedia.type = 'link'; } else { - if (isURL(mediaMessage.media)) { - mimetype = getMIMEType(mediaMessage.media); - prepareMedia.id = mediaMessage.media; - prepareMedia.type = 'link'; - } else { - mimetype = getMIMEType(mediaMessage.fileName); - const id = await this.getIdMedia(prepareMedia); - prepareMedia.id = id; - prepareMedia.type = 'id'; - } + mimetype = mimeTypes.lookup(mediaMessage.fileName); + const id = await this.getIdMedia(prepareMedia); + prepareMedia.id = id; + prepareMedia.type = 'id'; } prepareMedia.mimetype = mimetype; - this.logger.verbose('Generating wa message from content'); return prepareMedia; } catch (error) { this.logger.error(error); @@ -974,21 +1046,35 @@ export class BusinessStartupService extends ChannelStartupService { } } - public async mediaMessage(data: SendMediaDto, isChatwoot = false) { - this.logger.verbose('Sending media message'); - const message = await this.prepareMediaMessage(data.mediaMessage); + public async mediaMessage(data: SendMediaDto, file?: any, isIntegration = false) { + const mediaData: SendMediaDto = { ...data }; - return await this.sendMessageWithTyping(data.number, { ...message }, data?.options, isChatwoot); + if (file) mediaData.media = file.buffer.toString('base64'); + + const message = await this.prepareMediaMessage(mediaData); + + const mediaSent = await this.sendMessageWithTyping( + data.number, + { ...message }, + { + delay: data?.delay, + presence: 'composing', + quoted: data?.quoted, + linkPreview: data?.linkPreview, + mentionsEveryOne: data?.mentionsEveryOne, + mentioned: data?.mentioned, + }, + isIntegration, + ); + + return mediaSent; } public async processAudio(audio: string, number: string) { - this.logger.verbose('Processing audio'); - number = number.replace(/\D/g, ''); const hash = `${number}-${new Date().getTime()}`; - this.logger.verbose('Hash to audio name: ' + hash); - let mimetype: string; + let mimetype: string | false; const prepareMedia: any = { fileName: `${hash}.mp3`, @@ -997,11 +1083,11 @@ export class BusinessStartupService extends ChannelStartupService { }; if (isURL(audio)) { - mimetype = getMIMEType(audio); + mimetype = mimeTypes.lookup(audio); prepareMedia.id = audio; prepareMedia.type = 'link'; } else { - mimetype = getMIMEType(prepareMedia.fileName); + mimetype = mimeTypes.lookup(prepareMedia.fileName); const id = await this.getIdMedia(prepareMedia); prepareMedia.id = id; prepareMedia.type = 'id'; @@ -1012,30 +1098,44 @@ export class BusinessStartupService extends ChannelStartupService { return prepareMedia; } - public async audioWhatsapp(data: SendAudioDto, isChatwoot = false) { - this.logger.verbose('Sending audio whatsapp'); + public async audioWhatsapp(data: SendAudioDto, file?: any, isIntegration = false) { + const mediaData: SendAudioDto = { ...data }; - const message = await this.processAudio(data.audioMessage.audio, data.number); - - return await this.sendMessageWithTyping(data.number, { ...message }, data?.options, isChatwoot); - } - - public async buttonMessage(data: SendButtonDto) { - this.logger.verbose('Sending button message'); - const embeddedMedia: any = {}; - let mediatype = 'TEXT'; - - if (data.buttonMessage?.mediaMessage) { - mediatype = data.buttonMessage.mediaMessage?.mediatype.toUpperCase() ?? 'TEXT'; - embeddedMedia.mediaKey = mediatype.toLowerCase() + 'Message'; - const generate = await this.prepareMediaMessage(data.buttonMessage.mediaMessage); - embeddedMedia.message = generate.message[embeddedMedia.mediaKey]; - embeddedMedia.contentText = `*${data.buttonMessage.title}*\n\n${data.buttonMessage.description}`; + if (file?.buffer) { + mediaData.audio = file.buffer.toString('base64'); + } else if (isURL(mediaData.audio)) { + // DO NOTHING + // mediaData.audio = mediaData.audio; + } else { + console.error('El archivo no tiene buffer o file es undefined'); + throw new Error('File or buffer is undefined'); } + const message = await this.processAudio(mediaData.audio, data.number); + + const audioSent = await this.sendMessageWithTyping( + data.number, + { ...message }, + { + delay: data?.delay, + presence: 'composing', + quoted: data?.quoted, + linkPreview: data?.linkPreview, + mentionsEveryOne: data?.mentionsEveryOne, + mentioned: data?.mentioned, + }, + isIntegration, + ); + + return audioSent; + } + + public async buttonMessage(data: SendButtonsDto) { + const embeddedMedia: any = {}; + const btnItems = { - text: data.buttonMessage.buttons.map((btn) => btn.buttonText), - ids: data.buttonMessage.buttons.map((btn) => btn.buttonId), + text: data.buttons.map((btn) => btn.displayText), + ids: data.buttons.map((btn) => btn.id), }; if (!arrayUnique(btnItems.text) || !arrayUnique(btnItems.ids)) { @@ -1045,132 +1145,151 @@ export class BusinessStartupService extends ChannelStartupService { return await this.sendMessageWithTyping( data.number, { - text: !embeddedMedia?.mediaKey ? data.buttonMessage.title : undefined, - buttons: data.buttonMessage.buttons.map((button) => { + text: !embeddedMedia?.mediaKey ? data.title : undefined, + buttons: data.buttons.map((button) => { return { type: 'reply', reply: { - title: button.buttonText, - id: button.buttonId, + title: button.displayText, + id: button.id, }, }; }), [embeddedMedia?.mediaKey]: embeddedMedia?.message, }, - data?.options, + { + delay: data?.delay, + presence: 'composing', + quoted: data?.quoted, + linkPreview: data?.linkPreview, + mentionsEveryOne: data?.mentionsEveryOne, + mentioned: data?.mentioned, + }, ); } public async locationMessage(data: SendLocationDto) { - this.logger.verbose('Sending location message'); return await this.sendMessageWithTyping( data.number, { locationMessage: { - degreesLatitude: data.locationMessage.latitude, - degreesLongitude: data.locationMessage.longitude, - name: data.locationMessage?.name, - address: data.locationMessage?.address, + degreesLatitude: data.latitude, + degreesLongitude: data.longitude, + name: data?.name, + address: data?.address, }, }, - data?.options, + { + delay: data?.delay, + presence: 'composing', + quoted: data?.quoted, + linkPreview: data?.linkPreview, + mentionsEveryOne: data?.mentionsEveryOne, + mentioned: data?.mentioned, + }, ); } public async listMessage(data: SendListDto) { - this.logger.verbose('Sending list message'); const sectionsItems = { - title: data.listMessage.sections.map((list) => list.title), + title: data.sections.map((list) => list.title), }; if (!arrayUnique(sectionsItems.title)) { throw new BadRequestException('Section tiles cannot be repeated'); } - return await this.sendMessageWithTyping( - data.number, - { - title: data.listMessage.title, - text: data.listMessage.description, - footerText: data.listMessage?.footerText, - buttonText: data.listMessage?.buttonText, - sections: data.listMessage.sections.map((section) => { + const sendData: any = { + listMessage: { + title: data.title, + description: data.description, + footerText: data?.footerText, + buttonText: data?.buttonText, + sections: data.sections.map((section) => { return { title: section.title, rows: section.rows.map((row) => { return { title: row.title, - description: row.description, + description: row.description.substring(0, 72), id: row.rowId, }; }), }; }), }, - data?.options, - ); + }; + + return await this.sendMessageWithTyping(data.number, sendData, { + delay: data?.delay, + presence: 'composing', + quoted: data?.quoted, + linkPreview: data?.linkPreview, + mentionsEveryOne: data?.mentionsEveryOne, + mentioned: data?.mentioned, + }); } - public async templateMessage(data: SendTemplateDto, isChatwoot = false) { - this.logger.verbose('Sending text message'); + public async templateMessage(data: SendTemplateDto, isIntegration = false) { const res = await this.sendMessageWithTyping( data.number, { template: { - name: data.templateMessage.name, - language: data.templateMessage.language, - components: data.templateMessage.components, + name: data.name, + language: data.language, + components: data.components, }, }, - data?.options, - isChatwoot, + { + delay: data?.delay, + presence: 'composing', + quoted: data?.quoted, + linkPreview: data?.linkPreview, + mentionsEveryOne: data?.mentionsEveryOne, + mentioned: data?.mentioned, + webhookUrl: data?.webhookUrl, + }, + isIntegration, ); return res; } public async contactMessage(data: SendContactDto) { - this.logger.verbose('Sending contact message'); const message: any = {}; const vcard = (contact: ContactMessage) => { - this.logger.verbose('Creating vcard'); let result = 'BEGIN:VCARD\n' + 'VERSION:3.0\n' + `N:${contact.fullName}\n` + `FN:${contact.fullName}\n`; if (contact.organization) { - this.logger.verbose('Organization defined'); result += `ORG:${contact.organization};\n`; } if (contact.email) { - this.logger.verbose('Email defined'); result += `EMAIL:${contact.email}\n`; } if (contact.url) { - this.logger.verbose('Url defined'); result += `URL:${contact.url}\n`; } if (!contact.wuid) { - this.logger.verbose('Wuid defined'); - contact.wuid = this.createJid(contact.phoneNumber); + contact.wuid = createJid(contact.phoneNumber); } result += `item1.TEL;waid=${contact.wuid}:${contact.phoneNumber}\n` + 'item1.X-ABLabel:Celular\n' + 'END:VCARD'; - this.logger.verbose('Vcard created'); return result; }; - if (data.contactMessage.length === 1) { - message.contactMessage = { - displayName: data.contactMessage[0].fullName, - vcard: vcard(data.contactMessage[0]), + if (data.contact.length === 1) { + message.contact = { + displayName: data.contact[0].fullName, + vcard: vcard(data.contact[0]), }; } else { message.contactsArrayMessage = { - displayName: `${data.contactMessage.length} contacts`, - contacts: data.contactMessage.map((contact) => { + displayName: `${data.contact.length} contacts`, + contacts: data.contact.map((contact) => { return { displayName: contact.fullName, vcard: vcard(contact), @@ -1181,7 +1300,7 @@ export class BusinessStartupService extends ChannelStartupService { return await this.sendMessageWithTyping( data.number, { - contacts: data.contactMessage.map((contact) => { + contacts: data.contact.map((contact) => { return { name: { formatted_name: contact.fullName, first_name: contact.fullName }, phones: [{ phone: contact.phoneNumber }], @@ -1192,16 +1311,22 @@ export class BusinessStartupService extends ChannelStartupService { }), message, }, - data?.options, + { + delay: data?.delay, + presence: 'composing', + quoted: data?.quoted, + linkPreview: data?.linkPreview, + mentionsEveryOne: data?.mentionsEveryOne, + mentioned: data?.mentioned, + }, ); } public async reactionMessage(data: SendReactionDto) { - this.logger.verbose('Sending reaction message'); - return await this.sendMessageWithTyping(data.reactionMessage.key.remoteJid, { + return await this.sendMessageWithTyping(data.key.remoteJid, { reactionMessage: { - key: data.reactionMessage.key, - text: data.reactionMessage.reaction, + key: data.key, + text: data.reaction, }, }); } @@ -1209,11 +1334,9 @@ export class BusinessStartupService extends ChannelStartupService { public async getBase64FromMediaMessage(data: any) { try { const msg = data.message; - this.logger.verbose('Getting base64 from media message'); - const messageType = msg.messageType + 'Message'; + const messageType = msg.messageType.includes('Message') ? msg.messageType : msg.messageType + 'Message'; const mediaMessage = msg.message[messageType]; - this.logger.verbose('Media message downloaded'); return { mediaType: msg.messageType, fileName: mediaMessage?.fileName, @@ -1264,6 +1387,9 @@ export class BusinessStartupService extends ChannelStartupService { public async fetchProfile() { throw new BadRequestException('Method not available on WhatsApp Business API'); } + public async offerCall() { + throw new BadRequestException('Method not available on WhatsApp Business API'); + } public async sendPresence() { throw new BadRequestException('Method not available on WhatsApp Business API'); } @@ -1354,4 +1480,7 @@ export class BusinessStartupService extends ChannelStartupService { public async receiveMobileCode() { throw new BadRequestException('Method not available on WhatsApp Business API'); } + public async fakeCall() { + throw new BadRequestException('Method not available on WhatsApp Business API'); + } } diff --git a/src/api/integrations/channel/whatsapp/baileys.controller.ts b/src/api/integrations/channel/whatsapp/baileys.controller.ts new file mode 100644 index 00000000..ee547338 --- /dev/null +++ b/src/api/integrations/channel/whatsapp/baileys.controller.ts @@ -0,0 +1,60 @@ +import { InstanceDto } from '@api/dto/instance.dto'; +import { WAMonitoringService } from '@api/services/monitor.service'; + +export class BaileysController { + constructor(private readonly waMonitor: WAMonitoringService) {} + + public async onWhatsapp({ instanceName }: InstanceDto, body: any) { + const instance = this.waMonitor.waInstances[instanceName]; + + return instance.baileysOnWhatsapp(body?.jid); + } + + public async profilePictureUrl({ instanceName }: InstanceDto, body: any) { + const instance = this.waMonitor.waInstances[instanceName]; + + return instance.baileysProfilePictureUrl(body?.jid, body?.type, body?.timeoutMs); + } + + public async assertSessions({ instanceName }: InstanceDto, body: any) { + const instance = this.waMonitor.waInstances[instanceName]; + + return instance.baileysAssertSessions(body?.jids, body?.force); + } + + public async createParticipantNodes({ instanceName }: InstanceDto, body: any) { + const instance = this.waMonitor.waInstances[instanceName]; + + return instance.baileysCreateParticipantNodes(body?.jids, body?.message, body?.extraAttrs); + } + + public async getUSyncDevices({ instanceName }: InstanceDto, body: any) { + const instance = this.waMonitor.waInstances[instanceName]; + + return instance.baileysGetUSyncDevices(body?.jids, body?.useCache, body?.ignoreZeroDevices); + } + + public async generateMessageTag({ instanceName }: InstanceDto) { + const instance = this.waMonitor.waInstances[instanceName]; + + return instance.baileysGenerateMessageTag(); + } + + public async sendNode({ instanceName }: InstanceDto, body: any) { + const instance = this.waMonitor.waInstances[instanceName]; + + return instance.baileysSendNode(body?.stanza); + } + + public async signalRepositoryDecryptMessage({ instanceName }: InstanceDto, body: any) { + const instance = this.waMonitor.waInstances[instanceName]; + + return instance.baileysSignalRepositoryDecryptMessage(body?.jid, body?.type, body?.ciphertext); + } + + public async getAuthState({ instanceName }: InstanceDto) { + const instance = this.waMonitor.waInstances[instanceName]; + + return instance.baileysGetAuthState(); + } +} diff --git a/src/api/integrations/channel/whatsapp/baileys.router.ts b/src/api/integrations/channel/whatsapp/baileys.router.ts new file mode 100644 index 00000000..04a1d565 --- /dev/null +++ b/src/api/integrations/channel/whatsapp/baileys.router.ts @@ -0,0 +1,105 @@ +import { RouterBroker } from '@api/abstract/abstract.router'; +import { InstanceDto } from '@api/dto/instance.dto'; +import { HttpStatus } from '@api/routes/index.router'; +import { baileysController } from '@api/server.module'; +import { instanceSchema } from '@validate/instance.schema'; +import { RequestHandler, Router } from 'express'; + +export class BaileysRouter extends RouterBroker { + constructor(...guards: RequestHandler[]) { + super(); + this.router + .post(this.routerPath('onWhatsapp'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => baileysController.onWhatsapp(instance, req.body), + }); + + res.status(HttpStatus.OK).json(response); + }) + .post(this.routerPath('profilePictureUrl'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => baileysController.profilePictureUrl(instance, req.body), + }); + + res.status(HttpStatus.OK).json(response); + }) + .post(this.routerPath('assertSessions'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => baileysController.assertSessions(instance, req.body), + }); + + res.status(HttpStatus.OK).json(response); + }) + .post(this.routerPath('createParticipantNodes'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => baileysController.createParticipantNodes(instance, req.body), + }); + + res.status(HttpStatus.OK).json(response); + }) + .post(this.routerPath('getUSyncDevices'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => baileysController.getUSyncDevices(instance, req.body), + }); + + res.status(HttpStatus.OK).json(response); + }) + .post(this.routerPath('generateMessageTag'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => baileysController.generateMessageTag(instance), + }); + + res.status(HttpStatus.OK).json(response); + }) + .post(this.routerPath('sendNode'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => baileysController.sendNode(instance, req.body), + }); + + res.status(HttpStatus.OK).json(response); + }) + .post(this.routerPath('signalRepositoryDecryptMessage'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => baileysController.signalRepositoryDecryptMessage(instance, req.body), + }); + + res.status(HttpStatus.OK).json(response); + }) + .post(this.routerPath('getAuthState'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => baileysController.getAuthState(instance), + }); + + res.status(HttpStatus.OK).json(response); + }); + } + + public readonly router: Router = Router(); +} diff --git a/src/api/integrations/channel/whatsapp/voiceCalls/transport.type.ts b/src/api/integrations/channel/whatsapp/voiceCalls/transport.type.ts new file mode 100644 index 00000000..f03c1028 --- /dev/null +++ b/src/api/integrations/channel/whatsapp/voiceCalls/transport.type.ts @@ -0,0 +1,78 @@ +import { BinaryNode, Contact, JidWithDevice, proto, WAConnectionState } from 'baileys'; + +export interface ServerToClientEvents { + withAck: (d: string, callback: (e: number) => void) => void; + onWhatsApp: onWhatsAppType; + profilePictureUrl: ProfilePictureUrlType; + assertSessions: AssertSessionsType; + createParticipantNodes: CreateParticipantNodesType; + getUSyncDevices: GetUSyncDevicesType; + generateMessageTag: GenerateMessageTagType; + sendNode: SendNodeType; + 'signalRepository:decryptMessage': SignalRepositoryDecryptMessageType; +} + +export interface ClientToServerEvents { + init: ( + me: Contact | undefined, + account: proto.IADVSignedDeviceIdentity | undefined, + status: WAConnectionState, + ) => void; + 'CB:call': (packet: any) => void; + 'CB:ack,class:call': (packet: any) => void; + 'connection.update:status': ( + me: Contact | undefined, + account: proto.IADVSignedDeviceIdentity | undefined, + status: WAConnectionState, + ) => void; + 'connection.update:qr': (qr: string) => void; +} + +export type onWhatsAppType = (jid: string, callback: onWhatsAppCallback) => void; +export type onWhatsAppCallback = ( + response: { + exists: boolean; + jid: string; + }[], +) => void; + +export type ProfilePictureUrlType = ( + jid: string, + type: 'image' | 'preview', + timeoutMs: number | undefined, + callback: ProfilePictureUrlCallback, +) => void; +export type ProfilePictureUrlCallback = (response: string | undefined) => void; + +export type AssertSessionsType = (jids: string[], force: boolean, callback: AssertSessionsCallback) => void; +export type AssertSessionsCallback = (response: boolean) => void; + +export type CreateParticipantNodesType = ( + jids: string[], + message: any, + extraAttrs: any, + callback: CreateParticipantNodesCallback, +) => void; +export type CreateParticipantNodesCallback = (nodes: any, shouldIncludeDeviceIdentity: boolean) => void; + +export type GetUSyncDevicesType = ( + jids: string[], + useCache: boolean, + ignoreZeroDevices: boolean, + callback: GetUSyncDevicesTypeCallback, +) => void; +export type GetUSyncDevicesTypeCallback = (jids: JidWithDevice[]) => void; + +export type GenerateMessageTagType = (callback: GenerateMessageTagTypeCallback) => void; +export type GenerateMessageTagTypeCallback = (response: string) => void; + +export type SendNodeType = (stanza: BinaryNode, callback: SendNodeTypeCallback) => void; +export type SendNodeTypeCallback = (response: boolean) => void; + +export type SignalRepositoryDecryptMessageType = ( + jid: string, + type: 'pkmsg' | 'msg', + ciphertext: Buffer, + callback: SignalRepositoryDecryptMessageCallback, +) => void; +export type SignalRepositoryDecryptMessageCallback = (response: any) => void; diff --git a/src/api/integrations/channel/whatsapp/voiceCalls/useVoiceCallsBaileys.ts b/src/api/integrations/channel/whatsapp/voiceCalls/useVoiceCallsBaileys.ts new file mode 100644 index 00000000..951be1a0 --- /dev/null +++ b/src/api/integrations/channel/whatsapp/voiceCalls/useVoiceCallsBaileys.ts @@ -0,0 +1,181 @@ +import { ConnectionState, WAConnectionState, WASocket } from 'baileys'; +import { io, Socket } from 'socket.io-client'; + +import { ClientToServerEvents, ServerToClientEvents } from './transport.type'; + +let baileys_connection_state: WAConnectionState = 'close'; + +export const useVoiceCallsBaileys = async ( + wavoip_token: string, + baileys_sock: WASocket, + status?: WAConnectionState, + logger?: boolean, +) => { + baileys_connection_state = status ?? 'close'; + + const socket: Socket = io('https://devices.wavoip.com/baileys', { + transports: ['websocket'], + path: `/${wavoip_token}/websocket`, + }); + + socket.on('connect', () => { + if (logger) console.log('[*] - Wavoip connected', socket.id); + + socket.emit( + 'init', + baileys_sock.authState.creds.me, + baileys_sock.authState.creds.account, + baileys_connection_state, + ); + }); + + socket.on('disconnect', () => { + if (logger) console.log('[*] - Wavoip disconnect'); + }); + + socket.on('connect_error', (error) => { + if (socket.active) { + if (logger) + console.log( + '[*] - Wavoip connection error temporary failure, the socket will automatically try to reconnect', + error, + ); + } else { + if (logger) console.log('[*] - Wavoip connection error', error.message); + } + }); + + socket.on('onWhatsApp', async (jid, callback) => { + try { + const response: any = await baileys_sock.onWhatsApp(jid); + + callback(response); + + if (logger) console.log('[*] Success on call onWhatsApp function', response, jid); + } catch (error) { + if (logger) console.error('[*] Error on call onWhatsApp function', error); + } + }); + + socket.on('profilePictureUrl', async (jid, type, timeoutMs, callback) => { + try { + const response = await baileys_sock.profilePictureUrl(jid, type, timeoutMs); + + callback(response); + + if (logger) console.log('[*] Success on call profilePictureUrl function', response); + } catch (error) { + if (logger) console.error('[*] Error on call profilePictureUrl function', error); + } + }); + + socket.on('assertSessions', async (jids, force, callback) => { + try { + const response = await baileys_sock.assertSessions(jids, force); + + callback(response); + + if (logger) console.log('[*] Success on call assertSessions function', response); + } catch (error) { + if (logger) console.error('[*] Error on call assertSessions function', error); + } + }); + + socket.on('createParticipantNodes', async (jids, message, extraAttrs, callback) => { + try { + const response = await baileys_sock.createParticipantNodes(jids, message, extraAttrs); + + callback(response, true); + + if (logger) console.log('[*] Success on call createParticipantNodes function', response); + } catch (error) { + if (logger) console.error('[*] Error on call createParticipantNodes function', error); + } + }); + + socket.on('getUSyncDevices', async (jids, useCache, ignoreZeroDevices, callback) => { + try { + const response = await baileys_sock.getUSyncDevices(jids, useCache, ignoreZeroDevices); + + callback(response); + + if (logger) console.log('[*] Success on call getUSyncDevices function', response); + } catch (error) { + if (logger) console.error('[*] Error on call getUSyncDevices function', error); + } + }); + + socket.on('generateMessageTag', async (callback) => { + try { + const response = await baileys_sock.generateMessageTag(); + + callback(response); + + if (logger) console.log('[*] Success on call generateMessageTag function', response); + } catch (error) { + if (logger) console.error('[*] Error on call generateMessageTag function', error); + } + }); + + socket.on('sendNode', async (stanza, callback) => { + try { + console.log('sendNode', JSON.stringify(stanza)); + const response = await baileys_sock.sendNode(stanza); + + callback(true); + + if (logger) console.log('[*] Success on call sendNode function', response); + } catch (error) { + if (logger) console.error('[*] Error on call sendNode function', error); + } + }); + + socket.on('signalRepository:decryptMessage', async (jid, type, ciphertext, callback) => { + try { + const response = await baileys_sock.signalRepository.decryptMessage({ + jid: jid, + type: type, + ciphertext: ciphertext, + }); + + callback(response); + + if (logger) console.log('[*] Success on call signalRepository:decryptMessage function', response); + } catch (error) { + if (logger) console.error('[*] Error on call signalRepository:decryptMessage function', error); + } + }); + + // we only use this connection data to inform the webphone that the device is connected and creeds account to generate e2e whatsapp key for make call packets + baileys_sock.ev.on('connection.update', (update: Partial) => { + const { connection } = update; + + if (connection) { + baileys_connection_state = connection; + socket + .timeout(1000) + .emit( + 'connection.update:status', + baileys_sock.authState.creds.me, + baileys_sock.authState.creds.account, + connection, + ); + } + + if (update.qr) { + socket.timeout(1000).emit('connection.update:qr', update.qr); + } + }); + + baileys_sock.ws.on('CB:call', (packet) => { + if (logger) console.log('[*] Signling received'); + socket.volatile.timeout(1000).emit('CB:call', packet); + }); + + baileys_sock.ws.on('CB:ack,class:call', (packet) => { + if (logger) console.log('[*] Signling ack received'); + socket.volatile.timeout(1000).emit('CB:ack,class:call', packet); + }); + + return socket; +}; diff --git a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts new file mode 100644 index 00000000..10feb7ce --- /dev/null +++ b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts @@ -0,0 +1,4537 @@ +import { OfferCallDto } from '@api/dto/call.dto'; +import { + ArchiveChatDto, + BlockUserDto, + DeleteMessage, + getBase64FromMediaMessageDto, + LastMessage, + MarkChatUnreadDto, + NumberBusiness, + OnWhatsAppDto, + PrivacySettingDto, + ReadMessageDto, + SendPresenceDto, + UpdateMessageDto, + WhatsAppNumberDto, +} from '@api/dto/chat.dto'; +import { + AcceptGroupInvite, + CreateGroupDto, + GetParticipant, + GroupDescriptionDto, + GroupInvite, + GroupJid, + GroupPictureDto, + GroupSendInvite, + GroupSubjectDto, + GroupToggleEphemeralDto, + GroupUpdateParticipantDto, + GroupUpdateSettingDto, +} from '@api/dto/group.dto'; +import { InstanceDto, SetPresenceDto } from '@api/dto/instance.dto'; +import { HandleLabelDto, LabelDto } from '@api/dto/label.dto'; +import { + Button, + ContactMessage, + KeyType, + MediaMessage, + Options, + SendAudioDto, + SendButtonsDto, + SendContactDto, + SendListDto, + SendLocationDto, + SendMediaDto, + SendPollDto, + SendPtvDto, + SendReactionDto, + SendStatusDto, + SendStickerDto, + SendTextDto, + StatusMessage, + TypeButton, +} from '@api/dto/sendMessage.dto'; +import { chatwootImport } from '@api/integrations/chatbot/chatwoot/utils/chatwoot-import-helper'; +import * as s3Service from '@api/integrations/storage/s3/libs/minio.server'; +import { ProviderFiles } from '@api/provider/sessions'; +import { PrismaRepository } from '@api/repository/repository.service'; +import { chatbotController, waMonitor } from '@api/server.module'; +import { CacheService } from '@api/services/cache.service'; +import { ChannelStartupService } from '@api/services/channel.service'; +import { Events, MessageSubtype, TypeMediaMessage, wa } from '@api/types/wa.types'; +import { CacheEngine } from '@cache/cacheengine'; +import { + CacheConf, + Chatwoot, + ConfigService, + configService, + ConfigSessionPhone, + Database, + Log, + Openai, + ProviderSession, + QrCode, + S3, +} from '@config/env.config'; +import { BadRequestException, InternalServerErrorException, NotFoundException } from '@exceptions'; +import ffmpegPath from '@ffmpeg-installer/ffmpeg'; +import { Boom } from '@hapi/boom'; +import { createId as cuid } from '@paralleldrive/cuid2'; +import { Instance } from '@prisma/client'; +import { createJid } from '@utils/createJid'; +import { makeProxyAgent } from '@utils/makeProxyAgent'; +import { getOnWhatsappCache, saveOnWhatsappCache } from '@utils/onWhatsappCache'; +import { status } from '@utils/renderStatus'; +import useMultiFileAuthStatePrisma from '@utils/use-multi-file-auth-state-prisma'; +import { AuthStateProvider } from '@utils/use-multi-file-auth-state-provider-files'; +import { useMultiFileAuthStateRedisDb } from '@utils/use-multi-file-auth-state-redis-db'; +import axios from 'axios'; +import makeWASocket, { + AnyMessageContent, + BufferedEventData, + BufferJSON, + CacheStore, + Chat, + ConnectionState, + Contact, + delay, + DisconnectReason, + downloadMediaMessage, + fetchLatestBaileysVersion, + generateWAMessageFromContent, + getAggregateVotesInPollMessage, + getContentType, + getDevice, + GroupMetadata, + isJidBroadcast, + isJidGroup, + isJidNewsletter, + isJidUser, + makeCacheableSignalKeyStore, + MessageUpsertType, + MessageUserReceiptUpdate, + MiscMessageGenerationOptions, + ParticipantAction, + prepareWAMessageMedia, + proto, + UserFacingSocketConfig, + WABrowserDescription, + WAMediaUpload, + WAMessage, + WAMessageUpdate, + WAPresence, + WASocket, +} from 'baileys'; +import { Label } from 'baileys/lib/Types/Label'; +import { LabelAssociation } from 'baileys/lib/Types/LabelAssociation'; +import { spawn } from 'child_process'; +import { isArray, isBase64, isURL } from 'class-validator'; +import { randomBytes } from 'crypto'; +import EventEmitter2 from 'eventemitter2'; +import ffmpeg from 'fluent-ffmpeg'; +import FormData from 'form-data'; +import { readFileSync } from 'fs'; +import Long from 'long'; +import mimeTypes from 'mime-types'; +import NodeCache from 'node-cache'; +import cron from 'node-cron'; +import { release } from 'os'; +import { join } from 'path'; +import P from 'pino'; +import qrcode, { QRCodeToDataURLOptions } from 'qrcode'; +import qrcodeTerminal from 'qrcode-terminal'; +import sharp from 'sharp'; +import { PassThrough, Readable } from 'stream'; +import { v4 } from 'uuid'; + +import { useVoiceCallsBaileys } from './voiceCalls/useVoiceCallsBaileys'; + +const groupMetadataCache = new CacheService(new CacheEngine(configService, 'groups').getEngine()); + +// Adicione a função getVideoDuration no início do arquivo +async function getVideoDuration(input: Buffer | string | Readable): Promise { + const MediaInfoFactory = (await import('mediainfo.js')).default; + const mediainfo = await MediaInfoFactory({ format: 'JSON' }); + + let fileSize: number; + let readChunk: (size: number, offset: number) => Promise; + + if (Buffer.isBuffer(input)) { + fileSize = input.length; + readChunk = async (size: number, offset: number): Promise => { + return input.slice(offset, offset + size); + }; + } else if (typeof input === 'string') { + const fs = await import('fs'); + const stat = await fs.promises.stat(input); + fileSize = stat.size; + const fd = await fs.promises.open(input, 'r'); + + readChunk = async (size: number, offset: number): Promise => { + const buffer = Buffer.alloc(size); + await fd.read(buffer, 0, size, offset); + return buffer; + }; + + try { + const result = await mediainfo.analyzeData(() => fileSize, readChunk); + const jsonResult = JSON.parse(result); + + const generalTrack = jsonResult.media.track.find((t: any) => t['@type'] === 'General'); + const duration = generalTrack.Duration; + + return Math.round(parseFloat(duration)); + } finally { + await fd.close(); + } + } else if (input instanceof Readable) { + const chunks: Buffer[] = []; + for await (const chunk of input) { + chunks.push(chunk); + } + const data = Buffer.concat(chunks); + fileSize = data.length; + + readChunk = async (size: number, offset: number): Promise => { + return data.slice(offset, offset + size); + }; + } else { + throw new Error('Tipo de entrada não suportado'); + } + + const result = await mediainfo.analyzeData(() => fileSize, readChunk); + const jsonResult = JSON.parse(result); + + const generalTrack = jsonResult.media.track.find((t: any) => t['@type'] === 'General'); + const duration = generalTrack.Duration; + + return Math.round(parseFloat(duration)); +} + +export class BaileysStartupService extends ChannelStartupService { + constructor( + public readonly configService: ConfigService, + public readonly eventEmitter: EventEmitter2, + public readonly prismaRepository: PrismaRepository, + public readonly cache: CacheService, + public readonly chatwootCache: CacheService, + public readonly baileysCache: CacheService, + private readonly providerFiles: ProviderFiles, + ) { + super(configService, eventEmitter, prismaRepository, chatwootCache); + this.instance.qrcode = { count: 0 }; + + this.authStateProvider = new AuthStateProvider(this.providerFiles); + } + + private authStateProvider: AuthStateProvider; + private readonly msgRetryCounterCache: CacheStore = new NodeCache(); + private readonly userDevicesCache: CacheStore = new NodeCache(); + private endSession = false; + private logBaileys = this.configService.get('LOG').BAILEYS; + + public stateConnection: wa.StateConnection = { state: 'close' }; + + public phoneNumber: string; + + public get connectionStatus() { + return this.stateConnection; + } + + public async logoutInstance() { + await this.client?.logout('Log out instance: ' + this.instanceName); + + this.client?.ws?.close(); + + const sessionExists = await this.prismaRepository.session.findFirst({ + where: { sessionId: this.instanceId }, + }); + if (sessionExists) { + await this.prismaRepository.session.delete({ + where: { + sessionId: this.instanceId, + }, + }); + } + } + + public async getProfileName() { + let profileName = this.client.user?.name ?? this.client.user?.verifiedName; + if (!profileName) { + const data = await this.prismaRepository.session.findUnique({ + where: { sessionId: this.instanceId }, + }); + + if (data) { + const creds = JSON.parse(JSON.stringify(data.creds), BufferJSON.reviver); + profileName = creds.me?.name || creds.me?.verifiedName; + } + } + + return profileName; + } + + public async getProfileStatus() { + const status = await this.client.fetchStatus(this.instance.wuid); + + return status[0]?.status; + } + + public get profilePictureUrl() { + return this.instance.profilePictureUrl; + } + + public get qrCode(): wa.QrCode { + return { + pairingCode: this.instance.qrcode?.pairingCode, + code: this.instance.qrcode?.code, + base64: this.instance.qrcode?.base64, + count: this.instance.qrcode?.count, + }; + } + + private async connectionUpdate({ qr, connection, lastDisconnect }: Partial) { + if (qr) { + if (this.instance.qrcode.count === this.configService.get('QRCODE').LIMIT) { + this.sendDataWebhook(Events.QRCODE_UPDATED, { + message: 'QR code limit reached, please login again', + statusCode: DisconnectReason.badSession, + }); + + if (this.configService.get('CHATWOOT').ENABLED && this.localChatwoot?.enabled) { + this.chatwootService.eventWhatsapp( + Events.QRCODE_UPDATED, + { instanceName: this.instance.name, instanceId: this.instanceId }, + { + message: 'QR code limit reached, please login again', + statusCode: DisconnectReason.badSession, + }, + ); + } + + this.sendDataWebhook(Events.CONNECTION_UPDATE, { + instance: this.instance.name, + state: 'refused', + statusReason: DisconnectReason.connectionClosed, + wuid: this.instance.wuid, + profileName: await this.getProfileName(), + profilePictureUrl: this.instance.profilePictureUrl, + }); + + this.endSession = true; + + return this.eventEmitter.emit('no.connection', this.instance.name); + } + + this.instance.qrcode.count++; + + const color = this.configService.get('QRCODE').COLOR; + + const optsQrcode: QRCodeToDataURLOptions = { + margin: 3, + scale: 4, + errorCorrectionLevel: 'H', + color: { light: '#ffffff', dark: color }, + }; + + if (this.phoneNumber) { + await delay(1000); + this.instance.qrcode.pairingCode = await this.client.requestPairingCode(this.phoneNumber); + } else { + this.instance.qrcode.pairingCode = null; + } + + qrcode.toDataURL(qr, optsQrcode, (error, base64) => { + if (error) { + this.logger.error('Qrcode generate failed:' + error.toString()); + return; + } + + this.instance.qrcode.base64 = base64; + this.instance.qrcode.code = qr; + + this.sendDataWebhook(Events.QRCODE_UPDATED, { + qrcode: { + instance: this.instance.name, + pairingCode: this.instance.qrcode.pairingCode, + code: qr, + base64, + }, + }); + + if (this.configService.get('CHATWOOT').ENABLED && this.localChatwoot?.enabled) { + this.chatwootService.eventWhatsapp( + Events.QRCODE_UPDATED, + { instanceName: this.instance.name, instanceId: this.instanceId }, + { + qrcode: { + instance: this.instance.name, + pairingCode: this.instance.qrcode.pairingCode, + code: qr, + base64, + }, + }, + ); + } + }); + + qrcodeTerminal.generate(qr, { small: true }, (qrcode) => + this.logger.log( + `\n{ instance: ${this.instance.name} pairingCode: ${this.instance.qrcode.pairingCode}, qrcodeCount: ${this.instance.qrcode.count} }\n` + + qrcode, + ), + ); + + await this.prismaRepository.instance.update({ + where: { id: this.instanceId }, + data: { + connectionStatus: 'connecting', + }, + }); + } + + if (connection) { + this.stateConnection = { + state: connection, + statusReason: (lastDisconnect?.error as Boom)?.output?.statusCode ?? 200, + }; + } + + if (connection === 'close') { + const statusCode = (lastDisconnect?.error as Boom)?.output?.statusCode; + const codesToNotReconnect = [DisconnectReason.loggedOut, DisconnectReason.forbidden, 402, 406]; + const shouldReconnect = !codesToNotReconnect.includes(statusCode); + if (shouldReconnect) { + await this.connectToWhatsapp(this.phoneNumber); + } else { + this.sendDataWebhook(Events.STATUS_INSTANCE, { + instance: this.instance.name, + status: 'closed', + disconnectionAt: new Date(), + disconnectionReasonCode: statusCode, + disconnectionObject: JSON.stringify(lastDisconnect), + }); + + await this.prismaRepository.instance.update({ + where: { id: this.instanceId }, + data: { + connectionStatus: 'close', + disconnectionAt: new Date(), + disconnectionReasonCode: statusCode, + disconnectionObject: JSON.stringify(lastDisconnect), + }, + }); + + if (this.configService.get('CHATWOOT').ENABLED && this.localChatwoot?.enabled) { + this.chatwootService.eventWhatsapp( + Events.STATUS_INSTANCE, + { instanceName: this.instance.name, instanceId: this.instanceId }, + { + instance: this.instance.name, + status: 'closed', + }, + ); + } + + this.eventEmitter.emit('logout.instance', this.instance.name, 'inner'); + this.client?.ws?.close(); + this.client.end(new Error('Close connection')); + + this.sendDataWebhook(Events.CONNECTION_UPDATE, { + instance: this.instance.name, + ...this.stateConnection, + }); + } + } + + if (connection === 'open') { + this.instance.wuid = this.client.user.id.replace(/:\d+/, ''); + try { + const profilePic = await this.profilePicture(this.instance.wuid); + this.instance.profilePictureUrl = profilePic.profilePictureUrl; + } catch (error) { + this.instance.profilePictureUrl = null; + } + const formattedWuid = this.instance.wuid.split('@')[0].padEnd(30, ' '); + const formattedName = this.instance.name; + this.logger.info( + ` + ┌──────────────────────────────┐ + │ CONNECTED TO WHATSAPP │ + └──────────────────────────────┘`.replace(/^ +/gm, ' '), + ); + this.logger.info( + ` + wuid: ${formattedWuid} + name: ${formattedName} + `, + ); + + await this.prismaRepository.instance.update({ + where: { id: this.instanceId }, + data: { + ownerJid: this.instance.wuid, + profileName: (await this.getProfileName()) as string, + profilePicUrl: this.instance.profilePictureUrl, + connectionStatus: 'open', + }, + }); + + if (this.configService.get('CHATWOOT').ENABLED && this.localChatwoot?.enabled) { + this.chatwootService.eventWhatsapp( + Events.CONNECTION_UPDATE, + { instanceName: this.instance.name, instanceId: this.instanceId }, + { + instance: this.instance.name, + status: 'open', + }, + ); + this.syncChatwootLostMessages(); + } + + this.sendDataWebhook(Events.CONNECTION_UPDATE, { + instance: this.instance.name, + wuid: this.instance.wuid, + profileName: await this.getProfileName(), + profilePictureUrl: this.instance.profilePictureUrl, + ...this.stateConnection, + }); + } + + if (connection === 'connecting') { + this.sendDataWebhook(Events.CONNECTION_UPDATE, { + instance: this.instance.name, + ...this.stateConnection, + }); + } + } + + private async getMessage(key: proto.IMessageKey, full = false) { + try { + const webMessageInfo = (await this.prismaRepository.message.findMany({ + where: { + instanceId: this.instanceId, + key: { + path: ['id'], + equals: key.id, + }, + }, + })) as unknown as proto.IWebMessageInfo[]; + if (full) { + return webMessageInfo[0]; + } + if (webMessageInfo[0].message?.pollCreationMessage) { + const messageSecretBase64 = webMessageInfo[0].message?.messageContextInfo?.messageSecret; + + if (typeof messageSecretBase64 === 'string') { + const messageSecret = Buffer.from(messageSecretBase64, 'base64'); + + const msg = { + messageContextInfo: { + messageSecret, + }, + pollCreationMessage: webMessageInfo[0].message?.pollCreationMessage, + }; + + return msg; + } + } + + return webMessageInfo[0].message; + } catch (error) { + return { conversation: '' }; + } + } + + private async defineAuthState() { + const db = this.configService.get('DATABASE'); + const cache = this.configService.get('CACHE'); + + const provider = this.configService.get('PROVIDER'); + + if (provider?.ENABLED) { + return await this.authStateProvider.authStateProvider(this.instance.id); + } + + if (cache?.REDIS.ENABLED && cache?.REDIS.SAVE_INSTANCES) { + this.logger.info('Redis enabled'); + return await useMultiFileAuthStateRedisDb(this.instance.id, this.cache); + } + + if (db.SAVE_DATA.INSTANCE) { + return await useMultiFileAuthStatePrisma(this.instance.id, this.cache); + } + } + + private async createClient(number?: string): Promise { + this.instance.authState = await this.defineAuthState(); + + const session = this.configService.get('CONFIG_SESSION_PHONE'); + + let browserOptions = {}; + + if (number || this.phoneNumber) { + this.phoneNumber = number; + + this.logger.info(`Phone number: ${number}`); + } else { + const browser: WABrowserDescription = [session.CLIENT, session.NAME, release()]; + browserOptions = { browser }; + + this.logger.info(`Browser: ${browser}`); + } + + let version; + let log; + + if (session.VERSION) { + version = session.VERSION.split('.'); + log = `Baileys version env: ${version}`; + } else { + const baileysVersion = await fetchLatestBaileysVersion(); + version = baileysVersion.version; + log = `Baileys version: ${version}`; + } + + this.logger.info(log); + + this.logger.info(`Group Ignore: ${this.localSettings.groupsIgnore}`); + + let options; + + if (this.localProxy?.enabled) { + this.logger.info('Proxy enabled: ' + this.localProxy?.host); + + if (this.localProxy?.host?.includes('proxyscrape')) { + try { + const response = await axios.get(this.localProxy?.host); + const text = response.data; + const proxyUrls = text.split('\r\n'); + const rand = Math.floor(Math.random() * Math.floor(proxyUrls.length)); + const proxyUrl = 'http://' + proxyUrls[rand]; + options = { + agent: makeProxyAgent(proxyUrl), + fetchAgent: makeProxyAgent(proxyUrl), + }; + } catch (error) { + this.localProxy.enabled = false; + } + } else { + options = { + agent: makeProxyAgent({ + host: this.localProxy.host, + port: this.localProxy.port, + protocol: this.localProxy.protocol, + username: this.localProxy.username, + password: this.localProxy.password, + }), + fetchAgent: makeProxyAgent({ + host: this.localProxy.host, + port: this.localProxy.port, + protocol: this.localProxy.protocol, + username: this.localProxy.username, + password: this.localProxy.password, + }), + }; + } + } + + const socketConfig: UserFacingSocketConfig = { + ...options, + version, + logger: P({ level: this.logBaileys }), + printQRInTerminal: false, + auth: { + creds: this.instance.authState.state.creds, + keys: makeCacheableSignalKeyStore(this.instance.authState.state.keys, P({ level: 'error' }) as any), + }, + msgRetryCounterCache: this.msgRetryCounterCache, + generateHighQualityLinkPreview: true, + getMessage: async (key) => (await this.getMessage(key)) as Promise, + ...browserOptions, + markOnlineOnConnect: this.localSettings.alwaysOnline, + retryRequestDelayMs: 350, + maxMsgRetryCount: 4, + fireInitQueries: true, + connectTimeoutMs: 30_000, + keepAliveIntervalMs: 30_000, + qrTimeout: 45_000, + emitOwnEvents: false, + shouldIgnoreJid: (jid) => { + const isGroupJid = this.localSettings.groupsIgnore && isJidGroup(jid); + const isBroadcast = !this.localSettings.readStatus && isJidBroadcast(jid); + const isNewsletter = isJidNewsletter(jid); + + return isGroupJid || isBroadcast || isNewsletter; + }, + syncFullHistory: this.localSettings.syncFullHistory, + shouldSyncHistoryMessage: (msg: proto.Message.IHistorySyncNotification) => { + return this.historySyncNotification(msg); + }, + cachedGroupMetadata: this.getGroupMetadataCache, + userDevicesCache: this.userDevicesCache, + transactionOpts: { maxCommitRetries: 10, delayBetweenTriesMs: 3000 }, + patchMessageBeforeSending(message) { + if ( + message.deviceSentMessage?.message?.listMessage?.listType === proto.Message.ListMessage.ListType.PRODUCT_LIST + ) { + message = JSON.parse(JSON.stringify(message)); + + message.deviceSentMessage.message.listMessage.listType = proto.Message.ListMessage.ListType.SINGLE_SELECT; + } + + if (message.listMessage?.listType == proto.Message.ListMessage.ListType.PRODUCT_LIST) { + message = JSON.parse(JSON.stringify(message)); + + message.listMessage.listType = proto.Message.ListMessage.ListType.SINGLE_SELECT; + } + + return message; + }, + }; + + this.endSession = false; + + this.client = makeWASocket(socketConfig); + + if (this.localSettings.wavoipToken && this.localSettings.wavoipToken.length > 0) { + useVoiceCallsBaileys(this.localSettings.wavoipToken, this.client, this.connectionStatus.state as any, true); + } + + this.eventHandler(); + + this.client.ws.on('CB:call', (packet) => { + console.log('CB:call', packet); + const payload = { + event: 'CB:call', + packet: packet, + }; + this.sendDataWebhook(Events.CALL, payload, true, ['websocket']); + }); + + this.client.ws.on('CB:ack,class:call', (packet) => { + console.log('CB:ack,class:call', packet); + const payload = { + event: 'CB:ack,class:call', + packet: packet, + }; + this.sendDataWebhook(Events.CALL, payload, true, ['websocket']); + }); + + this.phoneNumber = number; + + return this.client; + } + + public async connectToWhatsapp(number?: string): Promise { + try { + this.loadChatwoot(); + this.loadSettings(); + this.loadWebhook(); + this.loadProxy(); + + return await this.createClient(number); + } catch (error) { + this.logger.error(error); + throw new InternalServerErrorException(error?.toString()); + } + } + + public async reloadConnection(): Promise { + try { + return await this.createClient(this.phoneNumber); + } catch (error) { + this.logger.error(error); + throw new InternalServerErrorException(error?.toString()); + } + } + + private readonly chatHandle = { + 'chats.upsert': async (chats: Chat[]) => { + const existingChatIds = await this.prismaRepository.chat.findMany({ + where: { instanceId: this.instanceId }, + select: { remoteJid: true }, + }); + + const existingChatIdSet = new Set(existingChatIds.map((chat) => chat.remoteJid)); + + const chatsToInsert = chats + .filter((chat) => !existingChatIdSet?.has(chat.id)) + .map((chat) => ({ + remoteJid: chat.id, + instanceId: this.instanceId, + name: chat.name, + unreadMessages: chat.unreadCount !== undefined ? chat.unreadCount : 0, + })); + + this.sendDataWebhook(Events.CHATS_UPSERT, chatsToInsert); + + if (chatsToInsert.length > 0) { + if (this.configService.get('DATABASE').SAVE_DATA.CHATS) + await this.prismaRepository.chat.createMany({ + data: chatsToInsert, + skipDuplicates: true, + }); + } + }, + + 'chats.update': async ( + chats: Partial< + proto.IConversation & { + lastMessageRecvTimestamp?: number; + } & { + conditional: (bufferedData: BufferedEventData) => boolean; + } + >[], + ) => { + const chatsRaw = chats.map((chat) => { + return { remoteJid: chat.id, instanceId: this.instanceId }; + }); + + this.sendDataWebhook(Events.CHATS_UPDATE, chatsRaw); + + for (const chat of chats) { + await this.prismaRepository.chat.updateMany({ + where: { + instanceId: this.instanceId, + remoteJid: chat.id, + name: chat.name, + }, + data: { remoteJid: chat.id }, + }); + } + }, + + 'chats.delete': async (chats: string[]) => { + chats.forEach( + async (chat) => + await this.prismaRepository.chat.deleteMany({ + where: { instanceId: this.instanceId, remoteJid: chat }, + }), + ); + + this.sendDataWebhook(Events.CHATS_DELETE, [...chats]); + }, + }; + + private readonly contactHandle = { + 'contacts.upsert': async (contacts: Contact[]) => { + try { + const contactsRaw: any = contacts.map((contact) => ({ + remoteJid: contact.id, + pushName: contact?.name || contact?.verifiedName || contact.id.split('@')[0], + profilePicUrl: null, + instanceId: this.instanceId, + })); + + if (contactsRaw.length > 0) { + this.sendDataWebhook(Events.CONTACTS_UPSERT, contactsRaw); + + if (this.configService.get('DATABASE').SAVE_DATA.CONTACTS) + await this.prismaRepository.contact.createMany({ + data: contactsRaw, + skipDuplicates: true, + }); + + const usersContacts = contactsRaw.filter((c) => c.remoteJid.includes('@s.whatsapp')); + if (usersContacts) { + await saveOnWhatsappCache(usersContacts.map((c) => ({ remoteJid: c.remoteJid }))); + } + } + + if ( + this.configService.get('CHATWOOT').ENABLED && + this.localChatwoot?.enabled && + this.localChatwoot.importContacts && + contactsRaw.length + ) { + this.chatwootService.addHistoryContacts( + { instanceName: this.instance.name, instanceId: this.instance.id }, + contactsRaw, + ); + chatwootImport.importHistoryContacts( + { instanceName: this.instance.name, instanceId: this.instance.id }, + this.localChatwoot, + ); + } + + const updatedContacts = await Promise.all( + contacts.map(async (contact) => ({ + remoteJid: contact.id, + pushName: contact?.name || contact?.verifiedName || contact.id.split('@')[0], + profilePicUrl: (await this.profilePicture(contact.id)).profilePictureUrl, + instanceId: this.instanceId, + })), + ); + + if (updatedContacts.length > 0) { + const usersContacts = updatedContacts.filter((c) => c.remoteJid.includes('@s.whatsapp')); + if (usersContacts) { + await saveOnWhatsappCache(usersContacts.map((c) => ({ remoteJid: c.remoteJid }))); + } + + this.sendDataWebhook(Events.CONTACTS_UPDATE, updatedContacts); + await Promise.all( + updatedContacts.map(async (contact) => { + const update = this.prismaRepository.contact.updateMany({ + where: { remoteJid: contact.remoteJid, instanceId: this.instanceId }, + data: { + profilePicUrl: contact.profilePicUrl, + }, + }); + + if (this.configService.get('CHATWOOT').ENABLED && this.localChatwoot?.enabled) { + const instance = { instanceName: this.instance.name, instanceId: this.instance.id }; + + const findParticipant = await this.chatwootService.findContact( + instance, + contact.remoteJid.split('@')[0], + ); + + if (!findParticipant) { + return; + } + + this.chatwootService.updateContact(instance, findParticipant.id, { + name: contact.pushName, + avatar_url: contact.profilePicUrl, + }); + } + + return update; + }), + ); + } + } catch (error) { + console.error(error); + this.logger.error(`Error: ${error.message}`); + } + }, + + 'contacts.update': async (contacts: Partial[]) => { + const contactsRaw: { + remoteJid: string; + pushName?: string; + profilePicUrl?: string; + instanceId: string; + }[] = []; + for await (const contact of contacts) { + contactsRaw.push({ + remoteJid: contact.id, + pushName: contact?.name ?? contact?.verifiedName, + profilePicUrl: (await this.profilePicture(contact.id)).profilePictureUrl, + instanceId: this.instanceId, + }); + } + + this.sendDataWebhook(Events.CONTACTS_UPDATE, contactsRaw); + + const updateTransactions = contactsRaw.map((contact) => + this.prismaRepository.contact.upsert({ + where: { remoteJid_instanceId: { remoteJid: contact.remoteJid, instanceId: contact.instanceId } }, + create: contact, + update: contact, + }), + ); + await this.prismaRepository.$transaction(updateTransactions); + + const usersContacts = contactsRaw.filter((c) => c.remoteJid.includes('@s.whatsapp')); + if (usersContacts) { + await saveOnWhatsappCache(usersContacts.map((c) => ({ remoteJid: c.remoteJid }))); + } + }, + }; + + private readonly messageHandle = { + 'messaging-history.set': async ({ + messages, + chats, + contacts, + isLatest, + progress, + syncType, + }: { + chats: Chat[]; + contacts: Contact[]; + messages: proto.IWebMessageInfo[]; + isLatest?: boolean; + progress?: number; + syncType?: proto.HistorySync.HistorySyncType; + }) => { + try { + if (syncType === proto.HistorySync.HistorySyncType.ON_DEMAND) { + console.log('received on-demand history sync, messages=', messages); + } + console.log( + `recv ${chats.length} chats, ${contacts.length} contacts, ${messages.length} msgs (is latest: ${isLatest}, progress: ${progress}%), type: ${syncType}`, + ); + + const instance: InstanceDto = { instanceName: this.instance.name }; + + let timestampLimitToImport = null; + + if (this.configService.get('CHATWOOT').ENABLED) { + const daysLimitToImport = this.localChatwoot?.enabled ? this.localChatwoot.daysLimitImportMessages : 1000; + + const date = new Date(); + timestampLimitToImport = new Date(date.setDate(date.getDate() - daysLimitToImport)).getTime() / 1000; + + const maxBatchTimestamp = Math.max(...messages.map((message) => message.messageTimestamp as number)); + + const processBatch = maxBatchTimestamp >= timestampLimitToImport; + + if (!processBatch) { + return; + } + } + + const chatsRaw: { remoteJid: string; instanceId: string; name?: string }[] = []; + const chatsRepository = new Set( + ( + await this.prismaRepository.chat.findMany({ + where: { instanceId: this.instanceId }, + }) + ).map((chat) => chat.remoteJid), + ); + + for (const chat of chats) { + if (chatsRepository?.has(chat.id)) { + continue; + } + + chatsRaw.push({ + remoteJid: chat.id, + instanceId: this.instanceId, + name: chat.name, + }); + } + + this.sendDataWebhook(Events.CHATS_SET, chatsRaw); + + if (this.configService.get('DATABASE').SAVE_DATA.HISTORIC) { + await this.prismaRepository.chat.createMany({ + data: chatsRaw, + skipDuplicates: true, + }); + } + + const messagesRaw: any[] = []; + + const messagesRepository: Set = new Set( + chatwootImport.getRepositoryMessagesCache(instance) ?? + ( + await this.prismaRepository.message.findMany({ + select: { key: true }, + where: { instanceId: this.instanceId }, + }) + ).map((message) => { + const key = message.key as { + id: string; + }; + + return key.id; + }), + ); + + if (chatwootImport.getRepositoryMessagesCache(instance) === null) { + chatwootImport.setRepositoryMessagesCache(instance, messagesRepository); + } + + for (const m of messages) { + if (!m.message || !m.key || !m.messageTimestamp) { + continue; + } + + if (Long.isLong(m?.messageTimestamp)) { + m.messageTimestamp = m.messageTimestamp?.toNumber(); + } + + if (this.configService.get('CHATWOOT').ENABLED) { + if (m.messageTimestamp <= timestampLimitToImport) { + continue; + } + } + + if (messagesRepository?.has(m.key.id)) { + continue; + } + + messagesRaw.push(this.prepareMessage(m)); + } + + this.sendDataWebhook(Events.MESSAGES_SET, [...messagesRaw]); + + if (this.configService.get('DATABASE').SAVE_DATA.HISTORIC) { + await this.prismaRepository.message.createMany({ + data: messagesRaw, + skipDuplicates: true, + }); + } + + if ( + this.configService.get('CHATWOOT').ENABLED && + this.localChatwoot?.enabled && + this.localChatwoot.importMessages && + messagesRaw.length > 0 + ) { + this.chatwootService.addHistoryMessages( + instance, + messagesRaw.filter((msg) => !chatwootImport.isIgnorePhoneNumber(msg.key?.remoteJid)), + ); + } + + await this.contactHandle['contacts.upsert']( + contacts + .filter((c) => !!c.notify || !!c.name) + .map((c) => ({ + id: c.id, + name: c.name ?? c.notify, + })), + ); + + contacts = undefined; + messages = undefined; + chats = undefined; + } catch (error) { + this.logger.error(error); + } + }, + + 'messages.upsert': async ( + { + messages, + type, + requestId, + }: { + messages: proto.IWebMessageInfo[]; + type: MessageUpsertType; + requestId?: string; + }, + settings: any, + ) => { + try { + for (const received of messages) { + if (received.message?.conversation || received.message?.extendedTextMessage?.text) { + const text = received.message?.conversation || received.message?.extendedTextMessage?.text; + + if (text == 'requestPlaceholder' && !requestId) { + const messageId = await this.client.requestPlaceholderResend(received.key); + + console.log('requested placeholder resync, id=', messageId); + } else if (requestId) { + console.log('Message received from phone, id=', requestId, received); + } + + if (text == 'onDemandHistSync') { + const messageId = await this.client.fetchMessageHistory(50, received.key, received.messageTimestamp!); + console.log('requested on-demand sync, id=', messageId); + } + } + + if (received.message?.protocolMessage?.editedMessage || received.message?.editedMessage?.message) { + const editedMessage = + received.message?.protocolMessage || received.message?.editedMessage?.message?.protocolMessage; + if (editedMessage) { + if (this.configService.get('CHATWOOT').ENABLED && this.localChatwoot?.enabled) + this.chatwootService.eventWhatsapp( + 'messages.edit', + { instanceName: this.instance.name, instanceId: this.instance.id }, + editedMessage, + ); + + await this.sendDataWebhook(Events.MESSAGES_EDITED, editedMessage); + } + } + + if (received.messageStubParameters && received.messageStubParameters[0] === 'Message absent from node') { + this.logger.info(`Recovering message lost messageId: ${received.key.id}`); + + await this.baileysCache.set(received.key.id, { + message: received, + retry: 0, + }); + + continue; + } + + const retryCache = (await this.baileysCache.get(received.key.id)) || null; + + if (retryCache) { + this.logger.info('Recovered message lost'); + await this.baileysCache.delete(received.key.id); + } + + if ( + (type !== 'notify' && type !== 'append') || + received.message?.protocolMessage || + received.message?.pollUpdateMessage || + !received?.message + ) { + continue; + } + + if (Long.isLong(received.messageTimestamp)) { + received.messageTimestamp = received.messageTimestamp?.toNumber(); + } + + if (settings?.groupsIgnore && received.key.remoteJid.includes('@g.us')) { + continue; + } + const existingChat = await this.prismaRepository.chat.findFirst({ + where: { instanceId: this.instanceId, remoteJid: received.key.remoteJid }, + select: { id: true, name: true }, + }); + + if ( + existingChat && + received.pushName && + existingChat.name !== received.pushName && + received.pushName.trim().length > 0 + ) { + this.sendDataWebhook(Events.CHATS_UPSERT, [{ ...existingChat, name: received.pushName }]); + if (this.configService.get('DATABASE').SAVE_DATA.CHATS) { + try { + await this.prismaRepository.chat.update({ + where: { id: existingChat.id }, + data: { name: received.pushName }, + }); + } catch (error) { + console.log(`Chat insert record ignored: ${received.key.remoteJid} - ${this.instanceId}`); + } + } + } + + const messageRaw = this.prepareMessage(received); + + const isMedia = + received?.message?.imageMessage || + received?.message?.videoMessage || + received?.message?.stickerMessage || + received?.message?.documentMessage || + received?.message?.documentWithCaptionMessage || + received?.message?.ptvMessage || + received?.message?.audioMessage; + + if (this.localSettings.readMessages && received.key.id !== 'status@broadcast') { + await this.client.readMessages([received.key]); + } + + if (this.localSettings.readStatus && received.key.id === 'status@broadcast') { + await this.client.readMessages([received.key]); + } + + if ( + this.configService.get('CHATWOOT').ENABLED && + this.localChatwoot?.enabled && + !received.key.id.includes('@broadcast') + ) { + const chatwootSentMessage = await this.chatwootService.eventWhatsapp( + Events.MESSAGES_UPSERT, + { instanceName: this.instance.name, instanceId: this.instance.id }, + messageRaw, + ); + + if (chatwootSentMessage?.id) { + messageRaw.chatwootMessageId = chatwootSentMessage.id; + messageRaw.chatwootInboxId = chatwootSentMessage.inbox_id; + messageRaw.chatwootConversationId = chatwootSentMessage.conversation_id; + } + } + + if (this.configService.get('OPENAI').ENABLED && received?.message?.audioMessage) { + const openAiDefaultSettings = await this.prismaRepository.openaiSetting.findFirst({ + where: { + instanceId: this.instanceId, + }, + include: { + OpenaiCreds: true, + }, + }); + + if (openAiDefaultSettings && openAiDefaultSettings.openaiCredsId && openAiDefaultSettings.speechToText) { + messageRaw.message.speechToText = await this.openaiService.speechToText( + openAiDefaultSettings.OpenaiCreds, + received, + this.client.updateMediaMessage, + ); + } + } + + if (this.configService.get('DATABASE').SAVE_DATA.NEW_MESSAGE) { + const msg = await this.prismaRepository.message.create({ + data: messageRaw, + }); + + if (received.key.fromMe === false) { + if (msg.status === status[3]) { + this.logger.log(`Update not read messages ${received.key.remoteJid}`); + + await this.updateChatUnreadMessages(received.key.remoteJid); + } else if (msg.status === status[4]) { + this.logger.log(`Update readed messages ${received.key.remoteJid} - ${msg.messageTimestamp}`); + + await this.updateMessagesReadedByTimestamp(received.key.remoteJid, msg.messageTimestamp); + } + } else { + // is send message by me + this.logger.log(`Update readed messages ${received.key.remoteJid} - ${msg.messageTimestamp}`); + + await this.updateMessagesReadedByTimestamp(received.key.remoteJid, msg.messageTimestamp); + } + + if (isMedia) { + if (this.configService.get('S3').ENABLE) { + try { + const message: any = received; + const media = await this.getBase64FromMediaMessage( + { + message, + }, + true, + ); + + const { buffer, mediaType, fileName, size } = media; + const mimetype = mimeTypes.lookup(fileName).toString(); + const fullName = join(`${this.instance.id}`, received.key.remoteJid, mediaType, fileName); + await s3Service.uploadFile(fullName, buffer, size.fileLength?.low, { + 'Content-Type': mimetype, + }); + + await this.prismaRepository.media.create({ + data: { + messageId: msg.id, + instanceId: this.instanceId, + type: mediaType, + fileName: fullName, + mimetype, + }, + }); + + const mediaUrl = await s3Service.getObjectUrl(fullName); + + messageRaw.message.mediaUrl = mediaUrl; + + await this.prismaRepository.message.update({ + where: { id: msg.id }, + data: messageRaw, + }); + } catch (error) { + this.logger.error(['Error on upload file to minio', error?.message, error?.stack]); + } + } + } + } + + if (this.localWebhook.enabled) { + if (isMedia && this.localWebhook.webhookBase64) { + try { + const buffer = await downloadMediaMessage( + { key: received.key, message: received?.message }, + 'buffer', + {}, + { + logger: P({ level: 'error' }) as any, + reuploadRequest: this.client.updateMediaMessage, + }, + ); + + messageRaw.message.base64 = buffer ? buffer.toString('base64') : undefined; + } catch (error) { + this.logger.error(['Error converting media to base64', error?.message]); + } + } + } + + this.logger.log(messageRaw); + + this.sendDataWebhook(Events.MESSAGES_UPSERT, messageRaw); + + await chatbotController.emit({ + instance: { instanceName: this.instance.name, instanceId: this.instanceId }, + remoteJid: messageRaw.key.remoteJid, + msg: messageRaw, + pushName: messageRaw.pushName, + }); + + const contact = await this.prismaRepository.contact.findFirst({ + where: { remoteJid: received.key.remoteJid, instanceId: this.instanceId }, + }); + + const contactRaw: { remoteJid: string; pushName: string; profilePicUrl?: string; instanceId: string } = { + remoteJid: received.key.remoteJid, + pushName: received.key.fromMe ? '' : received.key.fromMe == null ? '' : received.pushName, + profilePicUrl: (await this.profilePicture(received.key.remoteJid)).profilePictureUrl, + instanceId: this.instanceId, + }; + + if (contactRaw.remoteJid === 'status@broadcast') { + continue; + } + + if (contact) { + this.sendDataWebhook(Events.CONTACTS_UPDATE, contactRaw); + + if (this.configService.get('CHATWOOT').ENABLED && this.localChatwoot?.enabled) { + await this.chatwootService.eventWhatsapp( + Events.CONTACTS_UPDATE, + { instanceName: this.instance.name, instanceId: this.instanceId }, + contactRaw, + ); + } + + if (this.configService.get('DATABASE').SAVE_DATA.CONTACTS) + await this.prismaRepository.contact.upsert({ + where: { remoteJid_instanceId: { remoteJid: contactRaw.remoteJid, instanceId: contactRaw.instanceId } }, + create: contactRaw, + update: contactRaw, + }); + + continue; + } + + this.sendDataWebhook(Events.CONTACTS_UPSERT, contactRaw); + + if (this.configService.get('DATABASE').SAVE_DATA.CONTACTS) + await this.prismaRepository.contact.upsert({ + where: { + remoteJid_instanceId: { + remoteJid: contactRaw.remoteJid, + instanceId: contactRaw.instanceId, + }, + }, + update: contactRaw, + create: contactRaw, + }); + + if (contactRaw.remoteJid.includes('@s.whatsapp')) { + await saveOnWhatsappCache([{ remoteJid: contactRaw.remoteJid }]); + } + } + } catch (error) { + this.logger.error(error); + } + }, + + 'messages.update': async (args: WAMessageUpdate[], settings: any) => { + this.logger.log(`Update messages ${JSON.stringify(args, undefined, 2)}`); + + const readChatToUpdate: Record = {}; // {remoteJid: true} + + for await (const { key, update } of args) { + if (settings?.groupsIgnore && key.remoteJid?.includes('@g.us')) { + continue; + } + + if (status[update.status] === 'READ' && key.fromMe) { + if (this.configService.get('CHATWOOT').ENABLED && this.localChatwoot?.enabled) { + this.chatwootService.eventWhatsapp( + 'messages.read', + { instanceName: this.instance.name, instanceId: this.instanceId }, + { key: key }, + ); + } + } + + if (key.remoteJid !== 'status@broadcast') { + let pollUpdates: any; + + if (update.pollUpdates) { + const pollCreation = await this.getMessage(key); + + if (pollCreation) { + pollUpdates = getAggregateVotesInPollMessage({ + message: pollCreation as proto.IMessage, + pollUpdates: update.pollUpdates, + }); + } + } + + const findMessage = await this.prismaRepository.message.findFirst({ + where: { + instanceId: this.instanceId, + key: { + path: ['id'], + equals: key.id, + }, + }, + }); + + if (!findMessage) { + continue; + } + + if (update.message === null && update.status === undefined) { + this.sendDataWebhook(Events.MESSAGES_DELETE, key); + + const message: any = { + messageId: findMessage.id, + keyId: key.id, + remoteJid: key.remoteJid, + fromMe: key.fromMe, + participant: key?.remoteJid, + status: 'DELETED', + instanceId: this.instanceId, + }; + + if (this.configService.get('DATABASE').SAVE_DATA.MESSAGE_UPDATE) + await this.prismaRepository.messageUpdate.create({ + data: message, + }); + + if (this.configService.get('CHATWOOT').ENABLED && this.localChatwoot?.enabled) { + this.chatwootService.eventWhatsapp( + Events.MESSAGES_DELETE, + { instanceName: this.instance.name, instanceId: this.instanceId }, + { key: key }, + ); + } + + continue; + } else if (update.status !== undefined && status[update.status] !== findMessage.status) { + if (!key.fromMe && key.remoteJid) { + readChatToUpdate[key.remoteJid] = true; + + if (status[update.status] === status[4]) { + this.logger.log(`Update as read ${key.remoteJid} - ${findMessage.messageTimestamp}`); + this.updateMessagesReadedByTimestamp(key.remoteJid, findMessage.messageTimestamp); + } + } + + await this.prismaRepository.message.update({ + where: { id: findMessage.id }, + data: { status: status[update.status] }, + }); + } + + const message: any = { + messageId: findMessage.id, + keyId: key.id, + remoteJid: key.remoteJid, + fromMe: key.fromMe, + participant: key?.remoteJid, + status: status[update.status], + pollUpdates, + instanceId: this.instanceId, + }; + + this.sendDataWebhook(Events.MESSAGES_UPDATE, message); + + if (this.configService.get('DATABASE').SAVE_DATA.MESSAGE_UPDATE) + await this.prismaRepository.messageUpdate.create({ + data: message, + }); + + const existingChat = await this.prismaRepository.chat.findFirst({ + where: { instanceId: this.instanceId, remoteJid: message.remoteJid }, + }); + + if (existingChat) { + const chatToInsert = { + remoteJid: message.remoteJid, + instanceId: this.instanceId, + name: message.pushName || '', + unreadMessages: 0, + }; + + this.sendDataWebhook(Events.CHATS_UPSERT, [chatToInsert]); + if (this.configService.get('DATABASE').SAVE_DATA.CHATS) { + try { + await this.prismaRepository.chat.update({ + where: { + id: existingChat.id, + }, + data: chatToInsert, + }); + } catch (error) { + console.log(`Chat insert record ignored: ${chatToInsert.remoteJid} - ${chatToInsert.instanceId}`); + } + } + } + } + } + + await Promise.all(Object.keys(readChatToUpdate).map((remoteJid) => this.updateChatUnreadMessages(remoteJid))); + }, + }; + + private readonly groupHandler = { + 'groups.upsert': (groupMetadata: GroupMetadata[]) => { + this.sendDataWebhook(Events.GROUPS_UPSERT, groupMetadata); + }, + + 'groups.update': (groupMetadataUpdate: Partial[]) => { + this.sendDataWebhook(Events.GROUPS_UPDATE, groupMetadataUpdate); + + groupMetadataUpdate.forEach((group) => { + if (isJidGroup(group.id)) { + this.updateGroupMetadataCache(group.id); + } + }); + }, + + 'group-participants.update': (participantsUpdate: { + id: string; + participants: string[]; + action: ParticipantAction; + }) => { + this.sendDataWebhook(Events.GROUP_PARTICIPANTS_UPDATE, participantsUpdate); + + this.updateGroupMetadataCache(participantsUpdate.id); + }, + }; + + private readonly labelHandle = { + [Events.LABELS_EDIT]: async (label: Label) => { + this.sendDataWebhook(Events.LABELS_EDIT, { ...label, instance: this.instance.name }); + + const labelsRepository = await this.prismaRepository.label.findMany({ + where: { instanceId: this.instanceId }, + }); + + const savedLabel = labelsRepository.find((l) => l.labelId === label.id); + if (label.deleted && savedLabel) { + await this.prismaRepository.label.delete({ + where: { labelId_instanceId: { instanceId: this.instanceId, labelId: label.id } }, + }); + this.sendDataWebhook(Events.LABELS_EDIT, { ...label, instance: this.instance.name }); + return; + } + + const labelName = label.name.replace(/[^\x20-\x7E]/g, ''); + if (!savedLabel || savedLabel.color !== `${label.color}` || savedLabel.name !== labelName) { + if (this.configService.get('DATABASE').SAVE_DATA.LABELS) { + const labelData = { + color: `${label.color}`, + name: labelName, + labelId: label.id, + predefinedId: label.predefinedId, + instanceId: this.instanceId, + }; + await this.prismaRepository.label.upsert({ + where: { + labelId_instanceId: { + instanceId: labelData.instanceId, + labelId: labelData.labelId, + }, + }, + update: labelData, + create: labelData, + }); + } + } + }, + + [Events.LABELS_ASSOCIATION]: async ( + data: { association: LabelAssociation; type: 'remove' | 'add' }, + database: Database, + ) => { + this.logger.info( + `labels association - ${data?.association?.chatId} (${data.type}-${data?.association?.type}): ${data?.association?.labelId}`, + ); + if (database.SAVE_DATA.CHATS) { + const instanceId = this.instanceId; + const chatId = data.association.chatId; + const labelId = data.association.labelId; + + if (data.type === 'add') { + await this.addLabel(labelId, instanceId, chatId); + } else if (data.type === 'remove') { + await this.removeLabel(labelId, instanceId, chatId); + } + } + + this.sendDataWebhook(Events.LABELS_ASSOCIATION, { + instance: this.instance.name, + type: data.type, + chatId: data.association.chatId, + labelId: data.association.labelId, + }); + }, + }; + + private eventHandler() { + this.client.ev.process(async (events) => { + if (!this.endSession) { + const database = this.configService.get('DATABASE'); + const settings = await this.findSettings(); + + if (events.call) { + const call = events.call[0]; + + if (settings?.rejectCall && call.status == 'offer') { + this.client.rejectCall(call.id, call.from); + } + + if (settings?.msgCall?.trim().length > 0 && call.status == 'offer') { + const msg = await this.client.sendMessage(call.from, { + text: settings.msgCall, + }); + + this.client.ev.emit('messages.upsert', { + messages: [msg], + type: 'notify', + }); + } + + this.sendDataWebhook(Events.CALL, call); + } + + if (events['connection.update']) { + this.connectionUpdate(events['connection.update']); + } + + if (events['creds.update']) { + this.instance.authState.saveCreds(); + } + + if (events['messaging-history.set']) { + const payload = events['messaging-history.set']; + this.messageHandle['messaging-history.set'](payload); + } + + if (events['messages.upsert']) { + const payload = events['messages.upsert']; + this.messageHandle['messages.upsert'](payload, settings); + } + + if (events['messages.update']) { + const payload = events['messages.update']; + this.messageHandle['messages.update'](payload, settings); + } + + if (events['message-receipt.update']) { + const payload = events['message-receipt.update'] as MessageUserReceiptUpdate[]; + const remotesJidMap: Record = {}; + + for (const event of payload) { + if (typeof event.key.remoteJid === 'string' && typeof event.receipt.readTimestamp === 'number') { + remotesJidMap[event.key.remoteJid] = event.receipt.readTimestamp; + } + } + + await Promise.all( + Object.keys(remotesJidMap).map(async (remoteJid) => + this.updateMessagesReadedByTimestamp(remoteJid, remotesJidMap[remoteJid]), + ), + ); + } + + if (events['presence.update']) { + const payload = events['presence.update']; + + if (settings?.groupsIgnore && payload.id.includes('@g.us')) { + return; + } + + this.sendDataWebhook(Events.PRESENCE_UPDATE, payload); + } + + if (!settings?.groupsIgnore) { + if (events['groups.upsert']) { + const payload = events['groups.upsert']; + this.groupHandler['groups.upsert'](payload); + } + + if (events['groups.update']) { + const payload = events['groups.update']; + this.groupHandler['groups.update'](payload); + } + + if (events['group-participants.update']) { + const payload = events['group-participants.update']; + this.groupHandler['group-participants.update'](payload); + } + } + + if (events['chats.upsert']) { + const payload = events['chats.upsert']; + this.chatHandle['chats.upsert'](payload); + } + + if (events['chats.update']) { + const payload = events['chats.update']; + this.chatHandle['chats.update'](payload); + } + + if (events['chats.delete']) { + const payload = events['chats.delete']; + this.chatHandle['chats.delete'](payload); + } + + if (events['contacts.upsert']) { + const payload = events['contacts.upsert']; + this.contactHandle['contacts.upsert'](payload); + } + + if (events['contacts.update']) { + const payload = events['contacts.update']; + this.contactHandle['contacts.update'](payload); + } + + if (events[Events.LABELS_ASSOCIATION]) { + const payload = events[Events.LABELS_ASSOCIATION]; + this.labelHandle[Events.LABELS_ASSOCIATION](payload, database); + return; + } + + if (events[Events.LABELS_EDIT]) { + const payload = events[Events.LABELS_EDIT]; + this.labelHandle[Events.LABELS_EDIT](payload); + return; + } + } + }); + } + + private historySyncNotification(msg: proto.Message.IHistorySyncNotification) { + const instance: InstanceDto = { instanceName: this.instance.name }; + + if ( + this.configService.get('CHATWOOT').ENABLED && + this.localChatwoot?.enabled && + this.localChatwoot.importMessages && + this.isSyncNotificationFromUsedSyncType(msg) + ) { + if (msg.chunkOrder === 1) { + this.chatwootService.startImportHistoryMessages(instance); + } + + if (msg.progress === 100) { + setTimeout(() => { + this.chatwootService.importHistoryMessages(instance); + }, 10000); + } + } + + return true; + } + + private isSyncNotificationFromUsedSyncType(msg: proto.Message.IHistorySyncNotification) { + return ( + (this.localSettings.syncFullHistory && msg?.syncType === 2) || + (!this.localSettings.syncFullHistory && msg?.syncType === 3) + ); + } + + public async profilePicture(number: string) { + const jid = createJid(number); + + try { + const profilePictureUrl = await this.client.profilePictureUrl(jid, 'image'); + + return { + wuid: jid, + profilePictureUrl, + }; + } catch (error) { + return { + wuid: jid, + profilePictureUrl: null, + }; + } + } + + public async getStatus(number: string) { + const jid = createJid(number); + + try { + return { + wuid: jid, + status: (await this.client.fetchStatus(jid))[0]?.status, + }; + } catch (error) { + return { + wuid: jid, + status: null, + }; + } + } + + public async fetchProfile(instanceName: string, number?: string) { + const jid = number ? createJid(number) : this.client?.user?.id; + + const onWhatsapp = (await this.whatsappNumber({ numbers: [jid] }))?.shift(); + + if (!onWhatsapp.exists) { + throw new BadRequestException(onWhatsapp); + } + + try { + if (number) { + const info = (await this.whatsappNumber({ numbers: [jid] }))?.shift(); + const picture = await this.profilePicture(info?.jid); + const status = await this.getStatus(info?.jid); + const business = await this.fetchBusinessProfile(info?.jid); + + return { + wuid: info?.jid || jid, + name: info?.name, + numberExists: info?.exists, + picture: picture?.profilePictureUrl, + status: status?.status, + isBusiness: business.isBusiness, + email: business?.email, + description: business?.description, + website: business?.website?.shift(), + }; + } else { + const instanceNames = instanceName ? [instanceName] : null; + const info: Instance = await waMonitor.instanceInfo(instanceNames); + const business = await this.fetchBusinessProfile(jid); + + return { + wuid: jid, + name: info?.profileName, + numberExists: true, + picture: info?.profilePicUrl, + status: info?.connectionStatus, + isBusiness: business.isBusiness, + email: business?.email, + description: business?.description, + website: business?.website?.shift(), + }; + } + } catch (error) { + return { + wuid: jid, + name: null, + picture: null, + status: null, + os: null, + isBusiness: false, + }; + } + } + + public async offerCall({ number, isVideo, callDuration }: OfferCallDto) { + const jid = createJid(number); + + try { + const call = await this.client.offerCall(jid, isVideo); + setTimeout(() => this.client.terminateCall(call.id, call.to), callDuration * 1000); + + return call; + } catch (error) { + return error; + } + } + + private async sendMessage( + sender: string, + message: any, + mentions: any, + linkPreview: any, + quoted: any, + messageId?: string, + ephemeralExpiration?: number, + // participants?: GroupParticipant[], + ) { + sender = sender.toLowerCase(); + + const option: any = { + quoted, + }; + + if (isJidGroup(sender)) { + option.useCachedGroupMetadata = true; + // if (participants) + // option.cachedGroupMetadata = async () => { + // return { participants: participants as GroupParticipant[] }; + // }; + } + + if (ephemeralExpiration) option.ephemeralExpiration = ephemeralExpiration; + + if (messageId) option.messageId = messageId; + else option.messageId = '3EB0' + randomBytes(18).toString('hex').toUpperCase(); + + if (message['viewOnceMessage']) { + const m = generateWAMessageFromContent(sender, message, { + timestamp: new Date(), + userJid: this.instance.wuid, + messageId, + quoted, + }); + const id = await this.client.relayMessage(sender, message, { messageId }); + m.key = { + id: id, + remoteJid: sender, + participant: isJidUser(sender) ? sender : undefined, + fromMe: true, + }; + for (const [key, value] of Object.entries(m)) { + if (!value || (isArray(value) && value.length) === 0) { + delete m[key]; + } + } + return m; + } + + if ( + !message['audio'] && + !message['poll'] && + !message['sticker'] && + !message['conversation'] && + sender !== 'status@broadcast' + ) { + if (message['reactionMessage']) { + return await this.client.sendMessage( + sender, + { + react: { + text: message['reactionMessage']['text'], + key: message['reactionMessage']['key'], + }, + } as unknown as AnyMessageContent, + option as unknown as MiscMessageGenerationOptions, + ); + } + } + + if (message['conversation']) { + return await this.client.sendMessage( + sender, + { + text: message['conversation'], + mentions, + linkPreview: linkPreview, + } as unknown as AnyMessageContent, + option as unknown as MiscMessageGenerationOptions, + ); + } + + if (!message['audio'] && !message['poll'] && !message['sticker'] && sender != 'status@broadcast') { + return await this.client.sendMessage( + sender, + { + forward: { + key: { remoteJid: this.instance.wuid, fromMe: true }, + message, + }, + mentions, + }, + option as unknown as MiscMessageGenerationOptions, + ); + } + + if (sender === 'status@broadcast') { + let jidList; + if (message['status'].option.allContacts) { + const contacts = await this.prismaRepository.contact.findMany({ + where: { + instanceId: this.instanceId, + remoteJid: { + not: { + endsWith: '@g.us', + }, + }, + }, + }); + + jidList = contacts.map((contact) => contact.remoteJid); + } else { + jidList = message['status'].option.statusJidList; + } + + const batchSize = 10; + + const batches = Array.from({ length: Math.ceil(jidList.length / batchSize) }, (_, i) => + jidList.slice(i * batchSize, i * batchSize + batchSize), + ); + + let msgId: string | null = null; + + let firstMessage: WAMessage; + + const firstBatch = batches.shift(); + + if (firstBatch) { + firstMessage = await this.client.sendMessage( + sender, + message['status'].content as unknown as AnyMessageContent, + { + backgroundColor: message['status'].option.backgroundColor, + font: message['status'].option.font, + statusJidList: firstBatch, + } as unknown as MiscMessageGenerationOptions, + ); + + msgId = firstMessage.key.id; + } + + if (batches.length === 0) return firstMessage; + + await Promise.allSettled( + batches.map(async (batch) => { + const messageSent = await this.client.sendMessage( + sender, + message['status'].content as unknown as AnyMessageContent, + { + backgroundColor: message['status'].option.backgroundColor, + font: message['status'].option.font, + statusJidList: batch, + messageId: msgId, + } as unknown as MiscMessageGenerationOptions, + ); + + return messageSent; + }), + ); + + return firstMessage; + } + + return await this.client.sendMessage( + sender, + message as unknown as AnyMessageContent, + option as unknown as MiscMessageGenerationOptions, + ); + } + + private async sendMessageWithTyping( + number: string, + message: T, + options?: Options, + isIntegration = false, + ) { + const isWA = (await this.whatsappNumber({ numbers: [number] }))?.shift(); + + if (!isWA.exists && !isJidGroup(isWA.jid) && !isWA.jid.includes('@broadcast')) { + throw new BadRequestException(isWA); + } + + const sender = isWA.jid.toLowerCase(); + + this.logger.verbose(`Sending message to ${sender}`); + + try { + if (options?.delay) { + this.logger.verbose(`Typing for ${options.delay}ms to ${sender}`); + if (options.delay > 20000) { + let remainingDelay = options.delay; + while (remainingDelay > 20000) { + await this.client.presenceSubscribe(sender); + + await this.client.sendPresenceUpdate((options.presence as WAPresence) ?? 'composing', sender); + + await delay(20000); + + await this.client.sendPresenceUpdate('paused', sender); + + remainingDelay -= 20000; + } + if (remainingDelay > 0) { + await this.client.presenceSubscribe(sender); + + await this.client.sendPresenceUpdate((options.presence as WAPresence) ?? 'composing', sender); + + await delay(remainingDelay); + + await this.client.sendPresenceUpdate('paused', sender); + } + } else { + await this.client.presenceSubscribe(sender); + + await this.client.sendPresenceUpdate((options.presence as WAPresence) ?? 'composing', sender); + + await delay(options.delay); + + await this.client.sendPresenceUpdate('paused', sender); + } + } + + const linkPreview = options?.linkPreview != false ? undefined : false; + + let quoted: WAMessage; + + if (options?.quoted) { + const m = options?.quoted; + + const msg = m?.message ? m : ((await this.getMessage(m.key, true)) as proto.IWebMessageInfo); + + if (msg) { + quoted = msg; + } + } + + let messageSent: WAMessage; + + let mentions: string[]; + if (isJidGroup(sender)) { + let group; + try { + const cache = this.configService.get('CACHE'); + if (!cache.REDIS.ENABLED && !cache.LOCAL.ENABLED) group = await this.findGroup({ groupJid: sender }, 'inner'); + else group = await this.getGroupMetadataCache(sender); + // group = await this.findGroup({ groupJid: sender }, 'inner'); + } catch (error) { + throw new NotFoundException('Group not found'); + } + + if (!group) { + throw new NotFoundException('Group not found'); + } + + if (options?.mentionsEveryOne) { + mentions = group.participants.map((participant) => participant.id); + } else if (options?.mentioned?.length) { + mentions = options.mentioned.map((mention) => { + const jid = createJid(mention); + if (isJidGroup(jid)) { + return null; + } + return jid; + }); + } + + messageSent = await this.sendMessage( + sender, + message, + mentions, + linkPreview, + quoted, + null, + group?.ephemeralDuration, + // group?.participants, + ); + } else { + messageSent = await this.sendMessage(sender, message, mentions, linkPreview, quoted); + } + + if (Long.isLong(messageSent?.messageTimestamp)) { + messageSent.messageTimestamp = messageSent.messageTimestamp?.toNumber(); + } + + const messageRaw = this.prepareMessage(messageSent); + + const isMedia = + messageSent?.message?.imageMessage || + messageSent?.message?.videoMessage || + messageSent?.message?.stickerMessage || + messageSent?.message?.ptvMessage || + messageSent?.message?.documentMessage || + messageSent?.message?.documentWithCaptionMessage || + messageSent?.message?.ptvMessage || + messageSent?.message?.audioMessage; + + if (this.configService.get('CHATWOOT').ENABLED && this.localChatwoot?.enabled && !isIntegration) { + this.chatwootService.eventWhatsapp( + Events.SEND_MESSAGE, + { instanceName: this.instance.name, instanceId: this.instanceId }, + messageRaw, + ); + } + + if (this.configService.get('OPENAI').ENABLED && messageRaw?.message?.audioMessage) { + const openAiDefaultSettings = await this.prismaRepository.openaiSetting.findFirst({ + where: { + instanceId: this.instanceId, + }, + include: { + OpenaiCreds: true, + }, + }); + + if (openAiDefaultSettings && openAiDefaultSettings.openaiCredsId && openAiDefaultSettings.speechToText) { + messageRaw.message.speechToText = await this.openaiService.speechToText( + openAiDefaultSettings.OpenaiCreds, + messageRaw, + this.client.updateMediaMessage, + ); + } + } + + if (this.configService.get('DATABASE').SAVE_DATA.NEW_MESSAGE) { + const msg = await this.prismaRepository.message.create({ + data: messageRaw, + }); + + if (isMedia && this.configService.get('S3').ENABLE) { + try { + const message: any = messageRaw; + const media = await this.getBase64FromMediaMessage( + { + message, + }, + true, + ); + + const { buffer, mediaType, fileName, size } = media; + + const mimetype = mimeTypes.lookup(fileName).toString(); + + const fullName = join( + `${this.instance.id}`, + messageRaw.key.remoteJid, + `${messageRaw.key.id}`, + mediaType, + fileName, + ); + + await s3Service.uploadFile(fullName, buffer, size.fileLength?.low, { + 'Content-Type': mimetype, + }); + + await this.prismaRepository.media.create({ + data: { + messageId: msg.id, + instanceId: this.instanceId, + type: mediaType, + fileName: fullName, + mimetype, + }, + }); + + const mediaUrl = await s3Service.getObjectUrl(fullName); + + messageRaw.message.mediaUrl = mediaUrl; + + await this.prismaRepository.message.update({ + where: { id: msg.id }, + data: messageRaw, + }); + } catch (error) { + this.logger.error(['Error on upload file to minio', error?.message, error?.stack]); + } + } + } + + if (this.localWebhook.enabled) { + if (isMedia && this.localWebhook.webhookBase64) { + try { + const buffer = await downloadMediaMessage( + { key: messageRaw.key, message: messageRaw?.message }, + 'buffer', + {}, + { + logger: P({ level: 'error' }) as any, + reuploadRequest: this.client.updateMediaMessage, + }, + ); + + messageRaw.message.base64 = buffer ? buffer.toString('base64') : undefined; + } catch (error) { + this.logger.error(['Error converting media to base64', error?.message]); + } + } + } + + this.logger.log(messageRaw); + + this.sendDataWebhook(Events.SEND_MESSAGE, messageRaw); + + if (this.configService.get('CHATWOOT').ENABLED && this.localChatwoot?.enabled && isIntegration) { + await chatbotController.emit({ + instance: { instanceName: this.instance.name, instanceId: this.instanceId }, + remoteJid: messageRaw.key.remoteJid, + msg: messageRaw, + pushName: messageRaw.pushName, + isIntegration, + }); + } + + return messageRaw; + } catch (error) { + this.logger.error(error); + throw new BadRequestException(error.toString()); + } + } + + // Instance Controller + public async sendPresence(data: SendPresenceDto) { + try { + const { number } = data; + + const isWA = (await this.whatsappNumber({ numbers: [number] }))?.shift(); + + if (!isWA.exists && !isJidGroup(isWA.jid) && !isWA.jid.includes('@broadcast')) { + throw new BadRequestException(isWA); + } + + const sender = isWA.jid; + + if (data?.delay && data?.delay > 20000) { + let remainingDelay = data?.delay; + while (remainingDelay > 20000) { + await this.client.presenceSubscribe(sender); + + await this.client.sendPresenceUpdate((data?.presence as WAPresence) ?? 'composing', sender); + + await delay(20000); + + await this.client.sendPresenceUpdate('paused', sender); + + remainingDelay -= 20000; + } + if (remainingDelay > 0) { + await this.client.presenceSubscribe(sender); + + await this.client.sendPresenceUpdate((data?.presence as WAPresence) ?? 'composing', sender); + + await delay(remainingDelay); + + await this.client.sendPresenceUpdate('paused', sender); + } + } else { + await this.client.presenceSubscribe(sender); + + await this.client.sendPresenceUpdate((data?.presence as WAPresence) ?? 'composing', sender); + + await delay(data?.delay); + + await this.client.sendPresenceUpdate('paused', sender); + } + + return { presence: data.presence }; + } catch (error) { + this.logger.error(error); + throw new BadRequestException(error.toString()); + } + } + + // Presence Controller + public async setPresence(data: SetPresenceDto) { + try { + await this.client.sendPresenceUpdate(data.presence); + + return { presence: data.presence }; + } catch (error) { + this.logger.error(error); + throw new BadRequestException(error.toString()); + } + } + + // Send Message Controller + public async textMessage(data: SendTextDto, isIntegration = false) { + const text = data.text; + + if (!text || text.trim().length === 0) { + throw new BadRequestException('Text is required'); + } + + return await this.sendMessageWithTyping( + data.number, + { + conversation: data.text, + }, + { + delay: data?.delay, + presence: 'composing', + quoted: data?.quoted, + linkPreview: data?.linkPreview, + mentionsEveryOne: data?.mentionsEveryOne, + mentioned: data?.mentioned, + }, + isIntegration, + ); + } + + public async pollMessage(data: SendPollDto) { + return await this.sendMessageWithTyping( + data.number, + { + poll: { + name: data.name, + selectableCount: data.selectableCount, + values: data.values, + }, + }, + { + delay: data?.delay, + presence: 'composing', + quoted: data?.quoted, + linkPreview: data?.linkPreview, + mentionsEveryOne: data?.mentionsEveryOne, + mentioned: data?.mentioned, + }, + ); + } + + private async formatStatusMessage(status: StatusMessage) { + if (!status.type) { + throw new BadRequestException('Type is required'); + } + + if (!status.content) { + throw new BadRequestException('Content is required'); + } + + if (status.allContacts) { + const contacts = await this.prismaRepository.contact.findMany({ + where: { instanceId: this.instanceId }, + }); + + if (!contacts.length) { + throw new BadRequestException('Contacts not found'); + } + + status.statusJidList = contacts.filter((contact) => contact.pushName).map((contact) => contact.remoteJid); + } + + if (!status.statusJidList?.length && !status.allContacts) { + throw new BadRequestException('StatusJidList is required'); + } + + if (status.type === 'text') { + if (!status.backgroundColor) { + throw new BadRequestException('Background color is required'); + } + + if (!status.font) { + throw new BadRequestException('Font is required'); + } + + return { + content: { + text: status.content, + }, + option: { + backgroundColor: status.backgroundColor, + font: status.font, + statusJidList: status.statusJidList, + }, + }; + } + if (status.type === 'image') { + return { + content: { + image: { + url: status.content, + }, + caption: status.caption, + }, + option: { + statusJidList: status.statusJidList, + }, + }; + } + + if (status.type === 'video') { + return { + content: { + video: { + url: status.content, + }, + caption: status.caption, + }, + option: { + statusJidList: status.statusJidList, + }, + }; + } + + if (status.type === 'audio') { + const convert = await this.processAudioMp4(status.content); + if (Buffer.isBuffer(convert)) { + const result = { + content: { + audio: convert, + ptt: true, + mimetype: 'audio/ogg; codecs=opus', + }, + option: { + statusJidList: status.statusJidList, + }, + }; + + return result; + } else { + throw new InternalServerErrorException(convert); + } + } + + throw new BadRequestException('Type not found'); + } + + public async statusMessage(data: SendStatusDto, file?: any) { + const mediaData: SendStatusDto = { ...data }; + + if (file) mediaData.content = file.buffer.toString('base64'); + + const status = await this.formatStatusMessage(mediaData); + + const statusSent = await this.sendMessageWithTyping('status@broadcast', { + status, + }); + + return statusSent; + } + + private async prepareMediaMessage(mediaMessage: MediaMessage) { + try { + const type = mediaMessage.mediatype === 'ptv' ? 'video' : mediaMessage.mediatype; + + const prepareMedia = await prepareWAMessageMedia( + { + [type]: isURL(mediaMessage.media) ? { url: mediaMessage.media } : Buffer.from(mediaMessage.media, 'base64'), + } as any, + { upload: this.client.waUploadToServer }, + ); + + const mediaType = mediaMessage.mediatype + 'Message'; + + if (mediaMessage.mediatype === 'document' && !mediaMessage.fileName) { + const regex = new RegExp(/.*\/(.+?)\./); + const arrayMatch = regex.exec(mediaMessage.media); + mediaMessage.fileName = arrayMatch[1]; + } + + if (mediaMessage.mediatype === 'image' && !mediaMessage.fileName) { + mediaMessage.fileName = 'image.png'; + } + + if (mediaMessage.mediatype === 'video' && !mediaMessage.fileName) { + mediaMessage.fileName = 'video.mp4'; + } + + let mimetype: string | false; + + if (mediaMessage.mimetype) { + mimetype = mediaMessage.mimetype; + } else { + mimetype = mimeTypes.lookup(mediaMessage.fileName); + + if (!mimetype && isURL(mediaMessage.media)) { + let config: any = { + responseType: 'arraybuffer', + }; + + if (this.localProxy?.enabled) { + config = { + ...config, + httpsAgent: makeProxyAgent({ + host: this.localProxy.host, + port: this.localProxy.port, + protocol: this.localProxy.protocol, + username: this.localProxy.username, + password: this.localProxy.password, + }), + }; + } + + const response = await axios.get(mediaMessage.media, config); + + mimetype = response.headers['content-type']; + } + } + + if (mediaMessage.mediatype === 'ptv') { + prepareMedia[mediaType] = prepareMedia[type + 'Message']; + mimetype = 'video/mp4'; + + if (!prepareMedia[mediaType]) { + throw new Error('Failed to prepare video message'); + } + + try { + let mediaInput; + if (isURL(mediaMessage.media)) { + mediaInput = mediaMessage.media; + } else { + const mediaBuffer = Buffer.from(mediaMessage.media, 'base64'); + if (!mediaBuffer || mediaBuffer.length === 0) { + throw new Error('Invalid media buffer'); + } + mediaInput = mediaBuffer; + } + + const duration = await getVideoDuration(mediaInput); + if (!duration || duration <= 0) { + throw new Error('Invalid media duration'); + } + + this.logger.verbose(`Video duration: ${duration} seconds`); + prepareMedia[mediaType].seconds = duration; + } catch (error) { + this.logger.error('Error getting video duration:'); + this.logger.error(error); + throw new Error(`Failed to get video duration: ${error.message}`); + } + } + + prepareMedia[mediaType].caption = mediaMessage?.caption; + prepareMedia[mediaType].mimetype = mimetype; + prepareMedia[mediaType].fileName = mediaMessage.fileName; + + if (mediaMessage.mediatype === 'video') { + prepareMedia[mediaType].jpegThumbnail = Uint8Array.from( + readFileSync(join(process.cwd(), 'public', 'images', 'video-cover.png')), + ); + prepareMedia[mediaType].gifPlayback = false; + } + + return generateWAMessageFromContent( + '', + { [mediaType]: { ...prepareMedia[mediaType] } }, + { userJid: this.instance.wuid }, + ); + } catch (error) { + this.logger.error(error); + throw new InternalServerErrorException(error?.toString() || error); + } + } + + private async convertToWebP(image: string): Promise { + try { + let imageBuffer: Buffer; + + if (isBase64(image)) { + const base64Data = image.replace(/^data:image\/(jpeg|png|gif);base64,/, ''); + imageBuffer = Buffer.from(base64Data, 'base64'); + } else { + const timestamp = new Date().getTime(); + const url = `${image}?timestamp=${timestamp}`; + + let config: any = { + responseType: 'arraybuffer', + }; + + if (this.localProxy?.enabled) { + config = { + ...config, + httpsAgent: makeProxyAgent({ + host: this.localProxy.host, + port: this.localProxy.port, + protocol: this.localProxy.protocol, + username: this.localProxy.username, + password: this.localProxy.password, + }), + }; + } + + const response = await axios.get(url, config); + imageBuffer = Buffer.from(response.data, 'binary'); + } + + const webpBuffer = await sharp(imageBuffer).webp().toBuffer(); + + return webpBuffer; + } catch (error) { + console.error('Erro ao converter a imagem para WebP:', error); + throw error; + } + } + + public async mediaSticker(data: SendStickerDto, file?: any) { + const mediaData: SendStickerDto = { ...data }; + + if (file) mediaData.sticker = file.buffer.toString('base64'); + + const convert = await this.convertToWebP(data.sticker); + const gifPlayback = data.sticker.includes('.gif'); + const result = await this.sendMessageWithTyping( + data.number, + { + sticker: convert, + gifPlayback, + }, + { + delay: data?.delay, + presence: 'composing', + quoted: data?.quoted, + mentionsEveryOne: data?.mentionsEveryOne, + mentioned: data?.mentioned, + }, + ); + + return result; + } + + public async mediaMessage(data: SendMediaDto, file?: any, isIntegration = false) { + const mediaData: SendMediaDto = { ...data }; + + if (file) mediaData.media = file.buffer.toString('base64'); + + const generate = await this.prepareMediaMessage(mediaData); + + const mediaSent = await this.sendMessageWithTyping( + data.number, + { ...generate.message }, + { + delay: data?.delay, + presence: 'composing', + quoted: data?.quoted, + mentionsEveryOne: data?.mentionsEveryOne, + mentioned: data?.mentioned, + }, + isIntegration, + ); + + return mediaSent; + } + + public async ptvMessage(data: SendPtvDto, file?: any, isIntegration = false) { + const mediaData: SendMediaDto = { + number: data.number, + media: data.video, + mediatype: 'ptv', + delay: data?.delay, + quoted: data?.quoted, + mentionsEveryOne: data?.mentionsEveryOne, + mentioned: data?.mentioned, + }; + + if (file) mediaData.media = file.buffer.toString('base64'); + + const generate = await this.prepareMediaMessage(mediaData); + + const mediaSent = await this.sendMessageWithTyping( + data.number, + { ...generate.message }, + { + delay: data?.delay, + presence: 'composing', + quoted: data?.quoted, + mentionsEveryOne: data?.mentionsEveryOne, + mentioned: data?.mentioned, + }, + isIntegration, + ); + + return mediaSent; + } + + public async processAudioMp4(audio: string) { + let inputStream: PassThrough; + + if (isURL(audio)) { + const response = await axios.get(audio, { responseType: 'stream' }); + inputStream = response.data; + } else { + const audioBuffer = Buffer.from(audio, 'base64'); + inputStream = new PassThrough(); + inputStream.end(audioBuffer); + } + + return new Promise((resolve, reject) => { + const ffmpegProcess = spawn(ffmpegPath.path, [ + '-i', + 'pipe:0', + '-vn', + '-ab', + '128k', + '-ar', + '44100', + '-f', + 'mp4', + '-movflags', + 'frag_keyframe+empty_moov', + 'pipe:1', + ]); + + const outputChunks: Buffer[] = []; + let stderrData = ''; + + ffmpegProcess.stdout.on('data', (chunk) => { + outputChunks.push(chunk); + }); + + ffmpegProcess.stderr.on('data', (data) => { + stderrData += data.toString(); + this.logger.verbose(`ffmpeg stderr: ${data}`); + }); + + ffmpegProcess.on('error', (error) => { + console.error('Error in ffmpeg process', error); + reject(error); + }); + + ffmpegProcess.on('close', (code) => { + if (code === 0) { + this.logger.verbose('Audio converted to mp4'); + const outputBuffer = Buffer.concat(outputChunks); + resolve(outputBuffer); + } else { + this.logger.error(`ffmpeg exited with code ${code}`); + this.logger.error(`ffmpeg stderr: ${stderrData}`); + reject(new Error(`ffmpeg exited with code ${code}: ${stderrData}`)); + } + }); + + inputStream.pipe(ffmpegProcess.stdin); + + inputStream.on('error', (err) => { + console.error('Error in inputStream', err); + ffmpegProcess.stdin.end(); + reject(err); + }); + }); + } + + public async processAudio(audio: string): Promise { + if (process.env.API_AUDIO_CONVERTER) { + this.logger.verbose('Using audio converter API'); + const formData = new FormData(); + + if (isURL(audio)) { + formData.append('url', audio); + } else { + formData.append('base64', audio); + } + + const { data } = await axios.post(process.env.API_AUDIO_CONVERTER, formData, { + headers: { + ...formData.getHeaders(), + apikey: process.env.API_AUDIO_CONVERTER_KEY, + }, + }); + + if (!data.audio) { + throw new InternalServerErrorException('Failed to convert audio'); + } + + this.logger.verbose('Audio converted'); + return Buffer.from(data.audio, 'base64'); + } else { + let inputAudioStream: PassThrough; + + if (isURL(audio)) { + const timestamp = new Date().getTime(); + const url = `${audio}?timestamp=${timestamp}`; + + const config: any = { + responseType: 'stream', + }; + + const response = await axios.get(url, config); + inputAudioStream = response.data.pipe(new PassThrough()); + } else { + const audioBuffer = Buffer.from(audio, 'base64'); + inputAudioStream = new PassThrough(); + inputAudioStream.end(audioBuffer); + } + + return new Promise((resolve, reject) => { + const outputAudioStream = new PassThrough(); + const chunks: Buffer[] = []; + + outputAudioStream.on('data', (chunk) => chunks.push(chunk)); + outputAudioStream.on('end', () => { + const outputBuffer = Buffer.concat(chunks); + resolve(outputBuffer); + }); + + outputAudioStream.on('error', (error) => { + console.log('error', error); + reject(error); + }); + + ffmpeg.setFfmpegPath(ffmpegPath.path); + + ffmpeg(inputAudioStream) + .outputFormat('ogg') + .noVideo() + .audioCodec('libopus') + .addOutputOptions('-avoid_negative_ts make_zero') + .audioChannels(1) + .pipe(outputAudioStream, { end: true }) + .on('error', function (error) { + console.log('error', error); + reject(error); + }); + }); + } + } + + public async audioWhatsapp(data: SendAudioDto, file?: any, isIntegration = false) { + const mediaData: SendAudioDto = { ...data }; + + if (file?.buffer) { + mediaData.audio = file.buffer.toString('base64'); + } else if (!isURL(data.audio) && !isBase64(data.audio)) { + console.error('Invalid file or audio source'); + throw new BadRequestException('File buffer, URL, or base64 audio is required'); + } + + if (!data?.encoding && data?.encoding !== false) { + data.encoding = true; + } + + if (data?.encoding) { + const convert = await this.processAudio(mediaData.audio); + + if (Buffer.isBuffer(convert)) { + const result = this.sendMessageWithTyping( + data.number, + { + audio: convert, + ptt: true, + mimetype: 'audio/ogg; codecs=opus', + }, + { presence: 'recording', delay: data?.delay }, + isIntegration, + ); + + return result; + } else { + throw new InternalServerErrorException('Failed to convert audio'); + } + } + + return await this.sendMessageWithTyping( + data.number, + { + audio: isURL(data.audio) ? { url: data.audio } : Buffer.from(data.audio, 'base64'), + ptt: true, + mimetype: 'audio/ogg; codecs=opus', + }, + { presence: 'recording', delay: data?.delay }, + isIntegration, + ); + } + + private generateRandomId(length = 11) { + const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; + let result = ''; + for (let i = 0; i < length; i++) { + result += characters.charAt(Math.floor(Math.random() * characters.length)); + } + return result; + } + + private toJSONString(button: Button): string { + const toString = (obj: any) => JSON.stringify(obj); + + const json = { + call: () => toString({ display_text: button.displayText, phone_number: button.phoneNumber }), + reply: () => toString({ display_text: button.displayText, id: button.id }), + copy: () => toString({ display_text: button.displayText, copy_code: button.copyCode }), + url: () => + toString({ + display_text: button.displayText, + url: button.url, + merchant_url: button.url, + }), + pix: () => + toString({ + currency: button.currency, + total_amount: { + value: 0, + offset: 100, + }, + reference_id: this.generateRandomId(), + type: 'physical-goods', + order: { + status: 'pending', + subtotal: { + value: 0, + offset: 100, + }, + order_type: 'ORDER', + items: [ + { + name: '', + amount: { + value: 0, + offset: 100, + }, + quantity: 0, + sale_amount: { + value: 0, + offset: 100, + }, + }, + ], + }, + payment_settings: [ + { + type: 'pix_static_code', + pix_static_code: { + merchant_name: button.name, + key: button.key, + key_type: this.mapKeyType.get(button.keyType), + }, + }, + ], + share_payment_status: false, + }), + }; + + return json[button.type]?.() || ''; + } + + private readonly mapType = new Map([ + ['reply', 'quick_reply'], + ['copy', 'cta_copy'], + ['url', 'cta_url'], + ['call', 'cta_call'], + ['pix', 'payment_info'], + ]); + + private readonly mapKeyType = new Map([ + ['phone', 'PHONE'], + ['email', 'EMAIL'], + ['cpf', 'CPF'], + ['cnpj', 'CNPJ'], + ['random', 'EVP'], + ]); + + public async buttonMessage(data: SendButtonsDto) { + if (data.buttons.length === 0) { + throw new BadRequestException('At least one button is required'); + } + + const hasReplyButtons = data.buttons.some((btn) => btn.type === 'reply'); + + const hasPixButton = data.buttons.some((btn) => btn.type === 'pix'); + + const hasOtherButtons = data.buttons.some((btn) => btn.type !== 'reply' && btn.type !== 'pix'); + + if (hasReplyButtons) { + if (data.buttons.length > 3) { + throw new BadRequestException('Maximum of 3 reply buttons allowed'); + } + if (hasOtherButtons) { + throw new BadRequestException('Reply buttons cannot be mixed with other button types'); + } + } + + if (hasPixButton) { + if (data.buttons.length > 1) { + throw new BadRequestException('Only one PIX button is allowed'); + } + if (hasOtherButtons) { + throw new BadRequestException('PIX button cannot be mixed with other button types'); + } + + const message: proto.IMessage = { + viewOnceMessage: { + message: { + interactiveMessage: { + nativeFlowMessage: { + buttons: [ + { + name: this.mapType.get('pix'), + buttonParamsJson: this.toJSONString(data.buttons[0]), + }, + ], + messageParamsJson: JSON.stringify({ + from: 'api', + templateId: v4(), + }), + }, + }, + }, + }, + }; + + return await this.sendMessageWithTyping(data.number, message, { + delay: data?.delay, + presence: 'composing', + quoted: data?.quoted, + mentionsEveryOne: data?.mentionsEveryOne, + mentioned: data?.mentioned, + }); + } + + const generate = await (async () => { + if (data?.thumbnailUrl) { + return await this.prepareMediaMessage({ + mediatype: 'image', + media: data.thumbnailUrl, + }); + } + })(); + + const buttons = data.buttons.map((value) => { + return { + name: this.mapType.get(value.type), + buttonParamsJson: this.toJSONString(value), + }; + }); + + const message: proto.IMessage = { + viewOnceMessage: { + message: { + interactiveMessage: { + body: { + text: (() => { + let t = '*' + data.title + '*'; + if (data?.description) { + t += '\n\n'; + t += data.description; + t += '\n'; + } + return t; + })(), + }, + footer: { + text: data?.footer, + }, + header: (() => { + if (generate?.message?.imageMessage) { + return { + hasMediaAttachment: !!generate.message.imageMessage, + imageMessage: generate.message.imageMessage, + }; + } + })(), + nativeFlowMessage: { + buttons: buttons, + messageParamsJson: JSON.stringify({ + from: 'api', + templateId: v4(), + }), + }, + }, + }, + }, + }; + + return await this.sendMessageWithTyping(data.number, message, { + delay: data?.delay, + presence: 'composing', + quoted: data?.quoted, + mentionsEveryOne: data?.mentionsEveryOne, + mentioned: data?.mentioned, + }); + } + + public async locationMessage(data: SendLocationDto) { + return await this.sendMessageWithTyping( + data.number, + { + locationMessage: { + degreesLatitude: data.latitude, + degreesLongitude: data.longitude, + name: data?.name, + address: data?.address, + }, + }, + { + delay: data?.delay, + presence: 'composing', + quoted: data?.quoted, + mentionsEveryOne: data?.mentionsEveryOne, + mentioned: data?.mentioned, + }, + ); + } + + public async listMessage(data: SendListDto) { + return await this.sendMessageWithTyping( + data.number, + { + listMessage: { + title: data.title, + description: data.description, + buttonText: data?.buttonText, + footerText: data?.footerText, + sections: data.sections, + listType: 2, + }, + }, + { + delay: data?.delay, + presence: 'composing', + quoted: data?.quoted, + mentionsEveryOne: data?.mentionsEveryOne, + mentioned: data?.mentioned, + }, + ); + } + + public async contactMessage(data: SendContactDto) { + const message: proto.IMessage = {}; + + const vcard = (contact: ContactMessage) => { + let result = 'BEGIN:VCARD\n' + 'VERSION:3.0\n' + `N:${contact.fullName}\n` + `FN:${contact.fullName}\n`; + + if (contact.organization) { + result += `ORG:${contact.organization};\n`; + } + + if (contact.email) { + result += `EMAIL:${contact.email}\n`; + } + + if (contact.url) { + result += `URL:${contact.url}\n`; + } + + if (!contact.wuid) { + contact.wuid = createJid(contact.phoneNumber); + } + + result += `item1.TEL;waid=${contact.wuid}:${contact.phoneNumber}\n` + 'item1.X-ABLabel:Celular\n' + 'END:VCARD'; + + return result; + }; + + if (data.contact.length === 1) { + message.contactMessage = { + displayName: data.contact[0].fullName, + vcard: vcard(data.contact[0]), + }; + } else { + message.contactsArrayMessage = { + displayName: `${data.contact.length} contacts`, + contacts: data.contact.map((contact) => { + return { + displayName: contact.fullName, + vcard: vcard(contact), + }; + }), + }; + } + + return await this.sendMessageWithTyping(data.number, { ...message }, {}); + } + + public async reactionMessage(data: SendReactionDto) { + return await this.sendMessageWithTyping(data.key.remoteJid, { + reactionMessage: { + key: data.key, + text: data.reaction, + }, + }); + } + + // Chat Controller + public async whatsappNumber(data: WhatsAppNumberDto) { + const jids: { + groups: { number: string; jid: string }[]; + broadcast: { number: string; jid: string }[]; + users: { number: string; jid: string; name?: string }[]; + } = { + groups: [], + broadcast: [], + users: [], + }; + + data.numbers.forEach((number) => { + const jid = createJid(number); + + if (isJidGroup(jid)) { + jids.groups.push({ number, jid }); + } else if (jid === 'status@broadcast') { + jids.broadcast.push({ number, jid }); + } else { + jids.users.push({ number, jid }); + } + }); + + const onWhatsapp: OnWhatsAppDto[] = []; + + // BROADCAST + onWhatsapp.push(...jids.broadcast.map(({ jid, number }) => new OnWhatsAppDto(jid, false, number))); + + // GROUPS + const groups = await Promise.all( + jids.groups.map(async ({ jid, number }) => { + const group = await this.findGroup({ groupJid: jid }, 'inner'); + + if (!group) { + new OnWhatsAppDto(jid, false, number); + } + + return new OnWhatsAppDto(group.id, !!group?.id, number, group?.subject); + }), + ); + onWhatsapp.push(...groups); + + // USERS + const contacts: any[] = await this.prismaRepository.contact.findMany({ + where: { + instanceId: this.instanceId, + remoteJid: { + in: jids.users.map(({ jid }) => jid), + }, + }, + }); + + const numbersToVerify = jids.users.map(({ jid }) => jid.replace('+', '')); + + const cachedNumbers = await getOnWhatsappCache(numbersToVerify); + const filteredNumbers = numbersToVerify.filter( + (jid) => !cachedNumbers.some((cached) => cached.jidOptions.includes(jid)), + ); + + const verify = await this.client.onWhatsApp(...filteredNumbers); + const users: OnWhatsAppDto[] = await Promise.all( + jids.users.map(async (user) => { + let numberVerified: (typeof verify)[0] | null = null; + + const cached = cachedNumbers.find((cached) => cached.jidOptions.includes(user.jid.replace('+', ''))); + if (cached) { + return { + exists: true, + jid: cached.remoteJid, + name: contacts.find((c) => c.remoteJid === cached.remoteJid)?.pushName, + number: user.number, + }; + } + + // Brazilian numbers + if (user.number.startsWith('55')) { + const numberWithDigit = + user.number.slice(4, 5) === '9' && user.number.length === 13 + ? user.number + : `${user.number.slice(0, 4)}9${user.number.slice(4)}`; + const numberWithoutDigit = + user.number.length === 12 ? user.number : user.number.slice(0, 4) + user.number.slice(5); + + numberVerified = verify.find( + (v) => v.jid === `${numberWithDigit}@s.whatsapp.net` || v.jid === `${numberWithoutDigit}@s.whatsapp.net`, + ); + } + + // Mexican/Argentina numbers + // Ref: https://faq.whatsapp.com/1294841057948784 + if (!numberVerified && (user.number.startsWith('52') || user.number.startsWith('54'))) { + let prefix = ''; + if (user.number.startsWith('52')) { + prefix = ''; + } + if (user.number.startsWith('54')) { + prefix = '9'; + } + + const numberWithDigit = + user.number.slice(2, 3) === prefix && user.number.length === 13 + ? user.number + : `${user.number.slice(0, 2)}${prefix}${user.number.slice(2)}`; + const numberWithoutDigit = + user.number.length === 12 ? user.number : user.number.slice(0, 2) + user.number.slice(3); + + numberVerified = verify.find( + (v) => v.jid === `${numberWithDigit}@s.whatsapp.net` || v.jid === `${numberWithoutDigit}@s.whatsapp.net`, + ); + } + + if (!numberVerified) { + numberVerified = verify.find((v) => v.jid === user.jid); + } + + const numberJid = numberVerified?.jid || user.jid; + + return { + exists: !!numberVerified?.exists, + jid: numberJid, + name: contacts.find((c) => c.remoteJid === numberJid)?.pushName, + number: user.number, + }; + }), + ); + + await saveOnWhatsappCache(users.filter((user) => user.exists).map((user) => ({ remoteJid: user.jid }))); + + onWhatsapp.push(...users); + + return onWhatsapp; + } + + public async markMessageAsRead(data: ReadMessageDto) { + try { + const keys: proto.IMessageKey[] = []; + data.readMessages.forEach((read) => { + if (isJidGroup(read.remoteJid) || isJidUser(read.remoteJid)) { + keys.push({ + remoteJid: read.remoteJid, + fromMe: read.fromMe, + id: read.id, + }); + } + }); + await this.client.readMessages(keys); + return { message: 'Read messages', read: 'success' }; + } catch (error) { + throw new InternalServerErrorException('Read messages fail', error.toString()); + } + } + + public async getLastMessage(number: string) { + const where: any = { + key: { + remoteJid: number, + }, + instanceId: this.instance.id, + }; + + const messages = await this.prismaRepository.message.findMany({ + where, + orderBy: { + messageTimestamp: 'desc', + }, + take: 1, + }); + + if (messages.length === 0) { + throw new NotFoundException('Messages not found'); + } + + let lastMessage = messages.pop(); + + for (const message of messages) { + if (message.messageTimestamp >= lastMessage.messageTimestamp) { + lastMessage = message; + } + } + + return lastMessage as unknown as LastMessage; + } + + public async archiveChat(data: ArchiveChatDto) { + try { + let last_message = data.lastMessage; + let number = data.chat; + + if (!last_message && number) { + last_message = await this.getLastMessage(number); + } else { + last_message = data.lastMessage; + last_message.messageTimestamp = last_message?.messageTimestamp ?? Date.now(); + number = last_message?.key?.remoteJid; + } + + if (!last_message || Object.keys(last_message).length === 0) { + throw new NotFoundException('Last message not found'); + } + + await this.client.chatModify( + { + archive: data.archive, + lastMessages: [last_message], + }, + createJid(number), + ); + + return { + chatId: number, + archived: true, + }; + } catch (error) { + throw new InternalServerErrorException({ + archived: false, + message: ['An error occurred while archiving the chat. Open a calling.', error.toString()], + }); + } + } + + public async markChatUnread(data: MarkChatUnreadDto) { + try { + let last_message = data.lastMessage; + let number = data.chat; + + if (!last_message && number) { + last_message = await this.getLastMessage(number); + } else { + last_message = data.lastMessage; + last_message.messageTimestamp = last_message?.messageTimestamp ?? Date.now(); + number = last_message?.key?.remoteJid; + } + + if (!last_message || Object.keys(last_message).length === 0) { + throw new NotFoundException('Last message not found'); + } + + await this.client.chatModify( + { + markRead: false, + lastMessages: [last_message], + }, + createJid(number), + ); + + return { + chatId: number, + markedChatUnread: true, + }; + } catch (error) { + throw new InternalServerErrorException({ + markedChatUnread: false, + message: ['An error occurred while marked unread the chat. Open a calling.', error.toString()], + }); + } + } + + public async deleteMessage(del: DeleteMessage) { + try { + const response = await this.client.sendMessage(del.remoteJid, { delete: del }); + if (response) { + const messageId = response.message?.protocolMessage?.key?.id; + if (messageId) { + const isLogicalDeleted = configService.get('DATABASE').DELETE_DATA.LOGICAL_MESSAGE_DELETE; + let message = await this.prismaRepository.message.findFirst({ + where: { + key: { + path: ['id'], + equals: messageId, + }, + }, + }); + if (isLogicalDeleted) { + if (!message) return response; + const existingKey = typeof message?.key === 'object' && message.key !== null ? message.key : {}; + message = await this.prismaRepository.message.update({ + where: { id: message.id }, + data: { + key: { + ...existingKey, + deleted: true, + }, + status: 'DELETED', + }, + }); + } else { + await this.prismaRepository.message.deleteMany({ + where: { + id: message.id, + }, + }); + } + this.sendDataWebhook(Events.MESSAGES_DELETE, { + id: message.id, + instanceId: message.instanceId, + key: message.key, + messageType: message.messageType, + status: 'DELETED', + source: message.source, + messageTimestamp: message.messageTimestamp, + pushName: message.pushName, + participant: message.participant, + message: message.message, + }); + } + } + + return response; + } catch (error) { + throw new InternalServerErrorException('Error while deleting message for everyone', error?.toString()); + } + } + + public async getBase64FromMediaMessage(data: getBase64FromMediaMessageDto, getBuffer = false) { + try { + const m = data?.message; + const convertToMp4 = data?.convertToMp4 ?? false; + + const msg = m?.message ? m : ((await this.getMessage(m.key, true)) as proto.IWebMessageInfo); + + if (!msg) { + throw 'Message not found'; + } + + for (const subtype of MessageSubtype) { + if (msg.message[subtype]) { + msg.message = msg.message[subtype].message; + } + } + + let mediaMessage: any; + let mediaType: string; + + for (const type of TypeMediaMessage) { + mediaMessage = msg.message[type]; + if (mediaMessage) { + mediaType = type; + break; + } + } + + if (!mediaMessage) { + throw 'The message is not of the media type'; + } + + if (typeof mediaMessage['mediaKey'] === 'object') { + msg.message = JSON.parse(JSON.stringify(msg.message)); + } + + const buffer = await downloadMediaMessage( + { key: msg?.key, message: msg?.message }, + 'buffer', + {}, + { + logger: P({ level: 'error' }) as any, + reuploadRequest: this.client.updateMediaMessage, + }, + ); + const typeMessage = getContentType(msg.message); + + const ext = mimeTypes.extension(mediaMessage?.['mimetype']); + const fileName = mediaMessage?.['fileName'] || `${msg.key.id}.${ext}` || `${v4()}.${ext}`; + + if (convertToMp4 && typeMessage === 'audioMessage') { + try { + const convert = await this.processAudioMp4(buffer.toString('base64')); + + if (Buffer.isBuffer(convert)) { + const result = { + mediaType, + fileName, + caption: mediaMessage['caption'], + size: { + fileLength: mediaMessage['fileLength'], + height: mediaMessage['height'], + width: mediaMessage['width'], + }, + mimetype: 'audio/mp4', + base64: convert.toString('base64'), + buffer: getBuffer ? convert : null, + }; + + return result; + } + } catch (error) { + this.logger.error('Error converting audio to mp4:'); + this.logger.error(error); + throw new BadRequestException('Failed to convert audio to MP4'); + } + } + + return { + mediaType, + fileName, + caption: mediaMessage['caption'], + size: { + fileLength: mediaMessage['fileLength'], + height: mediaMessage['height'], + width: mediaMessage['width'], + }, + mimetype: mediaMessage['mimetype'], + base64: buffer.toString('base64'), + buffer: getBuffer ? buffer : null, + }; + } catch (error) { + this.logger.error('Error processing media message:'); + this.logger.error(error); + throw new BadRequestException(error.toString()); + } + } + + public async fetchPrivacySettings() { + const privacy = await this.client.fetchPrivacySettings(); + + return { + readreceipts: privacy.readreceipts, + profile: privacy.profile, + status: privacy.status, + online: privacy.online, + last: privacy.last, + groupadd: privacy.groupadd, + }; + } + + public async updatePrivacySettings(settings: PrivacySettingDto) { + try { + await this.client.updateReadReceiptsPrivacy(settings.readreceipts); + await this.client.updateProfilePicturePrivacy(settings.profile); + await this.client.updateStatusPrivacy(settings.status); + await this.client.updateOnlinePrivacy(settings.online); + await this.client.updateLastSeenPrivacy(settings.last); + await this.client.updateGroupsAddPrivacy(settings.groupadd); + + this.reloadConnection(); + + return { + update: 'success', + data: { + readreceipts: settings.readreceipts, + profile: settings.profile, + status: settings.status, + online: settings.online, + last: settings.last, + groupadd: settings.groupadd, + }, + }; + } catch (error) { + throw new InternalServerErrorException('Error updating privacy settings', error.toString()); + } + } + + public async fetchBusinessProfile(number: string): Promise { + try { + const jid = number ? createJid(number) : this.instance.wuid; + + const profile = await this.client.getBusinessProfile(jid); + + if (!profile) { + const info = await this.whatsappNumber({ numbers: [jid] }); + + return { + isBusiness: false, + message: 'Not is business profile', + ...info?.shift(), + }; + } + + return { + isBusiness: true, + ...profile, + }; + } catch (error) { + throw new InternalServerErrorException('Error updating profile name', error.toString()); + } + } + + public async updateProfileName(name: string) { + try { + await this.client.updateProfileName(name); + + return { update: 'success' }; + } catch (error) { + throw new InternalServerErrorException('Error updating profile name', error.toString()); + } + } + + public async updateProfileStatus(status: string) { + try { + await this.client.updateProfileStatus(status); + + return { update: 'success' }; + } catch (error) { + throw new InternalServerErrorException('Error updating profile status', error.toString()); + } + } + + public async updateProfilePicture(picture: string) { + try { + let pic: WAMediaUpload; + if (isURL(picture)) { + const timestamp = new Date().getTime(); + const url = `${picture}?timestamp=${timestamp}`; + + let config: any = { + responseType: 'arraybuffer', + }; + + if (this.localProxy?.enabled) { + config = { + ...config, + httpsAgent: makeProxyAgent({ + host: this.localProxy.host, + port: this.localProxy.port, + protocol: this.localProxy.protocol, + username: this.localProxy.username, + password: this.localProxy.password, + }), + }; + } + + pic = (await axios.get(url, config)).data; + } else if (isBase64(picture)) { + pic = Buffer.from(picture, 'base64'); + } else { + throw new BadRequestException('"profilePicture" must be a url or a base64'); + } + + await this.client.updateProfilePicture(this.instance.wuid, pic); + + this.reloadConnection(); + + return { update: 'success' }; + } catch (error) { + throw new InternalServerErrorException('Error updating profile picture', error.toString()); + } + } + + public async removeProfilePicture() { + try { + await this.client.removeProfilePicture(this.instance.wuid); + + this.reloadConnection(); + + return { update: 'success' }; + } catch (error) { + throw new InternalServerErrorException('Error removing profile picture', error.toString()); + } + } + + public async blockUser(data: BlockUserDto) { + try { + const { number } = data; + + const isWA = (await this.whatsappNumber({ numbers: [number] }))?.shift(); + + if (!isWA.exists && !isJidGroup(isWA.jid) && !isWA.jid.includes('@broadcast')) { + throw new BadRequestException(isWA); + } + + const sender = isWA.jid; + + await this.client.updateBlockStatus(sender, data.status); + + return { block: 'success' }; + } catch (error) { + throw new InternalServerErrorException('Error blocking user', error.toString()); + } + } + + private async formatUpdateMessage(data: UpdateMessageDto) { + try { + const msg: any = await this.getMessage(data.key, true); + + if (msg?.messageType === 'conversation' || msg?.messageType === 'extendedTextMessage') { + return { + text: data.text, + }; + } + + if (msg?.messageType === 'imageMessage') { + return { + image: msg?.message?.imageMessage, + caption: data.text, + }; + } + + if (msg?.messageType === 'videoMessage') { + return { + video: msg?.message?.videoMessage, + caption: data.text, + }; + } + + return null; + } catch (error) { + this.logger.error(error); + throw new BadRequestException(error.toString()); + } + } + + public async updateMessage(data: UpdateMessageDto) { + const jid = createJid(data.number); + + const options = await this.formatUpdateMessage(data); + + if (!options) { + this.logger.error('Message not compatible'); + throw new BadRequestException('Message not compatible'); + } + + try { + return await this.client.sendMessage(jid, { + ...(options as any), + edit: data.key, + }); + } catch (error) { + this.logger.error(error); + throw new BadRequestException(error.toString()); + } + } + + public async fetchLabels(): Promise { + const labels = await this.prismaRepository.label.findMany({ + where: { + instanceId: this.instanceId, + }, + }); + + return labels.map((label) => ({ + color: label.color, + name: label.name, + id: label.labelId, + predefinedId: label.predefinedId, + })); + } + + public async handleLabel(data: HandleLabelDto) { + const whatsappContact = await this.whatsappNumber({ numbers: [data.number] }); + if (whatsappContact.length === 0) { + throw new NotFoundException('Number not found'); + } + const contact = whatsappContact[0]; + if (!contact.exists) { + throw new NotFoundException('Number is not on WhatsApp'); + } + + try { + if (data.action === 'add') { + await this.client.addChatLabel(contact.jid, data.labelId); + await this.addLabel(data.labelId, this.instanceId, contact.jid); + + return { numberJid: contact.jid, labelId: data.labelId, add: true }; + } + if (data.action === 'remove') { + await this.client.removeChatLabel(contact.jid, data.labelId); + await this.removeLabel(data.labelId, this.instanceId, contact.jid); + + return { numberJid: contact.jid, labelId: data.labelId, remove: true }; + } + } catch (error) { + throw new BadRequestException(`Unable to ${data.action} label to chat`, error.toString()); + } + } + + // Group + private async updateGroupMetadataCache(groupJid: string) { + try { + const meta = await this.client.groupMetadata(groupJid); + + const cacheConf = this.configService.get('CACHE'); + + if ((cacheConf?.REDIS?.ENABLED && cacheConf?.REDIS?.URI !== '') || cacheConf?.LOCAL?.ENABLED) { + this.logger.verbose(`Updating cache for group: ${groupJid}`); + await groupMetadataCache.set(groupJid, { + timestamp: Date.now(), + data: meta, + }); + } + + return meta; + } catch (error) { + this.logger.error(error); + return null; + } + } + + private getGroupMetadataCache = async (groupJid: string) => { + if (!isJidGroup(groupJid)) return null; + + const cacheConf = this.configService.get('CACHE'); + + if ((cacheConf?.REDIS?.ENABLED && cacheConf?.REDIS?.URI !== '') || cacheConf?.LOCAL?.ENABLED) { + if (await groupMetadataCache?.has(groupJid)) { + console.log(`Cache request for group: ${groupJid}`); + const meta = await groupMetadataCache.get(groupJid); + + if (Date.now() - meta.timestamp > 3600000) { + await this.updateGroupMetadataCache(groupJid); + } + + return meta.data; + } + + console.log(`Cache request for group: ${groupJid} - not found`); + return await this.updateGroupMetadataCache(groupJid); + } + + return await this.findGroup({ groupJid }, 'inner'); + }; + + public async createGroup(create: CreateGroupDto) { + try { + const participants = (await this.whatsappNumber({ numbers: create.participants })) + .filter((participant) => participant.exists) + .map((participant) => participant.jid); + const { id } = await this.client.groupCreate(create.subject, participants); + + if (create?.description) { + await this.client.groupUpdateDescription(id, create.description); + } + + if (create?.promoteParticipants) { + await this.updateGParticipant({ + groupJid: id, + action: 'promote', + participants: participants, + }); + } + + const group = await this.client.groupMetadata(id); + + return group; + } catch (error) { + this.logger.error(error); + throw new InternalServerErrorException('Error creating group', error.toString()); + } + } + + public async updateGroupPicture(picture: GroupPictureDto) { + try { + let pic: WAMediaUpload; + if (isURL(picture.image)) { + const timestamp = new Date().getTime(); + const url = `${picture.image}?timestamp=${timestamp}`; + + let config: any = { + responseType: 'arraybuffer', + }; + + if (this.localProxy?.enabled) { + config = { + ...config, + httpsAgent: makeProxyAgent({ + host: this.localProxy.host, + port: this.localProxy.port, + protocol: this.localProxy.protocol, + username: this.localProxy.username, + password: this.localProxy.password, + }), + }; + } + + pic = (await axios.get(url, config)).data; + } else if (isBase64(picture.image)) { + pic = Buffer.from(picture.image, 'base64'); + } else { + throw new BadRequestException('"profilePicture" must be a url or a base64'); + } + await this.client.updateProfilePicture(picture.groupJid, pic); + + return { update: 'success' }; + } catch (error) { + throw new InternalServerErrorException('Error update group picture', error.toString()); + } + } + + public async updateGroupSubject(data: GroupSubjectDto) { + try { + await this.client.groupUpdateSubject(data.groupJid, data.subject); + + return { update: 'success' }; + } catch (error) { + throw new InternalServerErrorException('Error updating group subject', error.toString()); + } + } + + public async updateGroupDescription(data: GroupDescriptionDto) { + try { + await this.client.groupUpdateDescription(data.groupJid, data.description); + + return { update: 'success' }; + } catch (error) { + throw new InternalServerErrorException('Error updating group description', error.toString()); + } + } + + public async findGroup(id: GroupJid, reply: 'inner' | 'out' = 'out') { + try { + const group = await this.client.groupMetadata(id.groupJid); + + if (!group) { + this.logger.error('Group not found'); + return null; + } + + const picture = await this.profilePicture(group.id); + + return { + id: group.id, + subject: group.subject, + subjectOwner: group.subjectOwner, + subjectTime: group.subjectTime, + pictureUrl: picture.profilePictureUrl, + size: group.participants.length, + creation: group.creation, + owner: group.owner, + desc: group.desc, + descId: group.descId, + restrict: group.restrict, + announce: group.announce, + participants: group.participants, + isCommunity: group.isCommunity, + isCommunityAnnounce: group.isCommunityAnnounce, + linkedParent: group.linkedParent, + }; + } catch (error) { + if (reply === 'inner') { + return; + } + throw new NotFoundException('Error fetching group', error.toString()); + } + } + + public async fetchAllGroups(getParticipants: GetParticipant) { + const fetch = Object.values(await this?.client?.groupFetchAllParticipating()); + + let groups = []; + for (const group of fetch) { + const picture = await this.profilePicture(group.id); + + const result = { + id: group.id, + subject: group.subject, + subjectOwner: group.subjectOwner, + subjectTime: group.subjectTime, + pictureUrl: picture?.profilePictureUrl, + size: group.participants.length, + creation: group.creation, + owner: group.owner, + desc: group.desc, + descId: group.descId, + restrict: group.restrict, + announce: group.announce, + isCommunity: group.isCommunity, + isCommunityAnnounce: group.isCommunityAnnounce, + linkedParent: group.linkedParent, + }; + + if (getParticipants.getParticipants == 'true') { + result['participants'] = group.participants; + } + + groups = [...groups, result]; + } + + return groups; + } + + public async inviteCode(id: GroupJid) { + try { + const code = await this.client.groupInviteCode(id.groupJid); + return { inviteUrl: `https://chat.whatsapp.com/${code}`, inviteCode: code }; + } catch (error) { + throw new NotFoundException('No invite code', error.toString()); + } + } + + public async inviteInfo(id: GroupInvite) { + try { + return await this.client.groupGetInviteInfo(id.inviteCode); + } catch (error) { + throw new NotFoundException('No invite info', id.inviteCode); + } + } + + public async sendInvite(id: GroupSendInvite) { + try { + const inviteCode = await this.inviteCode({ groupJid: id.groupJid }); + + const inviteUrl = inviteCode.inviteUrl; + + const numbers = id.numbers.map((number) => createJid(number)); + const description = id.description ?? ''; + + const msg = `${description}\n\n${inviteUrl}`; + + const message = { + conversation: msg, + }; + + for await (const number of numbers) { + await this.sendMessageWithTyping(number, message); + } + + return { send: true, inviteUrl }; + } catch (error) { + throw new NotFoundException('No send invite'); + } + } + + public async acceptInviteCode(id: AcceptGroupInvite) { + try { + const groupJid = await this.client.groupAcceptInvite(id.inviteCode); + return { accepted: true, groupJid: groupJid }; + } catch (error) { + throw new NotFoundException('Accept invite error', error.toString()); + } + } + + public async revokeInviteCode(id: GroupJid) { + try { + const inviteCode = await this.client.groupRevokeInvite(id.groupJid); + return { revoked: true, inviteCode }; + } catch (error) { + throw new NotFoundException('Revoke error', error.toString()); + } + } + + public async findParticipants(id: GroupJid) { + try { + const participants = (await this.client.groupMetadata(id.groupJid)).participants; + const contacts = await this.prismaRepository.contact.findMany({ + where: { + instanceId: this.instanceId, + remoteJid: { + in: participants.map((p) => p.id), + }, + }, + }); + const parsedParticipants = participants.map((participant) => { + const contact = contacts.find((c) => c.remoteJid === participant.id); + return { + ...participant, + name: participant.name ?? contact?.pushName, + imgUrl: participant.imgUrl ?? contact?.profilePicUrl, + }; + }); + + const usersContacts = parsedParticipants.filter((c) => c.id.includes('@s.whatsapp')); + if (usersContacts) { + await saveOnWhatsappCache(usersContacts.map((c) => ({ remoteJid: c.id }))); + } + + return { participants: parsedParticipants }; + } catch (error) { + console.error(error); + throw new NotFoundException('No participants', error.toString()); + } + } + + public async updateGParticipant(update: GroupUpdateParticipantDto) { + try { + const participants = update.participants.map((p) => createJid(p)); + const updateParticipants = await this.client.groupParticipantsUpdate( + update.groupJid, + participants, + update.action, + ); + return { updateParticipants: updateParticipants }; + } catch (error) { + throw new BadRequestException('Error updating participants', error.toString()); + } + } + + public async updateGSetting(update: GroupUpdateSettingDto) { + try { + const updateSetting = await this.client.groupSettingUpdate(update.groupJid, update.action); + return { updateSetting: updateSetting }; + } catch (error) { + throw new BadRequestException('Error updating setting', error.toString()); + } + } + + public async toggleEphemeral(update: GroupToggleEphemeralDto) { + try { + await this.client.groupToggleEphemeral(update.groupJid, update.expiration); + return { success: true }; + } catch (error) { + throw new BadRequestException('Error updating setting', error.toString()); + } + } + + public async leaveGroup(id: GroupJid) { + try { + await this.client.groupLeave(id.groupJid); + return { groupJid: id.groupJid, leave: true }; + } catch (error) { + throw new BadRequestException('Unable to leave the group', error.toString()); + } + } + + public async templateMessage() { + throw new Error('Method not available in the Baileys service'); + } + + private prepareMessage(message: proto.IWebMessageInfo): any { + const contentType = getContentType(message.message); + const contentMsg = message?.message[contentType] as any; + + const messageRaw = { + key: message.key, + pushName: message.pushName, + status: status[message.status], + message: { ...message.message }, + contextInfo: contentMsg?.contextInfo, + messageType: contentType || 'unknown', + messageTimestamp: message.messageTimestamp as number, + instanceId: this.instanceId, + source: getDevice(message.key.id), + }; + + if (!messageRaw.status && message.key.fromMe === false) { + messageRaw.status = status[3]; // DELIVERED MESSAGE + } + + if (messageRaw.message.extendedTextMessage) { + messageRaw.messageType = 'conversation'; + messageRaw.message.conversation = messageRaw.message.extendedTextMessage.text; + delete messageRaw.message.extendedTextMessage; + } + + if (messageRaw.message.documentWithCaptionMessage) { + messageRaw.messageType = 'documentMessage'; + messageRaw.message.documentMessage = messageRaw.message.documentWithCaptionMessage.message.documentMessage; + delete messageRaw.message.documentWithCaptionMessage; + } + + const quotedMessage = messageRaw?.contextInfo?.quotedMessage; + if (quotedMessage) { + if (quotedMessage.extendedTextMessage) { + quotedMessage.conversation = quotedMessage.extendedTextMessage.text; + delete quotedMessage.extendedTextMessage; + } + + if (quotedMessage.documentWithCaptionMessage) { + quotedMessage.documentMessage = quotedMessage.documentWithCaptionMessage.message.documentMessage; + delete quotedMessage.documentWithCaptionMessage; + } + } + + return messageRaw; + } + + private async syncChatwootLostMessages() { + if (this.configService.get('CHATWOOT').ENABLED && this.localChatwoot?.enabled) { + const chatwootConfig = await this.findChatwoot(); + const prepare = (message: any) => this.prepareMessage(message); + this.chatwootService.syncLostMessages({ instanceName: this.instance.name }, chatwootConfig, prepare); + + const task = cron.schedule('0,30 * * * *', async () => { + this.chatwootService.syncLostMessages({ instanceName: this.instance.name }, chatwootConfig, prepare); + }); + task.start(); + } + } + + private async updateMessagesReadedByTimestamp(remoteJid: string, timestamp?: number): Promise { + if (timestamp === undefined || timestamp === null) return 0; + + const result = await this.prismaRepository.message.updateMany({ + where: { + AND: [ + { key: { path: ['remoteJid'], equals: remoteJid } }, + { key: { path: ['fromMe'], equals: false } }, + { messageTimestamp: { lte: timestamp } }, + { + OR: [{ status: null }, { status: status[3] }], + }, + ], + }, + data: { status: status[4] }, + }); + + if (result) { + if (result.count > 0) { + this.updateChatUnreadMessages(remoteJid); + } + + return result.count; + } + + return 0; + } + + private async updateChatUnreadMessages(remoteJid: string): Promise { + const [chat, unreadMessages] = await Promise.all([ + this.prismaRepository.chat.findFirst({ where: { remoteJid } }), + this.prismaRepository.message.count({ + where: { + AND: [ + { key: { path: ['remoteJid'], equals: remoteJid } }, + { key: { path: ['fromMe'], equals: false } }, + { status: { equals: status[3] } }, + ], + }, + }), + ]); + + if (chat && chat.unreadMessages !== unreadMessages) { + await this.prismaRepository.chat.update({ + where: { id: chat.id }, + data: { unreadMessages }, + }); + } + + return unreadMessages; + } + + private async addLabel(labelId: string, instanceId: string, chatId: string) { + const id = cuid(); + + await this.prismaRepository.$executeRawUnsafe( + `INSERT INTO "Chat" ("id", "instanceId", "remoteJid", "labels", "createdAt", "updatedAt") + VALUES ($4, $2, $3, to_jsonb(ARRAY[$1]::text[]), NOW(), NOW()) ON CONFLICT ("instanceId", "remoteJid") + DO + UPDATE + SET "labels" = ( + SELECT to_jsonb(array_agg(DISTINCT elem)) + FROM ( + SELECT jsonb_array_elements_text("Chat"."labels") AS elem + UNION + SELECT $1::text AS elem + ) sub + ), + "updatedAt" = NOW();`, + labelId, + instanceId, + chatId, + id, + ); + } + + private async removeLabel(labelId: string, instanceId: string, chatId: string) { + const id = cuid(); + + await this.prismaRepository.$executeRawUnsafe( + `INSERT INTO "Chat" ("id", "instanceId", "remoteJid", "labels", "createdAt", "updatedAt") + VALUES ($4, $2, $3, '[]'::jsonb, NOW(), NOW()) ON CONFLICT ("instanceId", "remoteJid") + DO + UPDATE + SET "labels" = COALESCE ( + ( + SELECT jsonb_agg(elem) + FROM jsonb_array_elements_text("Chat"."labels") AS elem + WHERE elem <> $1 + ), + '[]'::jsonb + ), + "updatedAt" = NOW();`, + labelId, + instanceId, + chatId, + id, + ); + } + + public async baileysOnWhatsapp(jid: string) { + const response = await this.client.onWhatsApp(jid); + + return response; + } + + public async baileysProfilePictureUrl(jid: string, type: 'image' | 'preview', timeoutMs: number) { + const response = await this.client.profilePictureUrl(jid, type, timeoutMs); + + return response; + } + + public async baileysAssertSessions(jids: string[], force: boolean) { + const response = await this.client.assertSessions(jids, force); + + return response; + } + + public async baileysCreateParticipantNodes(jids: string[], message: proto.IMessage, extraAttrs: any) { + const response = await this.client.createParticipantNodes(jids, message, extraAttrs); + + const convertedResponse = { + ...response, + nodes: response.nodes.map((node: any) => ({ + ...node, + content: node.content?.map((c: any) => ({ + ...c, + content: c.content instanceof Uint8Array ? Buffer.from(c.content).toString('base64') : c.content, + })), + })), + }; + + return convertedResponse; + } + + public async baileysSendNode(stanza: any) { + console.log('stanza', JSON.stringify(stanza)); + const response = await this.client.sendNode(stanza); + + return response; + } + + public async baileysGetUSyncDevices(jids: string[], useCache: boolean, ignoreZeroDevices: boolean) { + const response = await this.client.getUSyncDevices(jids, useCache, ignoreZeroDevices); + + return response; + } + + public async baileysGenerateMessageTag() { + const response = await this.client.generateMessageTag(); + + return response; + } + + public async baileysSignalRepositoryDecryptMessage(jid: string, type: 'pkmsg' | 'msg', ciphertext: string) { + try { + const ciphertextBuffer = Buffer.from(ciphertext, 'base64'); + + const response = await this.client.signalRepository.decryptMessage({ + jid, + type, + ciphertext: ciphertextBuffer, + }); + + return response instanceof Uint8Array ? Buffer.from(response).toString('base64') : response; + } catch (error) { + this.logger.error('Error decrypting message:'); + this.logger.error(error); + throw error; + } + } + + public async baileysGetAuthState() { + const response = { + me: this.client.authState.creds.me, + account: this.client.authState.creds.account, + }; + + return response; + } +} diff --git a/src/api/integrations/chatbot/chatbot.controller.ts b/src/api/integrations/chatbot/chatbot.controller.ts new file mode 100644 index 00000000..f99b4fae --- /dev/null +++ b/src/api/integrations/chatbot/chatbot.controller.ts @@ -0,0 +1,209 @@ +import { InstanceDto } from '@api/dto/instance.dto'; +import { PrismaRepository } from '@api/repository/repository.service'; +import { + difyController, + evolutionBotController, + flowiseController, + openaiController, + typebotController, +} from '@api/server.module'; +import { WAMonitoringService } from '@api/services/monitor.service'; +import { Logger } from '@config/logger.config'; +import { IntegrationSession } from '@prisma/client'; +import { findBotByTrigger } from '@utils/findBotByTrigger'; + +export type EmitData = { + instance: InstanceDto; + remoteJid: string; + msg: any; + pushName?: string; +}; + +export interface ChatbotControllerInterface { + integrationEnabled: boolean; + botRepository: any; + settingsRepository: any; + sessionRepository: any; + userMessageDebounce: { [key: string]: { message: string; timeoutId: NodeJS.Timeout } }; + + createBot(instance: InstanceDto, data: any): Promise; + findBot(instance: InstanceDto): Promise; + fetchBot(instance: InstanceDto, botId: string): Promise; + updateBot(instance: InstanceDto, botId: string, data: any): Promise; + deleteBot(instance: InstanceDto, botId: string): Promise; + + settings(instance: InstanceDto, data: any): Promise; + fetchSettings(instance: InstanceDto): Promise; + + changeStatus(instance: InstanceDto, botId: string, status: string): Promise; + fetchSessions(instance: InstanceDto, botId: string, remoteJid?: string): Promise; + ignoreJid(instance: InstanceDto, data: any): Promise; + + emit(data: EmitData): Promise; +} + +export class ChatbotController { + public prismaRepository: PrismaRepository; + public waMonitor: WAMonitoringService; + + public readonly logger = new Logger('ChatbotController'); + + constructor(prismaRepository: PrismaRepository, waMonitor: WAMonitoringService) { + this.prisma = prismaRepository; + this.monitor = waMonitor; + } + + public set prisma(prisma: PrismaRepository) { + this.prismaRepository = prisma; + } + + public get prisma() { + return this.prismaRepository; + } + + public set monitor(waMonitor: WAMonitoringService) { + this.waMonitor = waMonitor; + } + + public get monitor() { + return this.waMonitor; + } + + public async emit({ + instance, + remoteJid, + msg, + pushName, + isIntegration = false, + }: { + instance: InstanceDto; + remoteJid: string; + msg: any; + pushName?: string; + isIntegration?: boolean; + }): Promise { + const emitData = { + instance, + remoteJid, + msg, + pushName, + isIntegration, + }; + await evolutionBotController.emit(emitData); + + await typebotController.emit(emitData); + + await openaiController.emit(emitData); + + await difyController.emit(emitData); + + await flowiseController.emit(emitData); + } + + public processDebounce( + userMessageDebounce: any, + content: string, + remoteJid: string, + debounceTime: number, + callback: any, + ) { + if (userMessageDebounce[remoteJid]) { + userMessageDebounce[remoteJid].message += `\n${content}`; + this.logger.log('message debounced: ' + userMessageDebounce[remoteJid].message); + clearTimeout(userMessageDebounce[remoteJid].timeoutId); + } else { + userMessageDebounce[remoteJid] = { + message: content, + timeoutId: null, + }; + } + + userMessageDebounce[remoteJid].timeoutId = setTimeout(() => { + const myQuestion = userMessageDebounce[remoteJid].message; + this.logger.log('Debounce complete. Processing message: ' + myQuestion); + + delete userMessageDebounce[remoteJid]; + callback(myQuestion); + }, debounceTime * 1000); + } + + public checkIgnoreJids(ignoreJids: any, remoteJid: string) { + if (ignoreJids && ignoreJids.length > 0) { + let ignoreGroups = false; + let ignoreContacts = false; + + if (ignoreJids.includes('@g.us')) { + ignoreGroups = true; + } + + if (ignoreJids.includes('@s.whatsapp.net')) { + ignoreContacts = true; + } + + if (ignoreGroups && remoteJid.endsWith('@g.us')) { + this.logger.warn('Ignoring message from group: ' + remoteJid); + return true; + } + + if (ignoreContacts && remoteJid.endsWith('@s.whatsapp.net')) { + this.logger.warn('Ignoring message from contact: ' + remoteJid); + return true; + } + + if (ignoreJids.includes(remoteJid)) { + this.logger.warn('Ignoring message from jid: ' + remoteJid); + return true; + } + + return false; + } + + return false; + } + + public async getSession(remoteJid: string, instance: InstanceDto) { + let session = await this.prismaRepository.integrationSession.findFirst({ + where: { + remoteJid: remoteJid, + instanceId: instance.instanceId, + }, + orderBy: { createdAt: 'desc' }, + }); + + if (session) { + if (session.status !== 'closed' && !session.botId) { + this.logger.warn('Session is already opened in another integration'); + return; + } else if (!session.botId) { + session = null; + } + } + + return session; + } + + public async findBotTrigger( + botRepository: any, + content: string, + instance: InstanceDto, + session?: IntegrationSession, + ) { + let findBot: null; + + if (!session) { + findBot = await findBotByTrigger(botRepository, content, instance.instanceId); + + if (!findBot) { + return; + } + } else { + findBot = await botRepository.findFirst({ + where: { + id: session.botId, + }, + }); + } + + return findBot; + } +} diff --git a/src/api/integrations/chatbot/chatbot.router.ts b/src/api/integrations/chatbot/chatbot.router.ts new file mode 100644 index 00000000..19fc74b7 --- /dev/null +++ b/src/api/integrations/chatbot/chatbot.router.ts @@ -0,0 +1,23 @@ +import { ChatwootRouter } from '@api/integrations/chatbot/chatwoot/routes/chatwoot.router'; +import { DifyRouter } from '@api/integrations/chatbot/dify/routes/dify.router'; +import { OpenaiRouter } from '@api/integrations/chatbot/openai/routes/openai.router'; +import { TypebotRouter } from '@api/integrations/chatbot/typebot/routes/typebot.router'; +import { Router } from 'express'; + +import { EvolutionBotRouter } from './evolutionBot/routes/evolutionBot.router'; +import { FlowiseRouter } from './flowise/routes/flowise.router'; + +export class ChatbotRouter { + public readonly router: Router; + + constructor(...guards: any[]) { + this.router = Router(); + + this.router.use('/evolutionBot', new EvolutionBotRouter(...guards).router); + this.router.use('/chatwoot', new ChatwootRouter(...guards).router); + this.router.use('/typebot', new TypebotRouter(...guards).router); + this.router.use('/openai', new OpenaiRouter(...guards).router); + this.router.use('/dify', new DifyRouter(...guards).router); + this.router.use('/flowise', new FlowiseRouter(...guards).router); + } +} diff --git a/src/api/integrations/chatbot/chatbot.schema.ts b/src/api/integrations/chatbot/chatbot.schema.ts new file mode 100644 index 00000000..efc2388f --- /dev/null +++ b/src/api/integrations/chatbot/chatbot.schema.ts @@ -0,0 +1,6 @@ +export * from '@api/integrations/chatbot/chatwoot/validate/chatwoot.schema'; +export * from '@api/integrations/chatbot/dify/validate/dify.schema'; +export * from '@api/integrations/chatbot/evolutionBot/validate/evolutionBot.schema'; +export * from '@api/integrations/chatbot/flowise/validate/flowise.schema'; +export * from '@api/integrations/chatbot/openai/validate/openai.schema'; +export * from '@api/integrations/chatbot/typebot/validate/typebot.schema'; diff --git a/src/api/integrations/chatbot/chatwoot/controllers/chatwoot.controller.ts b/src/api/integrations/chatbot/chatwoot/controllers/chatwoot.controller.ts new file mode 100644 index 00000000..17cdce01 --- /dev/null +++ b/src/api/integrations/chatbot/chatwoot/controllers/chatwoot.controller.ts @@ -0,0 +1,92 @@ +import { InstanceDto } from '@api/dto/instance.dto'; +import { ChatwootDto } from '@api/integrations/chatbot/chatwoot/dto/chatwoot.dto'; +import { ChatwootService } from '@api/integrations/chatbot/chatwoot/services/chatwoot.service'; +import { PrismaRepository } from '@api/repository/repository.service'; +import { waMonitor } from '@api/server.module'; +import { CacheService } from '@api/services/cache.service'; +import { CacheEngine } from '@cache/cacheengine'; +import { Chatwoot, ConfigService, HttpServer } from '@config/env.config'; +import { BadRequestException } from '@exceptions'; +import { isURL } from 'class-validator'; + +export class ChatwootController { + constructor( + private readonly chatwootService: ChatwootService, + private readonly configService: ConfigService, + private readonly prismaRepository: PrismaRepository, + ) {} + + public async createChatwoot(instance: InstanceDto, data: ChatwootDto) { + if (!this.configService.get('CHATWOOT').ENABLED) throw new BadRequestException('Chatwoot is disabled'); + + if (data?.enabled) { + if (!isURL(data.url, { require_tld: false })) { + throw new BadRequestException('url is not valid'); + } + + if (!data.accountId) { + throw new BadRequestException('accountId is required'); + } + + if (!data.token) { + throw new BadRequestException('token is required'); + } + + if (data.signMsg !== true && data.signMsg !== false) { + throw new BadRequestException('signMsg is required'); + } + if (data.signMsg === false) data.signDelimiter = null; + } + + if (!data.nameInbox || data.nameInbox === '') { + data.nameInbox = instance.instanceName; + } + + const result = await this.chatwootService.create(instance, data); + + const urlServer = this.configService.get('SERVER').URL; + + const response = { + ...result, + webhook_url: `${urlServer}/chatwoot/webhook/${encodeURIComponent(instance.instanceName)}`, + }; + + return response; + } + + public async findChatwoot(instance: InstanceDto): Promise { + if (!this.configService.get('CHATWOOT').ENABLED) throw new BadRequestException('Chatwoot is disabled'); + + const result = await this.chatwootService.find(instance); + + const urlServer = this.configService.get('SERVER').URL; + + if (Object.keys(result || {}).length === 0) { + return { + enabled: false, + url: '', + accountId: '', + token: '', + signMsg: false, + nameInbox: '', + webhook_url: '', + }; + } + + const response = { + ...result, + webhook_url: `${urlServer}/chatwoot/webhook/${encodeURIComponent(instance.instanceName)}`, + }; + + return response; + } + + public async receiveWebhook(instance: InstanceDto, data: any) { + if (!this.configService.get('CHATWOOT').ENABLED) throw new BadRequestException('Chatwoot is disabled'); + + const chatwootCache = new CacheService(new CacheEngine(this.configService, ChatwootService.name).getEngine()); + const chatwootService = new ChatwootService(waMonitor, this.configService, this.prismaRepository, chatwootCache); + + return chatwootService.receiveWebhook(instance, data); + } +} diff --git a/src/api/integrations/chatbot/chatwoot/dto/chatwoot.dto.ts b/src/api/integrations/chatbot/chatwoot/dto/chatwoot.dto.ts new file mode 100644 index 00000000..4abf468f --- /dev/null +++ b/src/api/integrations/chatbot/chatwoot/dto/chatwoot.dto.ts @@ -0,0 +1,41 @@ +import { Constructor } from '@api/integrations/integration.dto'; + +export class ChatwootDto { + enabled?: boolean; + accountId?: string; + token?: string; + url?: string; + nameInbox?: string; + signMsg?: boolean; + signDelimiter?: string; + number?: string; + reopenConversation?: boolean; + conversationPending?: boolean; + mergeBrazilContacts?: boolean; + importContacts?: boolean; + importMessages?: boolean; + daysLimitImportMessages?: number; + autoCreate?: boolean; + organization?: string; + logo?: string; + ignoreJids?: string[]; +} + +export function ChatwootInstanceMixin(Base: TBase) { + return class extends Base { + chatwootAccountId?: string; + chatwootToken?: string; + chatwootUrl?: string; + chatwootSignMsg?: boolean; + chatwootReopenConversation?: boolean; + chatwootConversationPending?: boolean; + chatwootMergeBrazilContacts?: boolean; + chatwootImportContacts?: boolean; + chatwootImportMessages?: boolean; + chatwootDaysLimitImportMessages?: number; + chatwootNameInbox?: string; + chatwootOrganization?: string; + chatwootLogo?: string; + chatwootAutoCreate?: boolean; + }; +} diff --git a/src/api/integrations/chatwoot/libs/postgres.client.ts b/src/api/integrations/chatbot/chatwoot/libs/postgres.client.ts similarity index 79% rename from src/api/integrations/chatwoot/libs/postgres.client.ts rename to src/api/integrations/chatbot/chatwoot/libs/postgres.client.ts index 1211b075..3e3e9685 100644 --- a/src/api/integrations/chatwoot/libs/postgres.client.ts +++ b/src/api/integrations/chatbot/chatwoot/libs/postgres.client.ts @@ -1,12 +1,11 @@ +import { Chatwoot, configService } from '@config/env.config'; +import { Logger } from '@config/logger.config'; import postgresql from 'pg'; -import { Chatwoot, configService } from '../../../../config/env.config'; -import { Logger } from '../../../../config/logger.config'; - const { Pool } = postgresql; class Postgres { - private logger = new Logger(Postgres.name); + private logger = new Logger('Postgres'); private pool; private connected = false; @@ -27,7 +26,6 @@ class Postgres { }); try { - this.logger.verbose('connecting new postgres'); this.connected = true; } catch (e) { this.connected = false; diff --git a/src/api/integrations/chatwoot/routes/chatwoot.router.ts b/src/api/integrations/chatbot/chatwoot/routes/chatwoot.router.ts similarity index 50% rename from src/api/integrations/chatwoot/routes/chatwoot.router.ts rename to src/api/integrations/chatbot/chatwoot/routes/chatwoot.router.ts index cc227163..51b23ab5 100644 --- a/src/api/integrations/chatwoot/routes/chatwoot.router.ts +++ b/src/api/integrations/chatbot/chatwoot/routes/chatwoot.router.ts @@ -1,26 +1,16 @@ +import { RouterBroker } from '@api/abstract/abstract.router'; +import { InstanceDto } from '@api/dto/instance.dto'; +import { ChatwootDto } from '@api/integrations/chatbot/chatwoot/dto/chatwoot.dto'; +import { HttpStatus } from '@api/routes/index.router'; +import { chatwootController } from '@api/server.module'; +import { chatwootSchema, instanceSchema } from '@validate/validate.schema'; import { RequestHandler, Router } from 'express'; -import { Logger } from '../../../../config/logger.config'; -import { chatwootSchema, instanceNameSchema } from '../../../../validate/validate.schema'; -import { RouterBroker } from '../../../abstract/abstract.router'; -import { InstanceDto } from '../../../dto/instance.dto'; -import { HttpStatus } from '../../../routes/index.router'; -import { chatwootController } from '../../../server.module'; -import { ChatwootDto } from '../dto/chatwoot.dto'; - -const logger = new Logger('ChatwootRouter'); - export class ChatwootRouter extends RouterBroker { constructor(...guards: RequestHandler[]) { super(); this.router .post(this.routerPath('set'), ...guards, async (req, res) => { - logger.verbose('request received in setChatwoot'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); const response = await this.dataValidate({ request: req, schema: chatwootSchema, @@ -31,15 +21,9 @@ export class ChatwootRouter extends RouterBroker { res.status(HttpStatus.CREATED).json(response); }) .get(this.routerPath('find'), ...guards, async (req, res) => { - logger.verbose('request received in findChatwoot'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); const response = await this.dataValidate({ request: req, - schema: instanceNameSchema, + schema: instanceSchema, ClassRef: InstanceDto, execute: (instance) => chatwootController.findChatwoot(instance), }); @@ -47,15 +31,9 @@ export class ChatwootRouter extends RouterBroker { res.status(HttpStatus.OK).json(response); }) .post(this.routerPath('webhook'), async (req, res) => { - logger.verbose('request received in findChatwoot'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); const response = await this.dataValidate({ request: req, - schema: instanceNameSchema, + schema: instanceSchema, ClassRef: InstanceDto, execute: (instance, data) => chatwootController.receiveWebhook(instance, data), }); @@ -64,5 +42,5 @@ export class ChatwootRouter extends RouterBroker { }); } - public readonly router = Router(); + public readonly router: Router = Router(); } diff --git a/src/api/integrations/chatwoot/services/chatwoot.service.ts b/src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts similarity index 67% rename from src/api/integrations/chatwoot/services/chatwoot.service.ts rename to src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts index 4190267e..77b58bbe 100644 --- a/src/api/integrations/chatwoot/services/chatwoot.service.ts +++ b/src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts @@ -1,3 +1,14 @@ +import { InstanceDto } from '@api/dto/instance.dto'; +import { Options, Quoted, SendAudioDto, SendMediaDto, SendTextDto } from '@api/dto/sendMessage.dto'; +import { ChatwootDto } from '@api/integrations/chatbot/chatwoot/dto/chatwoot.dto'; +import { postgresClient } from '@api/integrations/chatbot/chatwoot/libs/postgres.client'; +import { chatwootImport } from '@api/integrations/chatbot/chatwoot/utils/chatwoot-import-helper'; +import { PrismaRepository } from '@api/repository/repository.service'; +import { CacheService } from '@api/services/cache.service'; +import { WAMonitoringService } from '@api/services/monitor.service'; +import { Events } from '@api/types/wa.types'; +import { Chatwoot, ConfigService, Database, HttpServer } from '@config/env.config'; +import { Logger } from '@config/logger.config'; import ChatwootClient, { ChatwootAPIConfig, contact, @@ -8,46 +19,49 @@ import ChatwootClient, { inbox, } from '@figuro/chatwoot-sdk'; import { request as chatwootRequest } from '@figuro/chatwoot-sdk/dist/core/request'; -import { proto } from '@whiskeysockets/baileys'; +import { Chatwoot as ChatwootModel, Contact as ContactModel, Message as MessageModel } from '@prisma/client'; +import i18next from '@utils/i18n'; +import { sendTelemetry } from '@utils/sendTelemetry'; import axios from 'axios'; +import { proto } from 'baileys'; +import dayjs from 'dayjs'; import FormData from 'form-data'; -import { createReadStream, unlinkSync, writeFileSync } from 'fs'; import Jimp from 'jimp'; +import Long from 'long'; import mimeTypes from 'mime-types'; import path from 'path'; +import { Readable } from 'stream'; -import { Chatwoot, ConfigService, HttpServer } from '../../../../config/env.config'; -import { Logger } from '../../../../config/logger.config'; -import i18next from '../../../../utils/i18n'; -import { ICache } from '../../../abstract/abstract.cache'; -import { InstanceDto } from '../../../dto/instance.dto'; -import { Options, Quoted, SendAudioDto, SendMediaDto, SendTextDto } from '../../../dto/sendMessage.dto'; -import { ChatwootRaw, ContactRaw, MessageRaw } from '../../../models'; -import { RepositoryBroker } from '../../../repository/repository.manager'; -import { WAMonitoringService } from '../../../services/monitor.service'; -import { Events } from '../../../types/wa.types'; -import { ChatwootDto } from '../dto/chatwoot.dto'; -import { chatwootImport } from '../utils/chatwoot-import-helper'; +interface ChatwootMessage { + messageId?: number; + inboxId?: number; + conversationId?: number; + contactInboxSourceId?: string; + isRead?: boolean; +} export class ChatwootService { - private readonly logger = new Logger(ChatwootService.name); + private readonly logger = new Logger('ChatwootService'); private provider: any; constructor( private readonly waMonitor: WAMonitoringService, private readonly configService: ConfigService, - private readonly repository: RepositoryBroker, - private readonly cache: ICache, + private readonly prismaRepository: PrismaRepository, + private readonly cache: CacheService, ) {} - private async getProvider(instance: InstanceDto) { + private pgClient = postgresClient.getChatwootConnection(); + + private async getProvider(instance: InstanceDto): Promise { const cacheKey = `${instance.instanceName}:getProvider`; if (await this.cache.has(cacheKey)) { - return (await this.cache.get(cacheKey)) as ChatwootRaw; + const provider = (await this.cache.get(cacheKey)) as ChatwootModel; + + return provider; } - this.logger.verbose('get provider to instance: ' + instance.instanceName); const provider = await this.waMonitor.waInstances[instance.instanceName]?.findChatwoot(); if (!provider) { @@ -55,16 +69,12 @@ export class ChatwootService { return null; } - this.logger.verbose('provider found'); - this.cache.set(cacheKey, provider); return provider; } private async clientCw(instance: InstanceDto) { - this.logger.verbose('get client to instance: ' + instance.instanceName); - const provider = await this.getProvider(instance); if (!provider) { @@ -72,28 +82,23 @@ export class ChatwootService { return null; } - this.logger.verbose('provider found'); - this.provider = provider; - this.logger.verbose('create client to instance: ' + instance.instanceName); const client = new ChatwootClient({ config: this.getClientCwConfig(), }); - this.logger.verbose('client created'); - return client; } - public getClientCwConfig(): ChatwootAPIConfig & { name_inbox: string; merge_brazil_contacts: boolean } { + public getClientCwConfig(): ChatwootAPIConfig & { nameInbox: string; mergeBrazilContacts: boolean } { return { basePath: this.provider.url, with_credentials: true, credentials: 'include', token: this.provider.token, - name_inbox: this.provider.name_inbox, - merge_brazil_contacts: this.provider.merge_brazil_contacts, + nameInbox: this.provider.nameInbox, + mergeBrazilContacts: this.provider.mergeBrazilContacts, }; } @@ -102,28 +107,26 @@ export class ChatwootService { } public async create(instance: InstanceDto, data: ChatwootDto) { - this.logger.verbose('create chatwoot: ' + instance.instanceName); - await this.waMonitor.waInstances[instance.instanceName].setChatwoot(data); - this.logger.verbose('chatwoot created'); - - if (data.auto_create) { + if (data.autoCreate) { + this.logger.log('Auto create chatwoot instance'); const urlServer = this.configService.get('SERVER').URL; await this.initInstanceChatwoot( instance, - data.name_inbox ?? instance.instanceName.split('-cwId-')[0], + data.nameInbox ?? instance.instanceName.split('-cwId-')[0], `${urlServer}/chatwoot/webhook/${encodeURIComponent(instance.instanceName)}`, true, data.number, + data.organization, + data.logo, ); } return data; } public async find(instance: InstanceDto): Promise { - this.logger.verbose('find chatwoot: ' + instance.instanceName); try { return await this.waMonitor.waInstances[instance.instanceName].findChatwoot(); } catch (error) { @@ -133,7 +136,6 @@ export class ChatwootService { } public async getContact(instance: InstanceDto, id: number) { - this.logger.verbose('get contact to instance: ' + instance.instanceName); const client = await this.clientCw(instance); if (!client) { @@ -146,9 +148,8 @@ export class ChatwootService { return null; } - this.logger.verbose('find contact in chatwoot'); const contact = await client.contact.getContactable({ - accountId: this.provider.account_id, + accountId: this.provider.accountId, id, }); @@ -157,7 +158,6 @@ export class ChatwootService { return null; } - this.logger.verbose('contact found'); return contact; } @@ -167,9 +167,9 @@ export class ChatwootService { webhookUrl: string, qrcode: boolean, number: string, + organization?: string, + logo?: string, ) { - this.logger.verbose('init instance chatwoot: ' + instance.instanceName); - const client = await this.clientCw(instance); if (!client) { @@ -177,25 +177,23 @@ export class ChatwootService { return null; } - this.logger.verbose('find inbox in chatwoot'); const findInbox: any = await client.inboxes.list({ - accountId: this.provider.account_id, + accountId: this.provider.accountId, }); - this.logger.verbose('check duplicate inbox'); const checkDuplicate = findInbox.payload.map((inbox) => inbox.name).includes(inboxName); let inboxId: number; + this.logger.log('Creating chatwoot inbox'); if (!checkDuplicate) { - this.logger.verbose('create inbox in chatwoot'); const data = { type: 'api', webhook_url: webhookUrl, }; const inbox = await client.inboxes.create({ - accountId: this.provider.account_id, + accountId: this.provider.accountId, data: { name: inboxName, channel: data as any, @@ -209,7 +207,6 @@ export class ChatwootService { inboxId = inbox.id; } else { - this.logger.verbose('find inbox in chatwoot'); const inbox = findInbox.payload.find((inbox) => inbox.name === inboxName); if (!inbox) { @@ -219,8 +216,15 @@ export class ChatwootService { inboxId = inbox.id; } + this.logger.log(`Inbox created - inboxId: ${inboxId}`); - this.logger.verbose('find contact in chatwoot and create if not exists'); + if (!this.configService.get('CHATWOOT').BOT_CONTACT) { + this.logger.log('Chatwoot bot contact is disabled'); + + return true; + } + + this.logger.log('Creating chatwoot bot contact'); const contact = (await this.findContact(instance, '123456')) || ((await this.createContact( @@ -228,8 +232,8 @@ export class ChatwootService { '123456', inboxId, false, - 'EvolutionAPI', - 'https://evolution-api.com/files/evolution-api-favicon.png', + organization ? organization : 'EvolutionAPI', + logo ? logo : 'https://evolution-api.com/files/evolution-api-favicon.png', )) as any); if (!contact) { @@ -238,16 +242,17 @@ export class ChatwootService { } const contactId = contact.id || contact.payload.contact.id; + this.logger.log(`Contact created - contactId: ${contactId}`); if (qrcode) { - this.logger.verbose('create conversation in chatwoot'); + this.logger.log('QR code enabled'); const data = { contact_id: contactId.toString(), inbox_id: inboxId.toString(), }; const conversation = await client.conversations.create({ - accountId: this.provider.account_id, + accountId: this.provider.accountId, data, }); @@ -256,8 +261,6 @@ export class ChatwootService { return null; } - this.logger.verbose('create message for init instance in chatwoot'); - let contentMsg = 'init'; if (number) { @@ -265,7 +268,7 @@ export class ChatwootService { } const message = await client.messages.create({ - accountId: this.provider.account_id, + accountId: this.provider.accountId, conversationId: conversation.id, data: { content: contentMsg, @@ -277,9 +280,9 @@ export class ChatwootService { this.logger.warn('conversation not found'); return null; } + this.logger.log('Init message sent'); } - this.logger.verbose('instance chatwoot initialized'); return true; } @@ -292,8 +295,6 @@ export class ChatwootService { avatar_url?: string, jid?: string, ) { - this.logger.verbose('create contact to instance: ' + instance.instanceName); - const client = await this.clientCw(instance); if (!client) { @@ -303,16 +304,17 @@ export class ChatwootService { let data: any = {}; if (!isGroup) { - this.logger.verbose('create contact in chatwoot'); data = { inbox_id: inboxId, name: name || phoneNumber, - phone_number: `+${phoneNumber}`, identifier: jid, avatar_url: avatar_url, }; + + if ((jid && jid.includes('@')) || !jid) { + data['phone_number'] = `+${phoneNumber}`; + } } else { - this.logger.verbose('create contact group in chatwoot'); data = { inbox_id: inboxId, name: name || phoneNumber, @@ -321,9 +323,8 @@ export class ChatwootService { }; } - this.logger.verbose('create contact in chatwoot'); const contact = await client.contacts.create({ - accountId: this.provider.account_id, + accountId: this.provider.accountId, data, }); @@ -332,12 +333,16 @@ export class ChatwootService { return null; } - this.logger.verbose('contact created'); + const findContact = await this.findContact(instance, phoneNumber); + + const contactId = findContact?.id; + + await this.addLabelToContact(this.provider.nameInbox, contactId); + return contact; } public async updateContact(instance: InstanceDto, id: number, data: any) { - this.logger.verbose('update contact to instance: ' + instance.instanceName); const client = await this.clientCw(instance); if (!client) { @@ -350,24 +355,57 @@ export class ChatwootService { return null; } - this.logger.verbose('update contact in chatwoot'); try { const contact = await client.contacts.update({ - accountId: this.provider.account_id, + accountId: this.provider.accountId, id, data, }); - this.logger.verbose('contact updated'); return contact; } catch (error) { - this.logger.error(error); + return null; + } + } + + public async addLabelToContact(nameInbox: string, contactId: number) { + try { + const uri = this.configService.get('CHATWOOT').IMPORT.DATABASE.CONNECTION.URI; + + if (!uri) return false; + + const sqlTags = `SELECT id, taggings_count FROM tags WHERE name = $1 LIMIT 1`; + const tagData = (await this.pgClient.query(sqlTags, [nameInbox]))?.rows[0]; + let tagId = tagData?.id; + const taggingsCount = tagData?.taggings_count || 0; + + const sqlTag = `INSERT INTO tags (name, taggings_count) + VALUES ($1, $2) + ON CONFLICT (name) + DO UPDATE SET taggings_count = tags.taggings_count + 1 + RETURNING id`; + + tagId = (await this.pgClient.query(sqlTag, [nameInbox, taggingsCount + 1]))?.rows[0]?.id; + + const sqlCheckTagging = `SELECT 1 FROM taggings + WHERE tag_id = $1 AND taggable_type = 'Contact' AND taggable_id = $2 AND context = 'labels' LIMIT 1`; + + const taggingExists = (await this.pgClient.query(sqlCheckTagging, [tagId, contactId]))?.rowCount > 0; + + if (!taggingExists) { + const sqlInsertLabel = `INSERT INTO taggings (tag_id, taggable_type, taggable_id, context, created_at) + VALUES ($1, 'Contact', $2, 'labels', NOW())`; + + await this.pgClient.query(sqlInsertLabel, [tagId, contactId]); + } + + return true; + } catch (error) { + return false; } } public async findContact(instance: InstanceDto, phoneNumber: string) { - this.logger.verbose('find contact to instance: ' + instance.instanceName); - const client = await this.clientCw(instance); if (!client) { @@ -379,26 +417,22 @@ export class ChatwootService { const isGroup = phoneNumber.includes('@g.us'); if (!isGroup) { - this.logger.verbose('format phone number'); query = `+${phoneNumber}`; } else { - this.logger.verbose('format group id'); query = phoneNumber; } - this.logger.verbose('find contact in chatwoot'); let contact: any; if (isGroup) { contact = await client.contacts.search({ - accountId: this.provider.account_id, + accountId: this.provider.accountId, q: query, }); } else { - // hotfix for: https://github.com/EvolutionAPI/evolution-api/pull/382. waiting fix: https://github.com/figurolatam/chatwoot-sdk/pull/7 contact = await chatwootRequest(this.getClientCwConfig(), { method: 'POST', - url: `/api/v1/accounts/${this.provider.account_id}/contacts/filter`, + url: `/api/v1/accounts/${this.provider.accountId}/contacts/filter`, body: { payload: this.getFilterPayload(query), }, @@ -411,21 +445,17 @@ export class ChatwootService { } if (!isGroup) { - this.logger.verbose('return contact'); return contact.payload.length > 1 ? this.findContactInContactList(contact.payload, query) : contact.payload[0]; } else { - this.logger.verbose('return group'); return contact.payload.find((contact) => contact.identifier === query); } } private async mergeBrazilianContacts(contacts: any[]) { try { - //sdk chatwoot não tem função merge - this.logger.verbose('merging contacts'); const contact = await chatwootRequest(this.getClientCwConfig(), { method: 'POST', - url: `/api/v1/accounts/${this.provider.account_id}/actions/contact_merge`, + url: `/api/v1/accounts/${this.provider.accountId}/actions/contact_merge`, body: { base_contact_id: contacts.find((contact) => contact.phone_number.length === 14)?.id, mergee_contact_id: contacts.find((contact) => contact.phone_number.length === 13)?.id, @@ -444,8 +474,7 @@ export class ChatwootService { const searchableFields = this.getSearchableFields(); // eslint-disable-next-line prettier/prettier - if(contacts.length === 2 && this.getClientCwConfig().merge_brazil_contacts && query.startsWith('+55')){ - + if (contacts.length === 2 && this.getClientCwConfig().mergeBrazilContacts && query.startsWith('+55')) { const contact = this.mergeBrazilianContacts(contacts); if (contact) { return contact; @@ -514,28 +543,37 @@ export class ChatwootService { } public async createConversation(instance: InstanceDto, body: any) { - this.logger.verbose('create conversation to instance: ' + instance.instanceName); try { + this.logger.verbose('--- Start createConversation ---'); + this.logger.verbose(`Instance: ${JSON.stringify(instance)}`); + const client = await this.clientCw(instance); if (!client) { - this.logger.warn('client not found'); + this.logger.warn(`Client not found for instance: ${JSON.stringify(instance)}`); return null; } const cacheKey = `${instance.instanceName}:createConversation-${body.key.remoteJid}`; + this.logger.verbose(`Cache key: ${cacheKey}`); + if (await this.cache.has(cacheKey)) { + this.logger.verbose(`Cache hit for key: ${cacheKey}`); const conversationId = (await this.cache.get(cacheKey)) as number; + this.logger.verbose(`Cached conversation ID: ${conversationId}`); let conversationExists: conversation | boolean; try { conversationExists = await client.conversations.get({ - accountId: this.provider.account_id, + accountId: this.provider.accountId, conversationId: conversationId, }); + this.logger.verbose(`Conversation exists: ${JSON.stringify(conversationExists)}`); } catch (error) { + this.logger.error(`Error getting conversation: ${error}`); conversationExists = false; } if (!conversationExists) { + this.logger.verbose('Conversation does not exist, re-calling createConversation'); this.cache.delete(cacheKey); return await this.createConversation(instance, body); } @@ -544,38 +582,37 @@ export class ChatwootService { } const isGroup = body.key.remoteJid.includes('@g.us'); - - this.logger.verbose('is group: ' + isGroup); + this.logger.verbose(`Is group: ${isGroup}`); const chatId = isGroup ? body.key.remoteJid : body.key.remoteJid.split('@')[0]; - - this.logger.verbose('chat id: ' + chatId); + this.logger.verbose(`Chat ID: ${chatId}`); let nameContact: string; nameContact = !body.key.fromMe ? body.pushName : chatId; + this.logger.verbose(`Name contact: ${nameContact}`); - this.logger.verbose('get inbox to instance: ' + instance.instanceName); const filterInbox = await this.getInbox(instance); if (!filterInbox) { - this.logger.warn('inbox not found'); + this.logger.warn(`Inbox not found for instance: ${JSON.stringify(instance)}`); return null; } if (isGroup) { - this.logger.verbose('get group name'); + this.logger.verbose('Processing group conversation'); const group = await this.waMonitor.waInstances[instance.instanceName].client.groupMetadata(chatId); + this.logger.verbose(`Group metadata: ${JSON.stringify(group)}`); nameContact = `${group.subject} (GROUP)`; - this.logger.verbose('find or create participant in chatwoot'); - const picture_url = await this.waMonitor.waInstances[instance.instanceName].profilePicture( body.key.participant.split('@')[0], ); + this.logger.verbose(`Participant profile picture URL: ${JSON.stringify(picture_url)}`); const findParticipant = await this.findContact(instance, body.key.participant.split('@')[0]); + this.logger.verbose(`Found participant: ${JSON.stringify(findParticipant)}`); if (findParticipant) { if (!findParticipant.name || findParticipant.name === chatId) { @@ -597,11 +634,11 @@ export class ChatwootService { } } - this.logger.verbose('find or create contact in chatwoot'); - const picture_url = await this.waMonitor.waInstances[instance.instanceName].profilePicture(chatId); + this.logger.verbose(`Contact profile picture URL: ${JSON.stringify(picture_url)}`); let contact = await this.findContact(instance, chatId); + this.logger.verbose(`Found contact: ${JSON.stringify(contact)}`); if (contact) { if (!body.key.fromMe) { @@ -618,9 +655,10 @@ export class ChatwootService { ) : false); - const contactNeedsUpdate = pictureNeedsUpdate || nameNeedsUpdate; - if (contactNeedsUpdate) { - this.logger.verbose('update contact in chatwoot'); + this.logger.verbose(`Picture needs update: ${pictureNeedsUpdate}`); + this.logger.verbose(`Name needs update: ${nameNeedsUpdate}`); + + if (pictureNeedsUpdate || nameNeedsUpdate) { contact = await this.updateContact(instance, contact.id, { ...(nameNeedsUpdate && { name: nameContact }), ...(waProfilePictureFile === '' && { avatar: null }), @@ -629,7 +667,7 @@ export class ChatwootService { } } } else { - const jid = isGroup ? null : body.key.remoteJid; + const jid = body.key.remoteJid; contact = await this.createContact( instance, chatId, @@ -642,77 +680,83 @@ export class ChatwootService { } if (!contact) { - this.logger.warn('contact not found'); + this.logger.warn('Contact not created or found'); return null; } const contactId = contact?.payload?.id || contact?.payload?.contact?.id || contact?.id; + this.logger.verbose(`Contact ID: ${contactId}`); - this.logger.verbose('get contact conversations in chatwoot'); const contactConversations = (await client.contacts.listConversations({ - accountId: this.provider.account_id, + accountId: this.provider.accountId, id: contactId, })) as any; + this.logger.verbose(`Contact conversations: ${JSON.stringify(contactConversations)}`); - if (contactConversations?.payload?.length) { + if (!contactConversations || !contactConversations.payload) { + this.logger.error('No conversations found or payload is undefined'); + return null; + } + + if (contactConversations.payload.length) { let conversation: any; - if (this.provider.reopen_conversation) { + if (this.provider.reopenConversation) { conversation = contactConversations.payload.find((conversation) => conversation.inbox_id == filterInbox.id); + this.logger.verbose(`Found conversation in reopenConversation mode: ${JSON.stringify(conversation)}`); - if (this.provider.conversation_pending) { - await client.conversations.toggleStatus({ - accountId: this.provider.account_id, - conversationId: conversation.id, - data: { - status: 'pending', - }, - }); + if (this.provider.conversationPending && conversation.status !== 'open') { + if (conversation) { + await client.conversations.toggleStatus({ + accountId: this.provider.accountId, + conversationId: conversation.id, + data: { + status: 'pending', + }, + }); + } } } else { conversation = contactConversations.payload.find( (conversation) => conversation.status !== 'resolved' && conversation.inbox_id == filterInbox.id, ); + this.logger.verbose(`Found conversation: ${JSON.stringify(conversation)}`); } - this.logger.verbose('return conversation if exists'); if (conversation) { - this.logger.verbose('conversation found'); + this.logger.verbose(`Returning existing conversation ID: ${conversation.id}`); this.cache.set(cacheKey, conversation.id); return conversation.id; } } - this.logger.verbose('create conversation in chatwoot'); const data = { contact_id: contactId.toString(), inbox_id: filterInbox.id.toString(), }; - if (this.provider.conversation_pending) { + if (this.provider.conversationPending) { data['status'] = 'pending'; } const conversation = await client.conversations.create({ - accountId: this.provider.account_id, + accountId: this.provider.accountId, data, }); if (!conversation) { - this.logger.warn('conversation not found'); + this.logger.warn('Conversation not created or found'); return null; } - this.logger.verbose('conversation created'); + this.logger.verbose(`New conversation created with ID: ${conversation.id}`); this.cache.set(cacheKey, conversation.id); return conversation.id; } catch (error) { - this.logger.error(error); + this.logger.error(`Error in createConversation: ${error}`); } } - public async getInbox(instance: InstanceDto) { - this.logger.verbose('get inbox to instance: ' + instance.instanceName); - + public async getInbox(instance: InstanceDto): Promise { const cacheKey = `${instance.instanceName}:getInbox`; if (await this.cache.has(cacheKey)) { return (await this.cache.get(cacheKey)) as inbox; @@ -725,9 +769,8 @@ export class ChatwootService { return null; } - this.logger.verbose('find inboxes in chatwoot'); const inbox = (await client.inboxes.list({ - accountId: this.provider.account_id, + accountId: this.provider.accountId, })) as any; if (!inbox) { @@ -735,15 +778,13 @@ export class ChatwootService { return null; } - this.logger.verbose('find inbox by name'); - const findByName = inbox.payload.find((inbox) => inbox.name === this.getClientCwConfig().name_inbox); + const findByName = inbox.payload.find((inbox) => inbox.name === this.getClientCwConfig().nameInbox); if (!findByName) { this.logger.warn('inbox not found'); return null; } - this.logger.verbose('return inbox'); this.cache.set(cacheKey, findByName); return findByName; } @@ -761,9 +802,8 @@ export class ChatwootService { }[], messageBody?: any, sourceId?: string, + quotedMsg?: MessageModel, ) { - this.logger.verbose('create message to instance: ' + instance.instanceName); - const client = await this.clientCw(instance); if (!client) { @@ -773,9 +813,10 @@ export class ChatwootService { const replyToIds = await this.getReplyToIds(messageBody, instance); - this.logger.verbose('create message in chatwoot'); + const sourceReplyId = quotedMsg?.chatwootMessageId || null; + const message = await client.messages.create({ - accountId: this.provider.account_id, + accountId: this.provider.accountId, conversationId: conversationId, data: { content: content, @@ -786,6 +827,7 @@ export class ChatwootService { content_attributes: { ...replyToIds, }, + source_reply_id: sourceReplyId ? sourceReplyId.toString() : null, }, }); @@ -794,8 +836,6 @@ export class ChatwootService { return null; } - this.logger.verbose('message created'); - return message; } @@ -804,8 +844,6 @@ export class ChatwootService { inbox: inbox, contact: generic_id & contact, ): Promise { - this.logger.verbose('find conversation in chatwoot'); - const client = await this.clientCw(instance); if (!client) { @@ -814,7 +852,7 @@ export class ChatwootService { } const conversations = (await client.contacts.listConversations({ - accountId: this.provider.account_id, + accountId: this.provider.accountId, id: contact.id, })) as any; @@ -835,8 +873,6 @@ export class ChatwootService { filename: string; }[], ) { - this.logger.verbose('create bot message to instance: ' + instance.instanceName); - const client = await this.clientCw(instance); if (!client) { @@ -844,7 +880,6 @@ export class ChatwootService { return null; } - this.logger.verbose('find contact in chatwoot'); const contact = await this.findContact(instance, '123456'); if (!contact) { @@ -852,7 +887,6 @@ export class ChatwootService { return null; } - this.logger.verbose('get inbox to instance: ' + instance.instanceName); const filterInbox = await this.getInbox(instance); if (!filterInbox) { @@ -867,9 +901,8 @@ export class ChatwootService { return; } - this.logger.verbose('create message in chatwoot'); const message = await client.messages.create({ - accountId: this.provider.account_id, + accountId: this.provider.accountId, conversationId: conversation.id, data: { content: content, @@ -883,54 +916,64 @@ export class ChatwootService { return null; } - this.logger.verbose('bot message created'); - return message; } private async sendData( conversationId: number, - file: string, + fileStream: Readable, + fileName: string, messageType: 'incoming' | 'outgoing' | undefined, content?: string, instance?: InstanceDto, messageBody?: any, sourceId?: string, + quotedMsg?: MessageModel, ) { - this.logger.verbose('send data to chatwoot'); - + if (sourceId && this.isImportHistoryAvailable()) { + const messageAlreadySaved = await chatwootImport.getExistingSourceIds([sourceId]); + if (messageAlreadySaved) { + if (messageAlreadySaved.size > 0) { + this.logger.warn('Message already saved on chatwoot'); + return null; + } + } + } const data = new FormData(); if (content) { - this.logger.verbose('content found'); data.append('content', content); } - this.logger.verbose('message type: ' + messageType); data.append('message_type', messageType); - this.logger.verbose('temp file found'); - data.append('attachments[]', createReadStream(file)); + data.append('attachments[]', fileStream, { filename: fileName }); + + const sourceReplyId = quotedMsg?.chatwootMessageId || null; if (messageBody && instance) { const replyToIds = await this.getReplyToIds(messageBody, instance); if (replyToIds.in_reply_to || replyToIds.in_reply_to_external_id) { - data.append('content_attributes', { + const content = JSON.stringify({ ...replyToIds, }); + data.append('content_attributes', content); } } + if (sourceReplyId) { + data.append('source_reply_id', sourceReplyId.toString()); + } + if (sourceId) { data.append('source_id', sourceId); } - this.logger.verbose('get client to instance: ' + this.provider.instanceName); const config = { method: 'post', maxBodyLength: Infinity, - url: `${this.provider.url}/api/v1/accounts/${this.provider.account_id}/conversations/${conversationId}/messages`, + url: `${this.provider.url}/api/v1/accounts/${this.provider.accountId}/conversations/${conversationId}/messages`, headers: { api_access_token: this.provider.token, ...data.getHeaders(), @@ -938,18 +981,12 @@ export class ChatwootService { data: data, }; - this.logger.verbose('send data to chatwoot'); try { const { data } = await axios.request(config); - this.logger.verbose('remove temp file'); - unlinkSync(file); - - this.logger.verbose('data sent'); return data; } catch (error) { this.logger.error(error); - unlinkSync(file); } } @@ -957,9 +994,9 @@ export class ChatwootService { instance: InstanceDto, content: string, messageType: 'incoming' | 'outgoing' | undefined, - file?: string, + fileStream?: Readable, + fileName?: string, ) { - this.logger.verbose('create bot qr to instance: ' + instance.instanceName); const client = await this.clientCw(instance); if (!client) { @@ -967,7 +1004,12 @@ export class ChatwootService { return null; } - this.logger.verbose('find contact in chatwoot'); + if (!this.configService.get('CHATWOOT').BOT_CONTACT) { + this.logger.log('Chatwoot bot contact is disabled'); + + return true; + } + const contact = await this.findContact(instance, '123456'); if (!contact) { @@ -975,7 +1017,6 @@ export class ChatwootService { return null; } - this.logger.verbose('get inbox to instance: ' + instance.instanceName); const filterInbox = await this.getInbox(instance); if (!filterInbox) { @@ -990,27 +1031,22 @@ export class ChatwootService { return; } - this.logger.verbose('send data to chatwoot'); const data = new FormData(); if (content) { - this.logger.verbose('content found'); data.append('content', content); } - this.logger.verbose('message type: ' + messageType); data.append('message_type', messageType); - if (file) { - this.logger.verbose('temp file found'); - data.append('attachments[]', createReadStream(file)); + if (fileStream && fileName) { + data.append('attachments[]', fileStream, { filename: fileName }); } - this.logger.verbose('get client to instance: ' + this.provider.instanceName); const config = { method: 'post', maxBodyLength: Infinity, - url: `${this.provider.url}/api/v1/accounts/${this.provider.account_id}/conversations/${conversation.id}/messages`, + url: `${this.provider.url}/api/v1/accounts/${this.provider.accountId}/conversations/${conversation.id}/messages`, headers: { api_access_token: this.provider.token, ...data.getHeaders(), @@ -1018,14 +1054,9 @@ export class ChatwootService { data: data, }; - this.logger.verbose('send data to chatwoot'); try { const { data } = await axios.request(config); - this.logger.verbose('remove temp file'); - unlinkSync(file); - - this.logger.verbose('data sent'); return data; } catch (error) { this.logger.error(error); @@ -1033,10 +1064,7 @@ export class ChatwootService { } public async sendAttachment(waInstance: any, number: string, media: any, caption?: string, options?: Options) { - this.logger.verbose('send attachment to instance: ' + waInstance.instanceName); - try { - this.logger.verbose('get media type'); const parsedMedia = path.parse(decodeURIComponent(media)); let mimeType = mimeTypes.lookup(parsedMedia?.ext) || ''; let fileName = parsedMedia?.name + parsedMedia?.ext; @@ -1044,13 +1072,11 @@ export class ChatwootService { if (!mimeType) { const parts = media.split('/'); fileName = decodeURIComponent(parts[parts.length - 1]); - this.logger.verbose('file name: ' + fileName); const response = await axios.get(media, { responseType: 'arraybuffer', }); mimeType = response.headers['content-type']; - this.logger.verbose('mime type: ' + mimeType); } let type = 'document'; @@ -1070,70 +1096,77 @@ export class ChatwootService { break; } - this.logger.verbose('type: ' + type); - if (type === 'audio') { - this.logger.verbose('send audio to instance: ' + waInstance.instanceName); const data: SendAudioDto = { number: number, - audioMessage: { - audio: media, - }, - options: { - delay: 1200, - presence: 'recording', - ...options, - }, + audio: media, + delay: 1200, + quoted: options?.quoted, }; + sendTelemetry('/message/sendWhatsAppAudio'); + const messageSent = await waInstance?.audioWhatsapp(data, true); - this.logger.verbose('audio sent'); return messageSent; } - this.logger.verbose('send media to instance: ' + waInstance.instanceName); - const data: SendMediaDto = { - number: number, - mediaMessage: { - mediatype: type as any, - fileName: fileName, - media: media, - }, - options: { - delay: 1200, - presence: 'composing', - ...options, - }, - }; - - if (caption) { - this.logger.verbose('caption found'); - data.mediaMessage.caption = caption; + if (type === 'image' && parsedMedia && parsedMedia?.ext === '.gif') { + type = 'document'; } - const messageSent = await waInstance?.mediaMessage(data, true); + const data: SendMediaDto = { + number: number, + mediatype: type as any, + fileName: fileName, + media: media, + delay: 1200, + quoted: options?.quoted, + }; + + sendTelemetry('/message/sendMedia'); + + if (caption) { + data.caption = caption; + } + + const messageSent = await waInstance?.mediaMessage(data, null, true); - this.logger.verbose('media sent'); return messageSent; } catch (error) { this.logger.error(error); } } - public async onSendMessageError(instance: InstanceDto, conversation: number, error?: string) { + public async onSendMessageError(instance: InstanceDto, conversation: number, error?: any) { + this.logger.verbose(`onSendMessageError ${JSON.stringify(error)}`); + const client = await this.clientCw(instance); if (!client) { return; } + if (error && error?.status === 400 && error?.message[0]?.exists === false) { + client.messages.create({ + accountId: this.provider.accountId, + conversationId: conversation, + data: { + content: `${i18next.t('cw.message.numbernotinwhatsapp')}`, + message_type: 'outgoing', + private: true, + }, + }); + + return; + } + client.messages.create({ - accountId: this.provider.account_id, + accountId: this.provider.accountId, conversationId: conversation, data: { content: i18next.t('cw.message.notsent', { - error: error?.length > 0 ? `_${error}_` : '', + error: error ? `_${error.toString()}_` : '', }), message_type: 'outgoing', private: true, @@ -1145,7 +1178,6 @@ export class ChatwootService { try { await new Promise((resolve) => setTimeout(resolve, 500)); - this.logger.verbose('receive webhook to chatwoot instance: ' + instance.instanceName); const client = await this.clientCw(instance); if (!client) { @@ -1153,9 +1185,8 @@ export class ChatwootService { return null; } - // invalidate the conversation cache if reopen_conversation is false and the conversation was resolved if ( - this.provider.reopen_conversation === false && + this.provider.reopenConversation === false && body.event === 'conversation_status_changed' && body.status === 'resolved' && body.meta?.sender?.identifier @@ -1164,7 +1195,6 @@ export class ChatwootService { this.cache.delete(keyToDelete); } - this.logger.verbose('check if is bot'); if ( !body?.conversation || body.private || @@ -1173,9 +1203,8 @@ export class ChatwootService { return { message: 'bot' }; } - this.logger.verbose('check if is group'); const chatId = - body.conversation.meta.sender?.phone_number?.replace('+', '') || body.conversation.meta.sender?.identifier; + body.conversation.meta.sender?.identifier || body.conversation.meta.sender?.phone_number.replace('+', ''); // Chatwoot to Whatsapp const messageReceived = body.content ? body.content @@ -1188,52 +1217,46 @@ export class ChatwootService { const senderName = body?.conversation?.messages[0]?.sender?.available_name || body?.sender?.name; const waInstance = this.waMonitor.waInstances[instance.instanceName]; - this.logger.verbose('check if is a message deletion'); if (body.event === 'message_updated' && body.content_attributes?.deleted) { - const message = await this.repository.message.find({ + const message = await this.prismaRepository.message.findFirst({ where: { - owner: instance.instanceName, - chatwoot: { - messageId: body.id, - }, + chatwootMessageId: body.id, + instanceId: instance.instanceId, }, - limit: 1, }); - if (message.length && message[0].key?.id) { - this.logger.verbose('deleting message in whatsapp. Message id: ' + message[0].key.id); - await waInstance?.client.sendMessage(message[0].key.remoteJid, { delete: message[0].key }); - this.logger.verbose('deleting message in repository. Message id: ' + message[0].key.id); - this.repository.message.delete({ + if (message) { + const key = message.key as { + id: string; + remoteJid: string; + fromMe: boolean; + participant: string; + }; + + await waInstance?.client.sendMessage(key.remoteJid, { delete: key }); + + await this.prismaRepository.message.deleteMany({ where: { - owner: instance.instanceName, - chatwoot: { - messageId: body.id, - }, + instanceId: instance.instanceId, + chatwootMessageId: body.id, }, }); } return { message: 'bot' }; } - if (chatId === '123456' && body.message_type === 'outgoing') { - this.logger.verbose('check if is command'); + const cwBotContact = this.configService.get('CHATWOOT').BOT_CONTACT; + if (chatId === '123456' && body.message_type === 'outgoing') { const command = messageReceived.replace('/', ''); - if (command.includes('init') || command.includes('iniciar')) { - this.logger.verbose('command init found'); + if (cwBotContact && (command.includes('init') || command.includes('iniciar'))) { const state = waInstance?.connectionStatus?.state; if (state !== 'open') { - if (state === 'close') { - this.logger.verbose('request cleaning up instance: ' + instance.instanceName); - } - this.logger.verbose('connect to whatsapp'); const number = command.split(':')[1]; await waInstance.connectToWhatsapp(number); } else { - this.logger.verbose('whatsapp already connected'); await this.createBotMessage( instance, i18next.t('cw.inbox.alreadyConnected', { @@ -1245,7 +1268,6 @@ export class ChatwootService { } if (command === 'clearcache') { - this.logger.verbose('command clearcache found'); waInstance.clearCacheChatwoot(); await this.createBotMessage( instance, @@ -1257,12 +1279,9 @@ export class ChatwootService { } if (command === 'status') { - this.logger.verbose('command status found'); - const state = waInstance?.connectionStatus?.state; if (!state) { - this.logger.verbose('state not found'); await this.createBotMessage( instance, i18next.t('cw.inbox.notFound', { @@ -1273,7 +1292,6 @@ export class ChatwootService { } if (state) { - this.logger.verbose('state: ' + state + ' found'); await this.createBotMessage( instance, i18next.t('cw.inbox.status', { @@ -1285,27 +1303,20 @@ export class ChatwootService { } } - if (command === 'disconnect' || command === 'desconectar') { - this.logger.verbose('command disconnect found'); - + if (cwBotContact && (command === 'disconnect' || command === 'desconectar')) { const msgLogout = i18next.t('cw.inbox.disconnect', { inboxName: body.inbox.name, }); - this.logger.verbose('send message to chatwoot'); await this.createBotMessage(instance, msgLogout, 'incoming'); - this.logger.verbose('disconnect to whatsapp'); await waInstance?.client?.logout('Log out instance: ' + instance.instanceName); await waInstance?.client?.ws?.close(); } } if (body.message_type === 'outgoing' && body?.conversation?.messages?.length && chatId !== '123456') { - this.logger.verbose('check if is group'); - if (body?.conversation?.messages[0]?.source_id?.substring(0, 5) === 'WAID:') { - this.logger.verbose('message sent directly from whatsapp. Webhook ignored.'); return { message: 'bot' }; } @@ -1314,28 +1325,23 @@ export class ChatwootService { return { message: 'bot' }; } - this.logger.verbose('Format message to send'); let formatText: string; if (senderName === null || senderName === undefined) { formatText = messageReceived; } else { - const formattedDelimiter = this.provider.sign_delimiter - ? this.provider.sign_delimiter.replaceAll('\\n', '\n') + const formattedDelimiter = this.provider.signDelimiter + ? this.provider.signDelimiter.replaceAll('\\n', '\n') : '\n'; - const textToConcat = this.provider.sign_msg ? [`*${senderName}:*`] : []; + const textToConcat = this.provider.signMsg ? [`*${senderName}:*`] : []; textToConcat.push(messageReceived); formatText = textToConcat.join(formattedDelimiter); } for (const message of body.conversation.messages) { - this.logger.verbose('check if message is media'); if (message.attachments && message.attachments.length > 0) { - this.logger.verbose('message is media'); for (const attachment of message.attachments) { - this.logger.verbose('send media to whatsapp'); if (!messageReceived) { - this.logger.verbose('message do not have text'); formatText = null; } @@ -1354,7 +1360,7 @@ export class ChatwootService { this.onSendMessageError(instance, body.conversation?.id); } - this.updateChatwootMessageId( + await this.updateChatwootMessageId( { ...messageSent, owner: instance.instanceName, @@ -1363,54 +1369,48 @@ export class ChatwootService { messageId: body.id, inboxId: body.inbox?.id, conversationId: body.conversation?.id, - contactInbox: { - sourceId: body.conversation?.contact_inbox?.source_id, - }, + contactInboxSourceId: body.conversation?.contact_inbox?.source_id, }, instance, ); } } else { - this.logger.verbose('message is text'); - - this.logger.verbose('send text to whatsapp'); const data: SendTextDto = { number: chatId, - textMessage: { - text: formatText, - }, - options: { - delay: 1200, - presence: 'composing', - quoted: await this.getQuotedMessage(body, instance), - }, + text: formatText, + delay: 1200, + quoted: await this.getQuotedMessage(body, instance), }; - let messageSent: MessageRaw | proto.WebMessageInfo; + sendTelemetry('/message/sendText'); + + let messageSent: any; try { messageSent = await waInstance?.textMessage(data, true); if (!messageSent) { throw new Error('Message not sent'); } - this.updateChatwootMessageId( + if (Long.isLong(messageSent?.messageTimestamp)) { + messageSent.messageTimestamp = messageSent.messageTimestamp?.toNumber(); + } + + await this.updateChatwootMessageId( { ...messageSent, - owner: instance.instanceName, + instanceId: instance.instanceId, }, { messageId: body.id, inboxId: body.inbox?.id, conversationId: body.conversation?.id, - contactInbox: { - sourceId: body.conversation?.contact_inbox?.source_id, - }, + contactInboxSourceId: body.conversation?.contact_inbox?.source_id, }, instance, ); } catch (error) { if (!messageSent && body.conversation?.id) { - this.onSendMessageError(instance, body.conversation?.id, error.toString()); + this.onSendMessageError(instance, body.conversation?.id, error); } throw error; } @@ -1419,51 +1419,62 @@ export class ChatwootService { const chatwootRead = this.configService.get('CHATWOOT').MESSAGE_READ; if (chatwootRead) { - const lastMessage = await this.repository.message.find({ + const lastMessage = await this.prismaRepository.message.findFirst({ where: { key: { - fromMe: false, + path: ['fromMe'], + equals: false, }, - owner: instance.instanceName, + instanceId: instance.instanceId, }, - limit: 1, }); - if (lastMessage.length > 0 && !lastMessage[0].chatwoot?.isRead) { + if (lastMessage && !lastMessage.chatwootIsRead) { + const key = lastMessage.key as { + id: string; + fromMe: boolean; + remoteJid: string; + participant?: string; + }; + waInstance?.markMessageAsRead({ - read_messages: lastMessage.map((msg) => ({ - id: msg.key?.id, - fromMe: msg.key?.fromMe, - remoteJid: msg.key?.remoteJid, - })), + readMessages: [ + { + id: key.id, + fromMe: key.fromMe, + remoteJid: key.remoteJid, + }, + ], }); - const updateMessage = lastMessage.map((msg) => ({ - key: msg.key, - owner: msg.owner, - chatwoot: { - ...msg.chatwoot, - isRead: true, + const updateMessage = { + chatwootMessageId: lastMessage.chatwootMessageId, + chatwootConversationId: lastMessage.chatwootConversationId, + chatwootInboxId: lastMessage.chatwootInboxId, + chatwootContactInboxSourceId: lastMessage.chatwootContactInboxSourceId, + chatwootIsRead: true, + }; + + await this.prismaRepository.message.updateMany({ + where: { + instanceId: instance.instanceId, + key: { + path: ['id'], + equals: key.id, + }, }, - })); - this.repository.message.update(updateMessage, instance.instanceName, true); + data: updateMessage, + }); } } } if (body.message_type === 'template' && body.event === 'message_created') { - this.logger.verbose('check if is template'); - const data: SendTextDto = { number: chatId, - textMessage: { - text: body.content.replace(/\\\r\n|\\\n|\n/g, '\n'), - }, - options: { - delay: 1200, - presence: 'composing', - }, + text: body.content.replace(/\\\r\n|\\\n|\n/g, '\n'), + delay: 1200, }; - this.logger.verbose('send text to whatsapp'); + sendTelemetry('/message/sendText'); await waInstance?.textMessage(data); } @@ -1476,31 +1487,56 @@ export class ChatwootService { } } - private updateChatwootMessageId( - message: MessageRaw, - chatwootMessageIds: MessageRaw['chatwoot'], + private async updateChatwootMessageId( + message: MessageModel, + chatwootMessageIds: ChatwootMessage, instance: InstanceDto, ) { - if (!chatwootMessageIds.messageId || !message?.key?.id) { + const key = message.key as { + id: string; + fromMe: boolean; + remoteJid: string; + participant?: string; + }; + + if (!chatwootMessageIds.messageId || !key?.id) { return; } - message.chatwoot = chatwootMessageIds; - this.repository.message.update([message], instance.instanceName, true); - } - - private async getMessageByKeyId(instance: InstanceDto, keyId: string): Promise { - const messages = await this.repository.message.find({ + await this.prismaRepository.message.updateMany({ where: { key: { - id: keyId, + path: ['id'], + equals: key.id, }, - owner: instance.instanceName, + instanceId: instance.instanceId, + }, + data: { + chatwootMessageId: chatwootMessageIds.messageId, + chatwootConversationId: chatwootMessageIds.conversationId, + chatwootInboxId: chatwootMessageIds.inboxId, + chatwootContactInboxSourceId: chatwootMessageIds.contactInboxSourceId, + chatwootIsRead: chatwootMessageIds.isRead, }, - limit: 1, }); - return messages.length ? messages[0] : null; + if (this.isImportHistoryAvailable()) { + chatwootImport.updateMessageSourceID(chatwootMessageIds.messageId, key.id); + } + } + + private async getMessageByKeyId(instance: InstanceDto, keyId: string): Promise { + const messages = await this.prismaRepository.message.findFirst({ + where: { + key: { + path: ['id'], + equals: keyId, + }, + instanceId: instance.instanceId, + }, + }); + + return messages || null; } private async getReplyToIds( @@ -1511,11 +1547,11 @@ export class ChatwootService { let inReplyToExternalId = null; if (msg) { - inReplyToExternalId = msg.message?.extendedTextMessage?.contextInfo?.stanzaId; + inReplyToExternalId = msg.message?.extendedTextMessage?.contextInfo?.stanzaId ?? msg.contextInfo?.stanzaId; if (inReplyToExternalId) { const message = await this.getMessageByKeyId(instance, inReplyToExternalId); - if (message?.chatwoot?.messageId) { - inReplyTo = message.chatwoot.messageId; + if (message?.chatwootMessageId) { + inReplyTo = message.chatwootMessageId; } } } @@ -1528,19 +1564,24 @@ export class ChatwootService { private async getQuotedMessage(msg: any, instance: InstanceDto): Promise { if (msg?.content_attributes?.in_reply_to) { - const message = await this.repository.message.find({ + const message = await this.prismaRepository.message.findFirst({ where: { - chatwoot: { - messageId: msg?.content_attributes?.in_reply_to, - }, - owner: instance.instanceName, + chatwootMessageId: msg?.content_attributes?.in_reply_to, + instanceId: instance.instanceId, }, - limit: 1, }); - if (message.length && message[0]?.key?.id) { + + const key = message?.key as { + id: string; + fromMe: boolean; + remoteJid: string; + participant?: string; + }; + + if (message && key?.id) { return { - key: message[0].key, - message: message[0].message, + key: message.key as proto.IMessageKey, + message: message.message as proto.IMessage, }; } } @@ -1549,7 +1590,6 @@ export class ChatwootService { } private isMediaMessage(message: any) { - this.logger.verbose('check if is media message'); const media = [ 'imageMessage', 'documentMessage', @@ -1557,13 +1597,13 @@ export class ChatwootService { 'audioMessage', 'videoMessage', 'stickerMessage', + 'viewOnceMessageV2', ]; const messageKeys = Object.keys(message); const result = messageKeys.some((key) => media.includes(key)); - this.logger.verbose('is media message: ' + result); return result; } @@ -1574,28 +1614,36 @@ export class ChatwootService { thumbnailUrl: string; sourceUrl: string; } - const adsMessage: AdsMessage | undefined = msg.extendedTextMessage?.contextInfo?.externalAdReply; - this.logger.verbose('Get ads message if it exist'); - adsMessage && this.logger.verbose('Ads message: ' + adsMessage); + const adsMessage: AdsMessage | undefined = { + title: msg.extendedTextMessage?.contextInfo?.externalAdReply?.title || msg.contextInfo?.externalAdReply?.title, + body: msg.extendedTextMessage?.contextInfo?.externalAdReply?.body || msg.contextInfo?.externalAdReply?.body, + thumbnailUrl: + msg.extendedTextMessage?.contextInfo?.externalAdReply?.thumbnailUrl || + msg.contextInfo?.externalAdReply?.thumbnailUrl, + sourceUrl: + msg.extendedTextMessage?.contextInfo?.externalAdReply?.sourceUrl || msg.contextInfo?.externalAdReply?.sourceUrl, + }; + return adsMessage; } private getReactionMessage(msg: any) { interface ReactionMessage { - key: MessageRaw['key']; + key: { + id: string; + fromMe: boolean; + remoteJid: string; + participant?: string; + }; text: string; } const reactionMessage: ReactionMessage | undefined = msg?.reactionMessage; - this.logger.verbose('Get reaction message if it exists'); - reactionMessage && this.logger.verbose('Reaction message: ' + reactionMessage); return reactionMessage; } private getTypeMessage(msg: any) { - this.logger.verbose('get type message'); - const types = { conversation: msg.conversation, imageMessage: msg.imageMessage?.caption, @@ -1612,18 +1660,24 @@ export class ChatwootService { liveLocationMessage: msg.liveLocationMessage, listMessage: msg.listMessage, listResponseMessage: msg.listResponseMessage, + viewOnceMessageV2: + msg?.message?.viewOnceMessageV2?.message?.imageMessage?.url || + msg?.message?.viewOnceMessageV2?.message?.videoMessage?.url || + msg?.message?.viewOnceMessageV2?.message?.audioMessage?.url, }; - this.logger.verbose('type message: ' + types); - return types; } private getMessageContent(types: any) { - this.logger.verbose('get message content'); const typeKey = Object.keys(types).find((key) => types[key] !== undefined); - const result = typeKey ? types[typeKey] : undefined; + let result = typeKey ? types[typeKey] : undefined; + + // Remove externalAdReplyBody| in Chatwoot (Already Have) + if (result && typeof result === 'string' && result.includes('externalAdReplyBody|')) { + result = result.split('externalAdReplyBody|').filter(Boolean).join(''); + } if (typeKey === 'locationMessage' || typeKey === 'liveLocationMessage') { const latitude = result.degreesLatitude; @@ -1641,8 +1695,6 @@ export class ChatwootService { `_${i18next.t('cw.locationMessage.locationUrl')}:_ ` + `https://www.google.com/maps/search/?api=1&query=${latitude},${longitude}`; - this.logger.verbose('message content: ' + formattedLocation); - return formattedLocation; } @@ -1674,7 +1726,6 @@ export class ChatwootService { } }); - this.logger.verbose('message content: ' + formattedContact); return formattedContact; } @@ -1712,8 +1763,6 @@ export class ChatwootService { const formattedContactsArray = formattedContacts.join('\n\n'); - this.logger.verbose('formatted contacts: ' + formattedContactsArray); - return formattedContactsArray; } @@ -1773,25 +1822,18 @@ export class ChatwootService { return formattedResponseList; } - this.logger.verbose('message content: ' + result); - return result; } public getConversationMessage(msg: any) { - this.logger.verbose('get conversation message'); - const types = this.getTypeMessage(msg); const messageContent = this.getMessageContent(types); - this.logger.verbose('conversation message: ' + messageContent); - return messageContent; } public async eventWhatsapp(event: string, instance: InstanceDto, body: any) { - this.logger.verbose('event whatsapp to instance: ' + instance.instanceName); try { const waInstance = this.waMonitor.waInstances[instance.instanceName]; @@ -1807,45 +1849,47 @@ export class ChatwootService { return null; } - if (event === 'contact.is_not_in_wpp') { - const getConversation = await this.createConversation(instance, body); + if (this.provider?.ignoreJids && this.provider?.ignoreJids.length > 0) { + const ignoreJids: any = this.provider?.ignoreJids; - if (!getConversation) { - this.logger.warn('conversation not found'); + let ignoreGroups = false; + let ignoreContacts = false; + + if (ignoreJids.includes('@g.us')) { + ignoreGroups = true; + } + + if (ignoreJids.includes('@s.whatsapp.net')) { + ignoreContacts = true; + } + + if (ignoreGroups && body?.key?.remoteJid.endsWith('@g.us')) { + this.logger.warn('Ignoring message from group: ' + body?.key?.remoteJid); return; } - client.messages.create({ - accountId: this.provider.account_id, - conversationId: getConversation, - data: { - content: `🚨 ${i18next.t('numbernotinwhatsapp')}`, - message_type: 'outgoing', - private: true, - }, - }); + if (ignoreContacts && body?.key?.remoteJid.endsWith('@s.whatsapp.net')) { + this.logger.warn('Ignoring message from contact: ' + body?.key?.remoteJid); + return; + } - return; + if (ignoreJids.includes(body?.key?.remoteJid)) { + this.logger.warn('Ignoring message from jid: ' + body?.key?.remoteJid); + return; + } } if (event === 'messages.upsert' || event === 'send.message') { - this.logger.verbose('event messages.upsert'); - if (body.key.remoteJid === 'status@broadcast') { - this.logger.verbose('status broadcast found'); return; } - // fix when receiving/sending messages from whatsapp desktop with ephemeral messages enabled if (body.message?.ephemeralMessage?.message) { body.message = { ...body.message?.ephemeralMessage?.message, }; } - this.logger.verbose('get conversation message'); - - // Whatsapp to Chatwoot const originalMessage = await this.getConversationMessage(body.message); const bodyMessage = originalMessage ? originalMessage @@ -1854,16 +1898,30 @@ export class ChatwootService { .replaceAll(/~((?!\s)([^\n~]+?)(? {}; + fileStream.push(fileData); + fileStream.push(null); - this.logger.verbose('temp file name: ' + nameFile); - - this.logger.verbose('create temp file'); - writeFileSync(fileName, fileData, 'utf8'); - - this.logger.verbose('check if is group'); if (body.key.remoteJid.includes('@g.us')) { - this.logger.verbose('message is group'); - const participantName = body.pushName; + const rawPhoneNumber = body.key.participant.split('@')[0]; + const phoneMatch = rawPhoneNumber.match(/^(\d{2})(\d{2})(\d{4})(\d{4})$/); + + let formattedPhoneNumber: string; + + if (phoneMatch) { + formattedPhoneNumber = `+${phoneMatch[1]} (${phoneMatch[2]}) ${phoneMatch[3]}-${phoneMatch[4]}`; + } else { + formattedPhoneNumber = `+${rawPhoneNumber}`; + } let content: string; if (!body.key.fromMe) { - this.logger.verbose('message is not from me'); - content = `**${participantName}:**\n\n${bodyMessage}`; + content = `**${formattedPhoneNumber} - ${participantName}:**\n\n${bodyMessage}`; } else { - this.logger.verbose('message is from me'); content = `${bodyMessage}`; } - this.logger.verbose('send data to chatwoot'); const send = await this.sendData( getConversation, - fileName, + fileStream, + nameFile, messageType, content, instance, body, 'WAID:' + body.key.id, + quotedMsg, ); if (!send) { @@ -1956,17 +2008,16 @@ export class ChatwootService { return send; } else { - this.logger.verbose('message is not group'); - - this.logger.verbose('send data to chatwoot'); const send = await this.sendData( getConversation, - fileName, + fileStream, + nameFile, messageType, bodyMessage, instance, body, 'WAID:' + body.key.id, + quotedMsg, ); if (!send) { @@ -1978,9 +2029,7 @@ export class ChatwootService { } } - this.logger.verbose('check if has ReactionMessage'); if (reactionMessage) { - this.logger.verbose('send data to chatwoot'); if (reactionMessage.text) { const send = await this.createMessage( instance, @@ -1993,6 +2042,7 @@ export class ChatwootService { message: { extendedTextMessage: { contextInfo: { stanzaId: reactionMessage.key.id } } }, }, 'WAID:' + body.key.id, + quotedMsg, ); if (!send) { this.logger.warn('message not sent'); @@ -2003,11 +2053,8 @@ export class ChatwootService { return; } - this.logger.verbose('check if has Ads Message'); - if (adsMessage) { - this.logger.verbose('message is from Ads'); - - this.logger.verbose('get base64 from media ads message'); + const isAdsMessage = (adsMessage && adsMessage.title) || adsMessage.body || adsMessage.thumbnailUrl; + if (isAdsMessage) { const imgBuffer = await axios.get(adsMessage.thumbnailUrl, { responseType: 'arraybuffer' }); const extension = mimeTypes.extension(imgBuffer.headers['content-type']); @@ -2021,28 +2068,30 @@ export class ChatwootService { const random = Math.random().toString(36).substring(7); const nameFile = `${random}.${mimeTypes.extension(mimeType)}`; const fileData = Buffer.from(imgBuffer.data, 'binary'); - const fileName = `${path.join(waInstance?.storePath, 'temp', `${nameFile}`)}`; - this.logger.verbose('temp file name: ' + nameFile); - this.logger.verbose('create temp file'); - await Jimp.read(fileData) - .then(async (img) => { - await img.cover(320, 180).writeAsync(fileName); - }) - .catch((err) => { - this.logger.error(`image is not write: ${err}`); - }); + const img = await Jimp.read(fileData); + await img.cover(320, 180); + + const processedBuffer = await img.getBufferAsync(Jimp.MIME_PNG); + + const fileStream = new Readable(); + fileStream._read = () => {}; // _read is required but you can noop it + fileStream.push(processedBuffer); + fileStream.push(null); + const truncStr = (str: string, len: number) => { + if (!str) return ''; + return str.length > len ? str.substring(0, len) + '...' : str; }; const title = truncStr(adsMessage.title, 40); - const description = truncStr(adsMessage.body, 75); + const description = truncStr(adsMessage?.body, 75); - this.logger.verbose('send data to chatwoot'); const send = await this.sendData( getConversation, - fileName, + fileStream, + nameFile, messageType, `${bodyMessage}\n\n\n**${title}**\n${description}\n${adsMessage.sourceUrl}`, instance, @@ -2058,22 +2107,27 @@ export class ChatwootService { return send; } - this.logger.verbose('check if is group'); if (body.key.remoteJid.includes('@g.us')) { - this.logger.verbose('message is group'); const participantName = body.pushName; + const rawPhoneNumber = body.key.participant.split('@')[0]; + const phoneMatch = rawPhoneNumber.match(/^(\d{2})(\d{2})(\d{4})(\d{4})$/); + + let formattedPhoneNumber: string; + + if (phoneMatch) { + formattedPhoneNumber = `+${phoneMatch[1]} (${phoneMatch[2]}) ${phoneMatch[3]}-${phoneMatch[4]}`; + } else { + formattedPhoneNumber = `+${rawPhoneNumber}`; + } let content: string; if (!body.key.fromMe) { - this.logger.verbose('message is not from me'); - content = `**${participantName}**\n\n${bodyMessage}`; + content = `**${formattedPhoneNumber} - ${participantName}:**\n\n${bodyMessage}`; } else { - this.logger.verbose('message is from me'); content = `${bodyMessage}`; } - this.logger.verbose('send data to chatwoot'); const send = await this.createMessage( instance, getConversation, @@ -2083,6 +2137,7 @@ export class ChatwootService { [], body, 'WAID:' + body.key.id, + quotedMsg, ); if (!send) { @@ -2092,9 +2147,6 @@ export class ChatwootService { return send; } else { - this.logger.verbose('message is not group'); - - this.logger.verbose('send data to chatwoot'); const send = await this.createMessage( instance, getConversation, @@ -2104,6 +2156,7 @@ export class ChatwootService { [], body, 'WAID:' + body.key.id, + quotedMsg, ); if (!send) { @@ -2117,31 +2170,30 @@ export class ChatwootService { if (event === Events.MESSAGES_DELETE) { const chatwootDelete = this.configService.get('CHATWOOT').MESSAGE_DELETE; - if (chatwootDelete === true) { - this.logger.verbose('deleting message from instance: ' + instance.instanceName); + if (chatwootDelete === true) { if (!body?.key?.id) { this.logger.warn('message id not found'); return; } const message = await this.getMessageByKeyId(instance, body.key.id); - if (message?.chatwoot?.messageId && message?.chatwoot?.conversationId) { - this.logger.verbose('deleting message in repository. Message id: ' + body.key.id); - this.repository.message.delete({ + + if (message?.chatwootMessageId && message?.chatwootConversationId) { + await this.prismaRepository.message.deleteMany({ where: { key: { - id: body.key.id, + path: ['id'], + equals: body.key.id, }, - owner: instance.instanceName, + instanceId: instance.instanceId, }, }); - this.logger.verbose('deleting message in chatwoot. Message id: ' + body.key.id); return await client.messages.delete({ - accountId: this.provider.account_id, - conversationId: message.chatwoot.conversationId, - messageId: message.chatwoot.messageId, + accountId: this.provider.accountId, + conversationId: message.chatwootConversationId, + messageId: message.chatwootMessageId, }); } } @@ -2152,20 +2204,28 @@ export class ChatwootService { body?.editedMessage?.conversation || body?.editedMessage?.extendedTextMessage?.text }\n\n_\`${i18next.t('cw.message.edited')}.\`_`; const message = await this.getMessageByKeyId(instance, body?.key?.id); - const messageType = message.key?.fromMe ? 'outgoing' : 'incoming'; + const key = message.key as { + id: string; + fromMe: boolean; + remoteJid: string; + participant?: string; + }; - if (message && message.chatwoot?.conversationId) { + const messageType = key?.fromMe ? 'outgoing' : 'incoming'; + + if (message && message.chatwootConversationId) { const send = await this.createMessage( instance, - message.chatwoot.conversationId, + message.chatwootConversationId, editedText, messageType, false, [], { - message: { extendedTextMessage: { contextInfo: { stanzaId: message.key.id } } }, + message: { extendedTextMessage: { contextInfo: { stanzaId: key.id } } }, }, 'WAID:' + body.key.id, + null, ); if (!send) { this.logger.warn('edited message not sent'); @@ -2176,24 +2236,24 @@ export class ChatwootService { } if (event === 'messages.read') { - this.logger.verbose('read message from instance: ' + instance.instanceName); - if (!body?.key?.id || !body?.key?.remoteJid) { this.logger.warn('message id not found'); return; } const message = await this.getMessageByKeyId(instance, body.key.id); - const { conversationId, contactInbox } = message?.chatwoot || {}; + const conversationId = message?.chatwootConversationId; + const contactInboxSourceId = message?.chatwootContactInboxSourceId; + if (conversationId) { - let sourceId = contactInbox?.sourceId; + let sourceId = contactInboxSourceId; const inbox = (await this.getInbox(instance)) as inbox & { inbox_identifier?: string; }; if (!sourceId && inbox) { const conversation = (await client.conversations.get({ - accountId: this.provider.account_id, + accountId: this.provider.accountId, conversationId: conversationId, })) as conversation_show & { last_non_activity_message: { conversation: { contact_inbox: contact_inboxes } }; @@ -2215,7 +2275,6 @@ export class ChatwootService { } if (event === 'status.instance') { - this.logger.verbose('event status.instance'); const data = body; const inbox = await this.getInbox(instance); @@ -2229,18 +2288,14 @@ export class ChatwootService { state: data.status, }); - this.logger.verbose('send message to chatwoot'); await this.createBotMessage(instance, msgStatus, 'incoming'); } if (event === 'connection.update') { - this.logger.verbose('event connection.update'); - if (body.status === 'open') { // if we have qrcode count then we understand that a new connection was established if (this.waMonitor.waInstances[instance.instanceName].qrCode.count > 0) { const msgConnection = i18next.t('cw.inbox.connected'); - this.logger.verbose('send message to chatwoot'); await this.createBotMessage(instance, msgConnection, 'incoming'); this.waMonitor.waInstances[instance.instanceName].qrCode.count = 0; chatwootImport.clearAll(instance); @@ -2249,27 +2304,24 @@ export class ChatwootService { } if (event === 'qrcode.updated') { - this.logger.verbose('event qrcode.updated'); if (body.statusCode === 500) { - this.logger.verbose('qrcode error'); - const erroQRcode = `🚨 ${i18next.t('qrlimitreached')}`; - - this.logger.verbose('send message to chatwoot'); return await this.createBotMessage(instance, erroQRcode, 'incoming'); } else { - this.logger.verbose('qrcode success'); const fileData = Buffer.from(body?.qrcode.base64.replace('data:image/png;base64,', ''), 'base64'); - const fileName = `${path.join(waInstance?.storePath, 'temp', `${instance.instanceName}.png`)}`; + const fileStream = new Readable(); + fileStream._read = () => {}; + fileStream.push(fileData); + fileStream.push(null); - this.logger.verbose('temp file name: ' + fileName); - - this.logger.verbose('create temp file'); - writeFileSync(fileName, fileData, 'utf8'); - - this.logger.verbose('send qrcode to chatwoot'); - await this.createBotQr(instance, i18next.t('qrgeneratedsuccesfully'), 'incoming', fileName); + await this.createBotQr( + instance, + i18next.t('qrgeneratedsuccesfully'), + 'incoming', + fileStream, + `${instance.instanceName}.png`, + ); let msgQrCode = `⚡️${i18next.t('qrgeneratedsuccesfully')}\n\n${i18next.t('scanqr')}`; @@ -2282,7 +2334,6 @@ export class ChatwootService { )}`; } - this.logger.verbose('send message to chatwoot'); await this.createBotMessage(instance, msgQrCode, 'incoming'); } } @@ -2309,10 +2360,7 @@ export class ChatwootService { return uri && uri !== 'postgres://user:password@hostname:port/dbname'; } - /* We can't proccess messages exactly in batch because Chatwoot use message id to order - messages in frontend and we are receiving the messages mixed between the batches. - Because this, we need to put all batches together and order after */ - public addHistoryMessages(instance: InstanceDto, messagesRaw: MessageRaw[]) { + public addHistoryMessages(instance: InstanceDto, messagesRaw: MessageModel[]) { if (!this.isImportHistoryAvailable()) { return; } @@ -2320,7 +2368,7 @@ export class ChatwootService { chatwootImport.addHistoryMessages(instance, messagesRaw); } - public addHistoryContacts(instance: InstanceDto, contactsRaw: ContactRaw[]) { + public addHistoryContacts(instance: InstanceDto, contactsRaw: ContactModel[]) { if (!this.isImportHistoryAvailable()) { return; } @@ -2376,22 +2424,28 @@ export class ChatwootService { limitContacts, ); + const contactIdentifiers = recentContacts + .map((contact) => contact.identifier) + .filter((identifier) => identifier !== null); + const contactsWithProfilePicture = ( - await this.repository.contact.find({ + await this.prismaRepository.contact.findMany({ where: { - owner: instance.instanceName, + instanceId: instance.instanceId, id: { - $in: recentContacts.map((contact) => contact.identifier), + in: contactIdentifiers, + }, + profilePicUrl: { + not: null, }, - profilePictureUrl: { $ne: null }, }, - } as any) - ).reduce((acc: Map, contact: ContactRaw) => acc.set(contact.id, contact), new Map()); + }) + ).reduce((acc: Map, contact: ContactModel) => acc.set(contact.id, contact), new Map()); recentContacts.forEach(async (contact) => { if (contactsWithProfilePicture.has(contact.identifier)) { client.contacts.update({ - accountId: this.provider.account_id, + accountId: this.provider.accountId, id: contact.id, data: { avatar_url: contactsWithProfilePicture.get(contact.identifier).profilePictureUrl || null, @@ -2403,4 +2457,67 @@ export class ChatwootService { this.logger.error(`Error on update avatar in recent conversations: ${error.toString()}`); } } + + public async syncLostMessages( + instance: InstanceDto, + chatwootConfig: ChatwootDto, + prepareMessage: (message: any) => any, + ) { + try { + if (!this.isImportHistoryAvailable()) { + return; + } + if (!this.configService.get('DATABASE').SAVE_DATA.MESSAGE_UPDATE) { + return; + } + + const inbox = await this.getInbox(instance); + + const sqlMessages = `select * from messages m + where account_id = ${chatwootConfig.accountId} + and inbox_id = ${inbox.id} + and created_at >= now() - interval '6h' + order by created_at desc`; + + const messagesData = (await this.pgClient.query(sqlMessages))?.rows; + const ids: string[] = messagesData + .filter((message) => !!message.source_id) + .map((message) => message.source_id.replace('WAID:', '')); + + const savedMessages = await this.prismaRepository.message.findMany({ + where: { + Instance: { name: instance.instanceName }, + messageTimestamp: { gte: dayjs().subtract(6, 'hours').unix() }, + AND: ids.map((id) => ({ key: { path: ['id'], not: id } })), + }, + }); + + const filteredMessages = savedMessages.filter( + (msg: any) => !chatwootImport.isIgnorePhoneNumber(msg.key?.remoteJid), + ); + const messagesRaw: any[] = []; + for (const m of filteredMessages) { + if (!m.message || !m.key || !m.messageTimestamp) { + continue; + } + + if (Long.isLong(m?.messageTimestamp)) { + m.messageTimestamp = m.messageTimestamp?.toNumber(); + } + + messagesRaw.push(prepareMessage(m as any)); + } + + this.addHistoryMessages( + instance, + messagesRaw.filter((msg) => !chatwootImport.isIgnorePhoneNumber(msg.key?.remoteJid)), + ); + + await chatwootImport.importHistoryMessages(instance, this, inbox, this.provider); + const waInstance = this.waMonitor.waInstances[instance.instanceName]; + waInstance.clearCacheChatwoot(); + } catch (error) { + return; + } + } } diff --git a/src/api/integrations/chatwoot/utils/chatwoot-import-helper.ts b/src/api/integrations/chatbot/chatwoot/utils/chatwoot-import-helper.ts similarity index 69% rename from src/api/integrations/chatwoot/utils/chatwoot-import-helper.ts rename to src/api/integrations/chatbot/chatwoot/utils/chatwoot-import-helper.ts index dd0bb23a..52453f59 100644 --- a/src/api/integrations/chatwoot/utils/chatwoot-import-helper.ts +++ b/src/api/integrations/chatbot/chatwoot/utils/chatwoot-import-helper.ts @@ -1,12 +1,12 @@ +import { InstanceDto } from '@api/dto/instance.dto'; +import { ChatwootDto } from '@api/integrations/chatbot/chatwoot/dto/chatwoot.dto'; +import { postgresClient } from '@api/integrations/chatbot/chatwoot/libs/postgres.client'; +import { ChatwootService } from '@api/integrations/chatbot/chatwoot/services/chatwoot.service'; +import { Chatwoot, configService } from '@config/env.config'; +import { Logger } from '@config/logger.config'; import { inbox } from '@figuro/chatwoot-sdk'; -import { proto } from '@whiskeysockets/baileys'; - -import { InstanceDto } from '../../../../api/dto/instance.dto'; -import { ChatwootRaw, ContactRaw, MessageRaw } from '../../../../api/models'; -import { Chatwoot, configService } from '../../../../config/env.config'; -import { Logger } from '../../../../config/logger.config'; -import { postgresClient } from '../libs/postgres.client'; -import { ChatwootService } from '../services/chatwoot.service'; +import { Chatwoot as ChatwootModel, Contact, Message } from '@prisma/client'; +import { proto } from 'baileys'; type ChatwootUser = { user_type: string; @@ -27,10 +27,10 @@ type firstLastTimestamp = { type IWebMessageInfo = Omit & Partial>; class ChatwootImport { - private logger = new Logger(ChatwootImport.name); + private logger = new Logger('ChatwootImport'); private repositoryMessagesCache = new Map>(); - private historyMessages = new Map(); - private historyContacts = new Map(); + private historyMessages = new Map(); + private historyContacts = new Map(); public getRepositoryMessagesCache(instance: InstanceDto) { return this.repositoryMessagesCache.has(instance.instanceName) @@ -46,14 +46,14 @@ class ChatwootImport { this.repositoryMessagesCache.delete(instance.instanceName); } - public addHistoryMessages(instance: InstanceDto, messagesRaw: MessageRaw[]) { + public addHistoryMessages(instance: InstanceDto, messagesRaw: Message[]) { const actualValue = this.historyMessages.has(instance.instanceName) ? this.historyMessages.get(instance.instanceName) : []; - this.historyMessages.set(instance.instanceName, actualValue.concat(messagesRaw)); + this.historyMessages.set(instance.instanceName, [...actualValue, ...messagesRaw]); } - public addHistoryContacts(instance: InstanceDto, contactsRaw: ContactRaw[]) { + public addHistoryContacts(instance: InstanceDto, contactsRaw: Contact[]) { const actualValue = this.historyContacts.has(instance.instanceName) ? this.historyContacts.get(instance.instanceName) : []; @@ -78,7 +78,7 @@ class ChatwootImport { return this.historyMessages.get(instance.instanceName)?.length ?? 0; } - public async importHistoryContacts(instance: InstanceDto, provider: ChatwootRaw) { + public async importHistoryContacts(instance: InstanceDto, provider: ChatwootDto) { try { if (this.getHistoryMessagesLenght(instance) > 0) { return; @@ -93,21 +93,32 @@ class ChatwootImport { return 0; } - let contactsChunk: ContactRaw[] = this.sliceIntoChunks(contacts, 3000); + let contactsChunk: Contact[] = this.sliceIntoChunks(contacts, 3000); while (contactsChunk.length > 0) { + const labelSql = `SELECT id FROM labels WHERE title = '${provider.nameInbox}' AND account_id = ${provider.accountId} LIMIT 1`; + + let labelId = (await pgClient.query(labelSql))?.rows[0]?.id; + + if (!labelId) { + // creating label in chatwoot db and getting the id + const sqlLabel = `INSERT INTO labels (title, color, show_on_sidebar, account_id, created_at, updated_at) VALUES ('${provider.nameInbox}', '#34039B', true, ${provider.accountId}, NOW(), NOW()) RETURNING id`; + + labelId = (await pgClient.query(sqlLabel))?.rows[0]?.id; + } + // inserting contacts in chatwoot db let sqlInsert = `INSERT INTO contacts (name, phone_number, account_id, identifier, created_at, updated_at) VALUES `; - const bindInsert = [provider.account_id]; + const bindInsert = [provider.accountId]; for (const contact of contactsChunk) { bindInsert.push(contact.pushName); const bindName = `$${bindInsert.length}`; - bindInsert.push(`+${contact.id.split('@')[0]}`); + bindInsert.push(`+${contact.remoteJid.split('@')[0]}`); const bindPhoneNumber = `$${bindInsert.length}`; - bindInsert.push(contact.id); + bindInsert.push(contact.remoteJid); const bindIdentifier = `$${bindInsert.length}`; sqlInsert += `(${bindName}, ${bindPhoneNumber}, $1, ${bindIdentifier}, NOW(), NOW()),`; @@ -122,6 +133,31 @@ class ChatwootImport { identifier = EXCLUDED.identifier`; totalContactsImported += (await pgClient.query(sqlInsert, bindInsert))?.rowCount ?? 0; + + const sqlTags = `SELECT id FROM tags WHERE name = '${provider.nameInbox}' LIMIT 1`; + + const tagData = (await pgClient.query(sqlTags))?.rows[0]; + let tagId = tagData?.id; + + const sqlTag = `INSERT INTO tags (name, taggings_count) VALUES ('${provider.nameInbox}', ${totalContactsImported}) ON CONFLICT (name) DO UPDATE SET taggings_count = tags.taggings_count + ${totalContactsImported} RETURNING id`; + + tagId = (await pgClient.query(sqlTag))?.rows[0]?.id; + + await pgClient.query(sqlTag); + + let sqlInsertLabel = `INSERT INTO taggings (tag_id, taggable_type, taggable_id, context, created_at) VALUES `; + + contactsChunk.forEach((contact) => { + const bindTaggableId = `(SELECT id FROM contacts WHERE identifier = '${contact.remoteJid}' AND account_id = ${provider.accountId})`; + sqlInsertLabel += `($1, $2, ${bindTaggableId}, $3, NOW()),`; + }); + + if (sqlInsertLabel.slice(-1) === ',') { + sqlInsertLabel = sqlInsertLabel.slice(0, -1); + } + + await pgClient.query(sqlInsertLabel, [tagId, 'Contact', 'labels']); + contactsChunk = this.sliceIntoChunks(contacts, 3000); } @@ -133,11 +169,34 @@ class ChatwootImport { } } + public async getExistingSourceIds(sourceIds: string[]): Promise> { + try { + const existingSourceIdsSet = new Set(); + + if (sourceIds.length === 0) { + return existingSourceIdsSet; + } + + const formattedSourceIds = sourceIds.map((sourceId) => `WAID:${sourceId.replace('WAID:', '')}`); // Make sure the sourceId is always formatted as WAID:1234567890 + const query = 'SELECT source_id FROM messages WHERE source_id = ANY($1)'; + const pgClient = postgresClient.getChatwootConnection(); + const result = await pgClient.query(query, [formattedSourceIds]); + + for (const row of result.rows) { + existingSourceIdsSet.add(row.source_id); + } + + return existingSourceIdsSet; + } catch (error) { + return null; + } + } + public async importHistoryMessages( instance: InstanceDto, chatwootService: ChatwootService, inbox: inbox, - provider: ChatwootRaw, + provider: ChatwootModel, ) { try { const pgClient = postgresClient.getChatwootConnection(); @@ -149,34 +208,44 @@ class ChatwootImport { let totalMessagesImported = 0; - const messagesOrdered = this.historyMessages.get(instance.instanceName) || []; + let messagesOrdered = this.historyMessages.get(instance.instanceName) || []; if (messagesOrdered.length === 0) { return 0; } // ordering messages by number and timestamp asc messagesOrdered.sort((a, b) => { - return ( - parseInt(a.key.remoteJid) - parseInt(b.key.remoteJid) || - (a.messageTimestamp as number) - (b.messageTimestamp as number) - ); + const aKey = a.key as { + remoteJid: string; + }; + + const bKey = b.key as { + remoteJid: string; + }; + + const aMessageTimestamp = a.messageTimestamp as any as number; + const bMessageTimestamp = b.messageTimestamp as any as number; + + return parseInt(aKey.remoteJid) - parseInt(bKey.remoteJid) || aMessageTimestamp - bMessageTimestamp; }); const allMessagesMappedByPhoneNumber = this.createMessagesMapByPhoneNumber(messagesOrdered); // Map structure: +552199999999 => { first message timestamp from number, last message timestamp from number} const phoneNumbersWithTimestamp = new Map(); - allMessagesMappedByPhoneNumber.forEach((messages: MessageRaw[], phoneNumber: string) => { + allMessagesMappedByPhoneNumber.forEach((messages: Message[], phoneNumber: string) => { phoneNumbersWithTimestamp.set(phoneNumber, { - first: messages[0]?.messageTimestamp as number, - last: messages[messages.length - 1]?.messageTimestamp as number, + first: messages[0]?.messageTimestamp as any as number, + last: messages[messages.length - 1]?.messageTimestamp as any as number, }); }); + const existingSourceIds = await this.getExistingSourceIds(messagesOrdered.map((message: any) => message.key.id)); + messagesOrdered = messagesOrdered.filter((message: any) => !existingSourceIds.has(message.key.id)); // processing messages in batch const batchSize = 4000; - let messagesChunk: MessageRaw[] = this.sliceIntoChunks(messagesOrdered, batchSize); + let messagesChunk: Message[] = this.sliceIntoChunks(messagesOrdered, batchSize); while (messagesChunk.length > 0) { - // Map structure: +552199999999 => MessageRaw[] + // Map structure: +552199999999 => Message[] const messagesByPhoneNumber = this.createMessagesMapByPhoneNumber(messagesChunk); if (messagesByPhoneNumber.size > 0) { @@ -189,11 +258,11 @@ class ChatwootImport { // inserting messages in chatwoot db let sqlInsertMsg = `INSERT INTO messages - (content, account_id, inbox_id, conversation_id, message_type, private, content_type, - sender_type, sender_id, created_at, updated_at) VALUES `; - const bindInsertMsg = [provider.account_id, inbox.id]; + (content, processed_message_content, account_id, inbox_id, conversation_id, message_type, private, content_type, + sender_type, sender_id, source_id, created_at, updated_at) VALUES `; + const bindInsertMsg = [provider.accountId, inbox.id]; - messagesByPhoneNumber.forEach((messages: MessageRaw[], phoneNumber: string) => { + messagesByPhoneNumber.forEach((messages: any[], phoneNumber: string) => { const fksChatwoot = fksByNumber.get(phoneNumber); messages.forEach((message) => { @@ -225,11 +294,14 @@ class ChatwootImport { bindInsertMsg.push(message.key.fromMe ? chatwootUser.user_id : fksChatwoot.contact_id); const bindSenderId = `$${bindInsertMsg.length}`; + bindInsertMsg.push('WAID:' + message.key.id); + const bindSourceId = `$${bindInsertMsg.length}`; + bindInsertMsg.push(message.messageTimestamp as number); const bindmessageTimestamp = `$${bindInsertMsg.length}`; - sqlInsertMsg += `(${bindContent}, $1, $2, ${bindConversationId}, ${bindMessageType}, FALSE, 0, - ${bindSenderType},${bindSenderId}, to_timestamp(${bindmessageTimestamp}), to_timestamp(${bindmessageTimestamp})),`; + sqlInsertMsg += `(${bindContent}, ${bindContent}, $1, $2, ${bindConversationId}, ${bindMessageType}, FALSE, 0, + ${bindSenderType},${bindSenderId},${bindSourceId}, to_timestamp(${bindmessageTimestamp}), to_timestamp(${bindmessageTimestamp})),`; }); }); if (bindInsertMsg.length > 2) { @@ -245,7 +317,12 @@ class ChatwootImport { this.deleteHistoryMessages(instance); this.deleteRepositoryMessagesCache(instance); - this.importHistoryContacts(instance, provider); + const providerData: ChatwootDto = { + ...provider, + ignoreJids: Array.isArray(provider.ignoreJids) ? provider.ignoreJids.map((event) => String(event)) : [], + }; + + this.importHistoryContacts(instance, providerData); return totalMessagesImported; } catch (error) { @@ -257,14 +334,14 @@ class ChatwootImport { } public async selectOrCreateFksFromChatwoot( - provider: ChatwootRaw, + provider: ChatwootModel, inbox: inbox, phoneNumbersWithTimestamp: Map, - messagesByPhoneNumber: Map, + messagesByPhoneNumber: Map, ): Promise> { const pgClient = postgresClient.getChatwootConnection(); - const bindValues = [provider.account_id, inbox.id]; + const bindValues = [provider.accountId, inbox.id]; const phoneNumberBind = Array.from(messagesByPhoneNumber.keys()) .map((phoneNumber) => { const phoneNumberTimestamp = phoneNumbersWithTimestamp.get(phoneNumber); @@ -348,7 +425,7 @@ class ChatwootImport { return new Map(fksFromChatwoot.rows.map((item: FksChatwoot) => [item.phone_number, item])); } - public async getChatwootUser(provider: ChatwootRaw): Promise { + public async getChatwootUser(provider: ChatwootModel): Promise { try { const pgClient = postgresClient.getChatwootConnection(); @@ -362,10 +439,13 @@ class ChatwootImport { } } - public createMessagesMapByPhoneNumber(messages: MessageRaw[]): Map { - return messages.reduce((acc: Map, message: MessageRaw) => { - if (!this.isIgnorePhoneNumber(message?.key?.remoteJid)) { - const phoneNumber = message?.key?.remoteJid?.split('@')[0]; + public createMessagesMapByPhoneNumber(messages: Message[]): Map { + return messages.reduce((acc: Map, message: Message) => { + const key = message?.key as { + remoteJid: string; + }; + if (!this.isIgnorePhoneNumber(key?.remoteJid)) { + const phoneNumber = key?.remoteJid?.split('@')[0]; if (phoneNumber) { const phoneNumberPlus = `+${phoneNumber}`; const messages = acc.has(phoneNumberPlus) ? acc.get(phoneNumberPlus) : []; @@ -380,7 +460,7 @@ class ChatwootImport { public async getContactsOrderByRecentConversations( inbox: inbox, - provider: ChatwootRaw, + provider: ChatwootModel, limit = 50, ): Promise<{ id: number; phone_number: string; identifier: string }[]> { try { @@ -394,7 +474,7 @@ class ChatwootImport { ORDER BY conversations.last_activity_at DESC LIMIT $3`; - return (await pgClient.query(sql, [provider.account_id, inbox.id, limit]))?.rows; + return (await pgClient.query(sql, [provider.accountId, inbox.id, limit]))?.rows; } catch (error) { this.logger.error(`Error on get recent conversations: ${error.toString()}`); } @@ -467,6 +547,14 @@ class ChatwootImport { public isIgnorePhoneNumber(remoteJid: string) { return this.isGroup(remoteJid) || remoteJid === 'status@broadcast' || remoteJid === '0@s.whatsapp.net'; } + + public updateMessageSourceID(messageId: string | number, sourceId: string) { + const pgClient = postgresClient.getChatwootConnection(); + + const sql = `UPDATE messages SET source_id = $1, status = 0, created_at = NOW(), updated_at = NOW() WHERE id = $2;`; + + return pgClient.query(sql, [`WAID:${sourceId}`, messageId]); + } } export const chatwootImport = new ChatwootImport(); diff --git a/src/api/integrations/chatbot/chatwoot/validate/chatwoot.schema.ts b/src/api/integrations/chatbot/chatwoot/validate/chatwoot.schema.ts new file mode 100644 index 00000000..ce9cf701 --- /dev/null +++ b/src/api/integrations/chatbot/chatwoot/validate/chatwoot.schema.ts @@ -0,0 +1,45 @@ +import { JSONSchema7 } from 'json-schema'; +import { v4 } from 'uuid'; + +const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => { + const properties = {}; + propertyNames.forEach( + (property) => + (properties[property] = { + minLength: 1, + description: `The "${property}" cannot be empty`, + }), + ); + return { + if: { + propertyNames: { + enum: [...propertyNames], + }, + }, + then: { properties }, + }; +}; + +export const chatwootSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + enabled: { type: 'boolean', enum: [true, false] }, + accountId: { type: 'string' }, + token: { type: 'string' }, + url: { type: 'string' }, + signMsg: { type: 'boolean', enum: [true, false] }, + signDelimiter: { type: ['string', 'null'] }, + nameInbox: { type: ['string', 'null'] }, + reopenConversation: { type: 'boolean', enum: [true, false] }, + conversationPending: { type: 'boolean', enum: [true, false] }, + autoCreate: { type: 'boolean', enum: [true, false] }, + importContacts: { type: 'boolean', enum: [true, false] }, + mergeBrazilContacts: { type: 'boolean', enum: [true, false] }, + importMessages: { type: 'boolean', enum: [true, false] }, + daysLimitImportMessages: { type: 'number' }, + ignoreJids: { type: 'array', items: { type: 'string' } }, + }, + required: ['enabled', 'accountId', 'token', 'url', 'signMsg', 'reopenConversation', 'conversationPending'], + ...isNotEmpty('enabled', 'accountId', 'token', 'url', 'signMsg', 'reopenConversation', 'conversationPending'), +}; diff --git a/src/api/integrations/chatbot/dify/controllers/dify.controller.ts b/src/api/integrations/chatbot/dify/controllers/dify.controller.ts new file mode 100644 index 00000000..05834fb3 --- /dev/null +++ b/src/api/integrations/chatbot/dify/controllers/dify.controller.ts @@ -0,0 +1,888 @@ +import { IgnoreJidDto } from '@api/dto/chatbot.dto'; +import { InstanceDto } from '@api/dto/instance.dto'; +import { DifyDto } from '@api/integrations/chatbot/dify/dto/dify.dto'; +import { DifyService } from '@api/integrations/chatbot/dify/services/dify.service'; +import { PrismaRepository } from '@api/repository/repository.service'; +import { WAMonitoringService } from '@api/services/monitor.service'; +import { configService, Dify } from '@config/env.config'; +import { Logger } from '@config/logger.config'; +import { BadRequestException } from '@exceptions'; +import { Dify as DifyModel } from '@prisma/client'; +import { getConversationMessage } from '@utils/getConversationMessage'; + +import { ChatbotController, ChatbotControllerInterface, EmitData } from '../../chatbot.controller'; + +export class DifyController extends ChatbotController implements ChatbotControllerInterface { + constructor( + private readonly difyService: DifyService, + prismaRepository: PrismaRepository, + waMonitor: WAMonitoringService, + ) { + super(prismaRepository, waMonitor); + + this.botRepository = this.prismaRepository.dify; + this.settingsRepository = this.prismaRepository.difySetting; + this.sessionRepository = this.prismaRepository.integrationSession; + } + + public readonly logger = new Logger('DifyController'); + + integrationEnabled = configService.get('DIFY').ENABLED; + botRepository: any; + settingsRepository: any; + sessionRepository: any; + userMessageDebounce: { [key: string]: { message: string; timeoutId: NodeJS.Timeout } } = {}; + + // Bots + public async createBot(instance: InstanceDto, data: DifyDto) { + if (!this.integrationEnabled) throw new BadRequestException('Dify is disabled'); + + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + if ( + !data.expire || + !data.keywordFinish || + !data.delayMessage || + !data.unknownMessage || + !data.listeningFromMe || + !data.stopBotFromMe || + !data.keepOpen || + !data.debounceTime || + !data.ignoreJids || + !data.splitMessages || + !data.timePerChar + ) { + const defaultSettingCheck = await this.settingsRepository.findFirst({ + where: { + instanceId: instanceId, + }, + }); + + if (data.expire === undefined || data.expire === null) data.expire = defaultSettingCheck.expire; + if (data.keywordFinish === undefined || data.keywordFinish === null) + data.keywordFinish = defaultSettingCheck.keywordFinish; + if (data.delayMessage === undefined || data.delayMessage === null) + data.delayMessage = defaultSettingCheck.delayMessage; + if (data.unknownMessage === undefined || data.unknownMessage === null) + data.unknownMessage = defaultSettingCheck.unknownMessage; + if (data.listeningFromMe === undefined || data.listeningFromMe === null) + data.listeningFromMe = defaultSettingCheck.listeningFromMe; + if (data.stopBotFromMe === undefined || data.stopBotFromMe === null) + data.stopBotFromMe = defaultSettingCheck.stopBotFromMe; + if (data.keepOpen === undefined || data.keepOpen === null) data.keepOpen = defaultSettingCheck.keepOpen; + if (data.debounceTime === undefined || data.debounceTime === null) + data.debounceTime = defaultSettingCheck.debounceTime; + if (data.ignoreJids === undefined || data.ignoreJids === null) data.ignoreJids = defaultSettingCheck.ignoreJids; + if (data.splitMessages === undefined || data.splitMessages === null) + data.splitMessages = defaultSettingCheck?.splitMessages ?? false; + if (data.timePerChar === undefined || data.timePerChar === null) + data.timePerChar = defaultSettingCheck?.timePerChar ?? 0; + + if (!defaultSettingCheck) { + await this.settings(instance, { + expire: data.expire, + keywordFinish: data.keywordFinish, + delayMessage: data.delayMessage, + unknownMessage: data.unknownMessage, + listeningFromMe: data.listeningFromMe, + stopBotFromMe: data.stopBotFromMe, + keepOpen: data.keepOpen, + debounceTime: data.debounceTime, + ignoreJids: data.ignoreJids, + splitMessages: data.splitMessages, + timePerChar: data.timePerChar, + }); + } + } + + const checkTriggerAll = await this.botRepository.findFirst({ + where: { + enabled: true, + triggerType: 'all', + instanceId: instanceId, + }, + }); + + if (checkTriggerAll && data.triggerType === 'all') { + throw new Error('You already have a dify with an "All" trigger, you cannot have more bots while it is active'); + } + + const checkDuplicate = await this.botRepository.findFirst({ + where: { + instanceId: instanceId, + botType: data.botType, + apiUrl: data.apiUrl, + apiKey: data.apiKey, + }, + }); + + if (checkDuplicate) { + throw new Error('Dify already exists'); + } + + if (data.triggerType === 'keyword') { + if (!data.triggerOperator || !data.triggerValue) { + throw new Error('Trigger operator and value are required'); + } + + const checkDuplicate = await this.botRepository.findFirst({ + where: { + triggerOperator: data.triggerOperator, + triggerValue: data.triggerValue, + instanceId: instanceId, + }, + }); + + if (checkDuplicate) { + throw new Error('Trigger already exists'); + } + } + + if (data.triggerType === 'advanced') { + if (!data.triggerValue) { + throw new Error('Trigger value is required'); + } + + const checkDuplicate = await this.botRepository.findFirst({ + where: { + triggerValue: data.triggerValue, + instanceId: instanceId, + }, + }); + + if (checkDuplicate) { + throw new Error('Trigger already exists'); + } + } + + try { + const bot = await this.botRepository.create({ + data: { + enabled: data?.enabled, + description: data.description, + botType: data.botType, + apiUrl: data.apiUrl, + apiKey: data.apiKey, + expire: data.expire, + keywordFinish: data.keywordFinish, + delayMessage: data.delayMessage, + unknownMessage: data.unknownMessage, + listeningFromMe: data.listeningFromMe, + stopBotFromMe: data.stopBotFromMe, + keepOpen: data.keepOpen, + debounceTime: data.debounceTime, + instanceId: instanceId, + triggerType: data.triggerType, + triggerOperator: data.triggerOperator, + triggerValue: data.triggerValue, + ignoreJids: data.ignoreJids, + splitMessages: data.splitMessages, + timePerChar: data.timePerChar, + }, + }); + + return bot; + } catch (error) { + this.logger.error(error); + throw new Error('Error creating dify'); + } + } + + public async findBot(instance: InstanceDto) { + if (!this.integrationEnabled) throw new BadRequestException('Dify is disabled'); + + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const bots = await this.botRepository.findMany({ + where: { + instanceId: instanceId, + }, + }); + + if (!bots.length) { + return null; + } + + return bots; + } + + public async fetchBot(instance: InstanceDto, botId: string) { + if (!this.integrationEnabled) throw new BadRequestException('Dify is disabled'); + + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const bot = await this.botRepository.findFirst({ + where: { + id: botId, + }, + }); + + if (!bot) { + throw new Error('Dify not found'); + } + + if (bot.instanceId !== instanceId) { + throw new Error('Dify not found'); + } + + return bot; + } + + public async updateBot(instance: InstanceDto, botId: string, data: DifyDto) { + if (!this.integrationEnabled) throw new BadRequestException('Dify is disabled'); + + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const bot = await this.botRepository.findFirst({ + where: { + id: botId, + }, + }); + + if (!bot) { + throw new Error('Dify not found'); + } + + if (bot.instanceId !== instanceId) { + throw new Error('Dify not found'); + } + + if (data.triggerType === 'all') { + const checkTriggerAll = await this.botRepository.findFirst({ + where: { + enabled: true, + triggerType: 'all', + id: { + not: botId, + }, + instanceId: instanceId, + }, + }); + + if (checkTriggerAll) { + throw new Error('You already have a dify with an "All" trigger, you cannot have more bots while it is active'); + } + } + + const checkDuplicate = await this.botRepository.findFirst({ + where: { + id: { + not: botId, + }, + instanceId: instanceId, + botType: data.botType, + apiUrl: data.apiUrl, + apiKey: data.apiKey, + }, + }); + + if (checkDuplicate) { + throw new Error('Dify already exists'); + } + + if (data.triggerType === 'keyword') { + if (!data.triggerOperator || !data.triggerValue) { + throw new Error('Trigger operator and value are required'); + } + + const checkDuplicate = await this.botRepository.findFirst({ + where: { + triggerOperator: data.triggerOperator, + triggerValue: data.triggerValue, + id: { not: botId }, + instanceId: instanceId, + }, + }); + + if (checkDuplicate) { + throw new Error('Trigger already exists'); + } + } + + if (data.triggerType === 'advanced') { + if (!data.triggerValue) { + throw new Error('Trigger value is required'); + } + + const checkDuplicate = await this.botRepository.findFirst({ + where: { + triggerValue: data.triggerValue, + id: { not: botId }, + instanceId: instanceId, + }, + }); + + if (checkDuplicate) { + throw new Error('Trigger already exists'); + } + } + + try { + const bot = await this.botRepository.update({ + where: { + id: botId, + }, + data: { + enabled: data?.enabled, + description: data.description, + botType: data.botType, + apiUrl: data.apiUrl, + apiKey: data.apiKey, + expire: data.expire, + keywordFinish: data.keywordFinish, + delayMessage: data.delayMessage, + unknownMessage: data.unknownMessage, + listeningFromMe: data.listeningFromMe, + stopBotFromMe: data.stopBotFromMe, + keepOpen: data.keepOpen, + debounceTime: data.debounceTime, + instanceId: instanceId, + triggerType: data.triggerType, + triggerOperator: data.triggerOperator, + triggerValue: data.triggerValue, + ignoreJids: data.ignoreJids, + splitMessages: data.splitMessages, + timePerChar: data.timePerChar, + }, + }); + + return bot; + } catch (error) { + this.logger.error(error); + throw new Error('Error updating dify'); + } + } + + public async deleteBot(instance: InstanceDto, botId: string) { + if (!this.integrationEnabled) throw new BadRequestException('Dify is disabled'); + + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const bot = await this.botRepository.findFirst({ + where: { + id: botId, + }, + }); + + if (!bot) { + throw new Error('Dify not found'); + } + + if (bot.instanceId !== instanceId) { + throw new Error('Dify not found'); + } + try { + await this.prismaRepository.integrationSession.deleteMany({ + where: { + botId: botId, + }, + }); + + await this.botRepository.delete({ + where: { + id: botId, + }, + }); + + return { bot: { id: botId } }; + } catch (error) { + this.logger.error(error); + throw new Error('Error deleting dify bot'); + } + } + + // Settings + public async settings(instance: InstanceDto, data: any) { + if (!this.integrationEnabled) throw new BadRequestException('Dify is disabled'); + + try { + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const settings = await this.settingsRepository.findFirst({ + where: { + instanceId: instanceId, + }, + }); + + if (settings) { + const updateSettings = await this.settingsRepository.update({ + where: { + id: settings.id, + }, + data: { + expire: data.expire, + keywordFinish: data.keywordFinish, + delayMessage: data.delayMessage, + unknownMessage: data.unknownMessage, + listeningFromMe: data.listeningFromMe, + stopBotFromMe: data.stopBotFromMe, + keepOpen: data.keepOpen, + debounceTime: data.debounceTime, + difyIdFallback: data.difyIdFallback, + ignoreJids: data.ignoreJids, + splitMessages: data.splitMessages, + timePerChar: data.timePerChar, + }, + }); + + return { + expire: updateSettings.expire, + keywordFinish: updateSettings.keywordFinish, + delayMessage: updateSettings.delayMessage, + unknownMessage: updateSettings.unknownMessage, + listeningFromMe: updateSettings.listeningFromMe, + stopBotFromMe: updateSettings.stopBotFromMe, + keepOpen: updateSettings.keepOpen, + debounceTime: updateSettings.debounceTime, + difyIdFallback: updateSettings.difyIdFallback, + ignoreJids: updateSettings.ignoreJids, + splitMessages: updateSettings.splitMessages, + timePerChar: updateSettings.timePerChar, + }; + } + + const newSetttings = await this.settingsRepository.create({ + data: { + expire: data.expire, + keywordFinish: data.keywordFinish, + delayMessage: data.delayMessage, + unknownMessage: data.unknownMessage, + listeningFromMe: data.listeningFromMe, + stopBotFromMe: data.stopBotFromMe, + keepOpen: data.keepOpen, + debounceTime: data.debounceTime, + difyIdFallback: data.difyIdFallback, + ignoreJids: data.ignoreJids, + instanceId: instanceId, + splitMessages: data.splitMessages, + timePerChar: data.timePerChar, + }, + }); + + return { + expire: newSetttings.expire, + keywordFinish: newSetttings.keywordFinish, + delayMessage: newSetttings.delayMessage, + unknownMessage: newSetttings.unknownMessage, + listeningFromMe: newSetttings.listeningFromMe, + stopBotFromMe: newSetttings.stopBotFromMe, + keepOpen: newSetttings.keepOpen, + debounceTime: newSetttings.debounceTime, + difyIdFallback: newSetttings.difyIdFallback, + ignoreJids: newSetttings.ignoreJids, + splitMessages: newSetttings.splitMessages, + timePerChar: newSetttings.timePerChar, + }; + } catch (error) { + this.logger.error(error); + throw new Error('Error setting default settings'); + } + } + + public async fetchSettings(instance: InstanceDto) { + if (!this.integrationEnabled) throw new BadRequestException('Dify is disabled'); + + try { + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const settings = await this.settingsRepository.findFirst({ + where: { + instanceId: instanceId, + }, + include: { + Fallback: true, + }, + }); + + if (!settings) { + return { + expire: 0, + keywordFinish: '', + delayMessage: 0, + unknownMessage: '', + listeningFromMe: false, + stopBotFromMe: false, + keepOpen: false, + ignoreJids: [], + splitMessages: false, + timePerChar: 0, + difyIdFallback: '', + fallback: null, + }; + } + + return { + expire: settings.expire, + keywordFinish: settings.keywordFinish, + delayMessage: settings.delayMessage, + unknownMessage: settings.unknownMessage, + listeningFromMe: settings.listeningFromMe, + stopBotFromMe: settings.stopBotFromMe, + keepOpen: settings.keepOpen, + ignoreJids: settings.ignoreJids, + splitMessages: settings.splitMessages, + timePerChar: settings.timePerChar, + difyIdFallback: settings.difyIdFallback, + fallback: settings.Fallback, + }; + } catch (error) { + this.logger.error(error); + throw new Error('Error fetching default settings'); + } + } + + // Sessions + public async changeStatus(instance: InstanceDto, data: any) { + if (!this.integrationEnabled) throw new BadRequestException('Dify is disabled'); + + try { + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const defaultSettingCheck = await this.settingsRepository.findFirst({ + where: { + instanceId, + }, + }); + + const remoteJid = data.remoteJid; + const status = data.status; + + if (status === 'delete') { + await this.sessionRepository.deleteMany({ + where: { + remoteJid: remoteJid, + botId: { not: null }, + }, + }); + + return { bot: { remoteJid: remoteJid, status: status } }; + } + + if (status === 'closed') { + if (defaultSettingCheck?.keepOpen) { + await this.sessionRepository.updateMany({ + where: { + remoteJid: remoteJid, + botId: { not: null }, + }, + data: { + status: 'closed', + }, + }); + } else { + await this.sessionRepository.deleteMany({ + where: { + remoteJid: remoteJid, + botId: { not: null }, + }, + }); + } + + return { bot: { ...instance, bot: { remoteJid: remoteJid, status: status } } }; + } else { + const session = await this.sessionRepository.updateMany({ + where: { + instanceId: instanceId, + remoteJid: remoteJid, + botId: { not: null }, + }, + data: { + status: status, + }, + }); + + const botData = { + remoteJid: remoteJid, + status: status, + session, + }; + + return { bot: { ...instance, bot: botData } }; + } + } catch (error) { + this.logger.error(error); + throw new Error('Error changing status'); + } + } + + public async fetchSessions(instance: InstanceDto, botId: string, remoteJid?: string) { + if (!this.integrationEnabled) throw new BadRequestException('Dify is disabled'); + + try { + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const bot = await this.botRepository.findFirst({ + where: { + id: botId, + }, + }); + + if (bot && bot.instanceId !== instanceId) { + throw new Error('Dify not found'); + } + + return await this.sessionRepository.findMany({ + where: { + instanceId: instanceId, + remoteJid, + botId: bot ? botId : { not: null }, + type: 'dify', + }, + }); + } catch (error) { + this.logger.error(error); + throw new Error('Error fetching sessions'); + } + } + + public async ignoreJid(instance: InstanceDto, data: IgnoreJidDto) { + if (!this.integrationEnabled) throw new BadRequestException('Dify is disabled'); + + try { + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const settings = await this.settingsRepository.findFirst({ + where: { + instanceId: instanceId, + }, + }); + + if (!settings) { + throw new Error('Settings not found'); + } + + let ignoreJids: any = settings?.ignoreJids || []; + + if (data.action === 'add') { + if (ignoreJids.includes(data.remoteJid)) return { ignoreJids: ignoreJids }; + + ignoreJids.push(data.remoteJid); + } else { + ignoreJids = ignoreJids.filter((jid) => jid !== data.remoteJid); + } + + const updateSettings = await this.settingsRepository.update({ + where: { + id: settings.id, + }, + data: { + ignoreJids: ignoreJids, + }, + }); + + return { + ignoreJids: updateSettings.ignoreJids, + }; + } catch (error) { + this.logger.error(error); + throw new Error('Error setting default settings'); + } + } + + // Emit + public async emit({ instance, remoteJid, msg }: EmitData) { + if (!this.integrationEnabled) return; + + try { + const settings = await this.settingsRepository.findFirst({ + where: { + instanceId: instance.instanceId, + }, + }); + + if (this.checkIgnoreJids(settings?.ignoreJids, remoteJid)) return; + + const session = await this.getSession(remoteJid, instance); + + const content = getConversationMessage(msg); + + let findBot = (await this.findBotTrigger(this.botRepository, content, instance, session)) as DifyModel; + + if (!findBot) { + const fallback = await this.settingsRepository.findFirst({ + where: { + instanceId: instance.instanceId, + }, + }); + + if (fallback?.difyIdFallback) { + const findFallback = await this.botRepository.findFirst({ + where: { + id: fallback.difyIdFallback, + }, + }); + + findBot = findFallback; + } else { + return; + } + } + + let expire = findBot?.expire; + let keywordFinish = findBot?.keywordFinish; + let delayMessage = findBot?.delayMessage; + let unknownMessage = findBot?.unknownMessage; + let listeningFromMe = findBot?.listeningFromMe; + let stopBotFromMe = findBot?.stopBotFromMe; + let keepOpen = findBot?.keepOpen; + let debounceTime = findBot?.debounceTime; + let ignoreJids = findBot?.ignoreJids; + let splitMessages = findBot?.splitMessages; + let timePerChar = findBot?.timePerChar; + + if (expire === undefined || expire === null) expire = settings.expire; + if (keywordFinish === undefined || keywordFinish === null) keywordFinish = settings.keywordFinish; + if (delayMessage === undefined || delayMessage === null) delayMessage = settings.delayMessage; + if (unknownMessage === undefined || unknownMessage === null) unknownMessage = settings.unknownMessage; + if (listeningFromMe === undefined || listeningFromMe === null) listeningFromMe = settings.listeningFromMe; + if (stopBotFromMe === undefined || stopBotFromMe === null) stopBotFromMe = settings.stopBotFromMe; + if (keepOpen === undefined || keepOpen === null) keepOpen = settings.keepOpen; + if (debounceTime === undefined || debounceTime === null) debounceTime = settings.debounceTime; + if (ignoreJids === undefined || ignoreJids === null) ignoreJids = settings.ignoreJids; + if (splitMessages === undefined || splitMessages === null) splitMessages = settings?.splitMessages ?? false; + if (timePerChar === undefined || timePerChar === null) timePerChar = settings?.timePerChar ?? 0; + + const key = msg.key as { + id: string; + remoteJid: string; + fromMe: boolean; + participant: string; + }; + + if (stopBotFromMe && key.fromMe && session) { + await this.prismaRepository.integrationSession.update({ + where: { + id: session.id, + }, + data: { + status: 'paused', + }, + }); + return; + } + + if (!listeningFromMe && key.fromMe) { + return; + } + + if (session && !session.awaitUser) { + return; + } + + if (debounceTime && debounceTime > 0) { + this.processDebounce(this.userMessageDebounce, content, remoteJid, debounceTime, async (debouncedContent) => { + await this.difyService.processDify( + this.waMonitor.waInstances[instance.instanceName], + remoteJid, + findBot, + session, + { + ...settings, + expire, + keywordFinish, + delayMessage, + unknownMessage, + listeningFromMe, + stopBotFromMe, + keepOpen, + debounceTime, + ignoreJids, + splitMessages, + timePerChar, + }, + debouncedContent, + msg?.pushName, + ); + }); + } else { + await this.difyService.processDify( + this.waMonitor.waInstances[instance.instanceName], + remoteJid, + findBot, + session, + { + ...settings, + expire, + keywordFinish, + delayMessage, + unknownMessage, + listeningFromMe, + stopBotFromMe, + keepOpen, + debounceTime, + ignoreJids, + splitMessages, + timePerChar, + }, + content, + msg?.pushName, + ); + } + + return; + } catch (error) { + this.logger.error(error); + return; + } + } +} diff --git a/src/api/integrations/chatbot/dify/dto/dify.dto.ts b/src/api/integrations/chatbot/dify/dto/dify.dto.ts new file mode 100644 index 00000000..ff9bba05 --- /dev/null +++ b/src/api/integrations/chatbot/dify/dto/dify.dto.ts @@ -0,0 +1,38 @@ +import { $Enums, TriggerOperator, TriggerType } from '@prisma/client'; + +export class DifyDto { + enabled?: boolean; + description?: string; + botType?: $Enums.DifyBotType; + apiUrl?: string; + apiKey?: string; + expire?: number; + keywordFinish?: string; + delayMessage?: number; + unknownMessage?: string; + listeningFromMe?: boolean; + stopBotFromMe?: boolean; + keepOpen?: boolean; + debounceTime?: number; + triggerType?: TriggerType; + triggerOperator?: TriggerOperator; + triggerValue?: string; + ignoreJids?: any; + splitMessages?: boolean; + timePerChar?: number; +} + +export class DifySettingDto { + expire?: number; + keywordFinish?: string; + delayMessage?: number; + unknownMessage?: string; + listeningFromMe?: boolean; + stopBotFromMe?: boolean; + keepOpen?: boolean; + debounceTime?: number; + difyIdFallback?: string; + ignoreJids?: any; + splitMessages?: boolean; + timePerChar?: number; +} diff --git a/src/api/integrations/chatbot/dify/routes/dify.router.ts b/src/api/integrations/chatbot/dify/routes/dify.router.ts new file mode 100644 index 00000000..1d80b903 --- /dev/null +++ b/src/api/integrations/chatbot/dify/routes/dify.router.ts @@ -0,0 +1,123 @@ +import { RouterBroker } from '@api/abstract/abstract.router'; +import { IgnoreJidDto } from '@api/dto/chatbot.dto'; +import { InstanceDto } from '@api/dto/instance.dto'; +import { DifyDto, DifySettingDto } from '@api/integrations/chatbot/dify/dto/dify.dto'; +import { HttpStatus } from '@api/routes/index.router'; +import { difyController } from '@api/server.module'; +import { + difyIgnoreJidSchema, + difySchema, + difySettingSchema, + difyStatusSchema, + instanceSchema, +} from '@validate/validate.schema'; +import { RequestHandler, Router } from 'express'; + +export class DifyRouter extends RouterBroker { + constructor(...guards: RequestHandler[]) { + super(); + this.router + .post(this.routerPath('create'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: difySchema, + ClassRef: DifyDto, + execute: (instance, data) => difyController.createBot(instance, data), + }); + + res.status(HttpStatus.CREATED).json(response); + }) + .get(this.routerPath('find'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => difyController.findBot(instance), + }); + + res.status(HttpStatus.OK).json(response); + }) + .get(this.routerPath('fetch/:difyId'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => difyController.fetchBot(instance, req.params.difyId), + }); + + res.status(HttpStatus.OK).json(response); + }) + .put(this.routerPath('update/:difyId'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: difySchema, + ClassRef: DifyDto, + execute: (instance, data) => difyController.updateBot(instance, req.params.difyId, data), + }); + + res.status(HttpStatus.OK).json(response); + }) + .delete(this.routerPath('delete/:difyId'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => difyController.deleteBot(instance, req.params.difyId), + }); + + res.status(HttpStatus.OK).json(response); + }) + .post(this.routerPath('settings'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: difySettingSchema, + ClassRef: DifySettingDto, + execute: (instance, data) => difyController.settings(instance, data), + }); + + res.status(HttpStatus.OK).json(response); + }) + .get(this.routerPath('fetchSettings'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => difyController.fetchSettings(instance), + }); + + res.status(HttpStatus.OK).json(response); + }) + .post(this.routerPath('changeStatus'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: difyStatusSchema, + ClassRef: InstanceDto, + execute: (instance, data) => difyController.changeStatus(instance, data), + }); + + res.status(HttpStatus.OK).json(response); + }) + .get(this.routerPath('fetchSessions/:difyId'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => difyController.fetchSessions(instance, req.params.difyId), + }); + + res.status(HttpStatus.OK).json(response); + }) + .post(this.routerPath('ignoreJid'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: difyIgnoreJidSchema, + ClassRef: IgnoreJidDto, + execute: (instance, data) => difyController.ignoreJid(instance, data), + }); + + res.status(HttpStatus.OK).json(response); + }); + } + + public readonly router: Router = Router(); +} diff --git a/src/api/integrations/chatbot/dify/services/dify.service.ts b/src/api/integrations/chatbot/dify/services/dify.service.ts new file mode 100644 index 00000000..348ee70c --- /dev/null +++ b/src/api/integrations/chatbot/dify/services/dify.service.ts @@ -0,0 +1,627 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import { InstanceDto } from '@api/dto/instance.dto'; +import { PrismaRepository } from '@api/repository/repository.service'; +import { WAMonitoringService } from '@api/services/monitor.service'; +import { Integration } from '@api/types/wa.types'; +import { Auth, ConfigService, HttpServer } from '@config/env.config'; +import { Logger } from '@config/logger.config'; +import { Dify, DifySetting, IntegrationSession } from '@prisma/client'; +import { sendTelemetry } from '@utils/sendTelemetry'; +import axios from 'axios'; +import { Readable } from 'stream'; + +export class DifyService { + constructor( + private readonly waMonitor: WAMonitoringService, + private readonly configService: ConfigService, + private readonly prismaRepository: PrismaRepository, + ) {} + + private readonly logger = new Logger('DifyService'); + + public async createNewSession(instance: InstanceDto, data: any) { + try { + const session = await this.prismaRepository.integrationSession.create({ + data: { + remoteJid: data.remoteJid, + pushName: data.pushName, + sessionId: data.remoteJid, + status: 'opened', + awaitUser: false, + botId: data.botId, + instanceId: instance.instanceId, + type: 'dify', + }, + }); + + return { session }; + } catch (error) { + this.logger.error(error); + return; + } + } + + private isImageMessage(content: string) { + return content.includes('imageMessage'); + } + + private isJSON(str: string): boolean { + try { + JSON.parse(str); + return true; + } catch (e) { + return false; + } + } + + private async sendMessageToBot( + instance: any, + session: IntegrationSession, + settings: DifySetting, + dify: Dify, + remoteJid: string, + pushName: string, + content: string, + ) { + try { + let endpoint: string = dify.apiUrl; + + if (dify.botType === 'chatBot') { + endpoint += '/chat-messages'; + const payload: any = { + inputs: { + remoteJid: remoteJid, + pushName: pushName, + instanceName: instance.instanceName, + serverUrl: this.configService.get('SERVER').URL, + apiKey: this.configService.get('AUTHENTICATION').API_KEY.KEY, + }, + query: content, + response_mode: 'blocking', + conversation_id: session.sessionId === remoteJid ? undefined : session.sessionId, + user: remoteJid, + }; + + if (this.isImageMessage(content)) { + const contentSplit = content.split('|'); + + payload.files = [ + { + type: 'image', + transfer_method: 'remote_url', + url: contentSplit[1].split('?')[0], + }, + ]; + payload.query = contentSplit[2] || content; + } + + if (instance.integration === Integration.WHATSAPP_BAILEYS) { + await instance.client.presenceSubscribe(remoteJid); + await instance.client.sendPresenceUpdate('composing', remoteJid); + } + + const response = await axios.post(endpoint, payload, { + headers: { + Authorization: `Bearer ${dify.apiKey}`, + }, + }); + + if (instance.integration === Integration.WHATSAPP_BAILEYS) + await instance.client.sendPresenceUpdate('paused', remoteJid); + + const message = response?.data?.answer; + const conversationId = response?.data?.conversation_id; + + await this.sendMessageWhatsApp(instance, remoteJid, message, settings); + + await this.prismaRepository.integrationSession.update({ + where: { + id: session.id, + }, + data: { + status: 'opened', + awaitUser: true, + sessionId: session.sessionId === remoteJid ? conversationId : session.sessionId, + }, + }); + } + + if (dify.botType === 'textGenerator') { + endpoint += '/completion-messages'; + const payload: any = { + inputs: { + query: content, + pushName: pushName, + remoteJid: remoteJid, + instanceName: instance.instanceName, + serverUrl: this.configService.get('SERVER').URL, + apiKey: this.configService.get('AUTHENTICATION').API_KEY.KEY, + }, + response_mode: 'blocking', + conversation_id: session.sessionId === remoteJid ? undefined : session.sessionId, + user: remoteJid, + }; + + if (this.isImageMessage(content)) { + const contentSplit = content.split('|'); + + payload.files = [ + { + type: 'image', + transfer_method: 'remote_url', + url: contentSplit[1].split('?')[0], + }, + ]; + payload.inputs.query = contentSplit[2] || content; + } + + if (instance.integration === Integration.WHATSAPP_BAILEYS) { + await instance.client.presenceSubscribe(remoteJid); + await instance.client.sendPresenceUpdate('composing', remoteJid); + } + + const response = await axios.post(endpoint, payload, { + headers: { + Authorization: `Bearer ${dify.apiKey}`, + }, + }); + + if (instance.integration === Integration.WHATSAPP_BAILEYS) + await instance.client.sendPresenceUpdate('paused', remoteJid); + + const message = response?.data?.answer; + const conversationId = response?.data?.conversation_id; + + await this.sendMessageWhatsApp(instance, remoteJid, message, settings); + + await this.prismaRepository.integrationSession.update({ + where: { + id: session.id, + }, + data: { + status: 'opened', + awaitUser: true, + sessionId: session.sessionId === remoteJid ? conversationId : session.sessionId, + }, + }); + } + + if (dify.botType === 'agent') { + endpoint += '/chat-messages'; + const payload: any = { + inputs: { + remoteJid: remoteJid, + pushName: pushName, + instanceName: instance.instanceName, + serverUrl: this.configService.get('SERVER').URL, + apiKey: this.configService.get('AUTHENTICATION').API_KEY.KEY, + }, + query: content, + response_mode: 'streaming', + conversation_id: session.sessionId === remoteJid ? undefined : session.sessionId, + user: remoteJid, + }; + + if (this.isImageMessage(content)) { + const contentSplit = content.split('|'); + + payload.files = [ + { + type: 'image', + transfer_method: 'remote_url', + url: contentSplit[1].split('?')[0], + }, + ]; + payload.query = contentSplit[2] || content; + } + + if (instance.integration === Integration.WHATSAPP_BAILEYS) { + await instance.client.presenceSubscribe(remoteJid); + await instance.client.sendPresenceUpdate('composing', remoteJid); + } + + const response = await axios.post(endpoint, payload, { + headers: { + Authorization: `Bearer ${dify.apiKey}`, + }, + }); + + let conversationId; + let answer = ''; + + const data = response.data.replaceAll('data: ', ''); + + const events = data.split('\n').filter((line) => line.trim() !== ''); + + for (const eventString of events) { + if (eventString.trim().startsWith('{')) { + const event = JSON.parse(eventString); + + if (event?.event === 'agent_message') { + console.log('event:', event); + conversationId = conversationId ?? event?.conversation_id; + answer += event?.answer; + } + } + } + + if (instance.integration === Integration.WHATSAPP_BAILEYS) + await instance.client.sendPresenceUpdate('paused', remoteJid); + + const message = answer; + + await this.sendMessageWhatsApp(instance, remoteJid, message, settings); + + await this.prismaRepository.integrationSession.update({ + where: { + id: session.id, + }, + data: { + status: 'opened', + awaitUser: true, + sessionId: conversationId, + }, + }); + + return; + } + + if (dify.botType === 'workflow') { + endpoint += '/workflows/run'; + const payload: any = { + inputs: { + query: content, + remoteJid: remoteJid, + pushName: pushName, + instanceName: instance.instanceName, + serverUrl: this.configService.get('SERVER').URL, + apiKey: this.configService.get('AUTHENTICATION').API_KEY.KEY, + }, + response_mode: 'blocking', + user: remoteJid, + }; + + if (this.isImageMessage(content)) { + const contentSplit = content.split('|'); + + payload.files = [ + { + type: 'image', + transfer_method: 'remote_url', + url: contentSplit[1].split('?')[0], + }, + ]; + payload.inputs.query = contentSplit[2] || content; + } + + if (instance.integration === Integration.WHATSAPP_BAILEYS) { + await instance.client.presenceSubscribe(remoteJid); + await instance.client.sendPresenceUpdate('composing', remoteJid); + } + + const response = await axios.post(endpoint, payload, { + headers: { + Authorization: `Bearer ${dify.apiKey}`, + }, + }); + + if (instance.integration === Integration.WHATSAPP_BAILEYS) + await instance.client.sendPresenceUpdate('paused', remoteJid); + + const message = response?.data?.data.outputs.text; + + await this.sendMessageWhatsApp(instance, remoteJid, message, settings); + + await this.prismaRepository.integrationSession.update({ + where: { + id: session.id, + }, + data: { + status: 'opened', + awaitUser: true, + }, + }); + + return; + } + } catch (error) { + this.logger.error(error.response?.data || error); + return; + } + } + + private async sendMessageWhatsApp(instance: any, remoteJid: string, message: string, settings: DifySetting) { + const linkRegex = /(!?)\[(.*?)\]\((.*?)\)/g; + + let textBuffer = ''; + let lastIndex = 0; + + let match: RegExpExecArray | null; + + const getMediaType = (url: string): string | null => { + const extension = url.split('.').pop()?.toLowerCase(); + const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']; + const audioExtensions = ['mp3', 'wav', 'aac', 'ogg']; + const videoExtensions = ['mp4', 'avi', 'mkv', 'mov']; + const documentExtensions = ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt']; + + if (imageExtensions.includes(extension || '')) return 'image'; + if (audioExtensions.includes(extension || '')) return 'audio'; + if (videoExtensions.includes(extension || '')) return 'video'; + if (documentExtensions.includes(extension || '')) return 'document'; + return null; + }; + + while ((match = linkRegex.exec(message)) !== null) { + const [fullMatch, exclMark, altText, url] = match; + const mediaType = getMediaType(url); + + const beforeText = message.slice(lastIndex, match.index); + if (beforeText) { + textBuffer += beforeText; + } + + if (mediaType) { + const splitMessages = settings.splitMessages ?? false; + const timePerChar = settings.timePerChar ?? 0; + const minDelay = 1000; + const maxDelay = 20000; + + if (textBuffer.trim()) { + if (splitMessages) { + const multipleMessages = textBuffer.trim().split('\n\n'); + + for (let index = 0; index < multipleMessages.length; index++) { + const message = multipleMessages[index]; + + const delay = Math.min(Math.max(message.length * timePerChar, minDelay), maxDelay); + + if (instance.integration === Integration.WHATSAPP_BAILEYS) { + await instance.client.presenceSubscribe(remoteJid); + await instance.client.sendPresenceUpdate('composing', remoteJid); + } + + await new Promise((resolve) => { + setTimeout(async () => { + await instance.textMessage( + { + number: remoteJid.split('@')[0], + delay: settings?.delayMessage || 1000, + text: message, + }, + false, + ); + resolve(); + }, delay); + }); + + if (instance.integration === Integration.WHATSAPP_BAILEYS) { + await instance.client.sendPresenceUpdate('paused', remoteJid); + } + } + } else { + await instance.textMessage( + { + number: remoteJid.split('@')[0], + delay: settings?.delayMessage || 1000, + text: textBuffer.trim(), + }, + false, + ); + } + textBuffer = ''; + } + + if (mediaType === 'audio') { + await instance.audioWhatsapp({ + number: remoteJid.split('@')[0], + delay: settings?.delayMessage || 1000, + audio: url, + caption: altText, + }); + } else { + await instance.mediaMessage( + { + number: remoteJid.split('@')[0], + delay: settings?.delayMessage || 1000, + mediatype: mediaType, + media: url, + caption: altText, + }, + null, + false, + ); + } + } else { + textBuffer += `[${altText}](${url})`; + } + + lastIndex = linkRegex.lastIndex; + } + + if (lastIndex < message.length) { + const remainingText = message.slice(lastIndex); + if (remainingText.trim()) { + textBuffer += remainingText; + } + } + + const splitMessages = settings.splitMessages ?? false; + const timePerChar = settings.timePerChar ?? 0; + const minDelay = 1000; + const maxDelay = 20000; + + if (textBuffer.trim()) { + if (splitMessages) { + const multipleMessages = textBuffer.trim().split('\n\n'); + + for (let index = 0; index < multipleMessages.length; index++) { + const message = multipleMessages[index]; + + const delay = Math.min(Math.max(message.length * timePerChar, minDelay), maxDelay); + + if (instance.integration === Integration.WHATSAPP_BAILEYS) { + await instance.client.presenceSubscribe(remoteJid); + await instance.client.sendPresenceUpdate('composing', remoteJid); + } + + await new Promise((resolve) => { + setTimeout(async () => { + await instance.textMessage( + { + number: remoteJid.split('@')[0], + delay: settings?.delayMessage || 1000, + text: message, + }, + false, + ); + resolve(); + }, delay); + }); + + if (instance.integration === Integration.WHATSAPP_BAILEYS) { + await instance.client.sendPresenceUpdate('paused', remoteJid); + } + } + } else { + await instance.textMessage( + { + number: remoteJid.split('@')[0], + delay: settings?.delayMessage || 1000, + text: textBuffer.trim(), + }, + false, + ); + } + } + + sendTelemetry('/message/sendText'); + } + + private async initNewSession( + instance: any, + remoteJid: string, + dify: Dify, + settings: DifySetting, + session: IntegrationSession, + content: string, + pushName?: string, + ) { + const data = await this.createNewSession(instance, { + remoteJid, + pushName, + botId: dify.id, + }); + + if (data.session) { + session = data.session; + } + + await this.sendMessageToBot(instance, session, settings, dify, remoteJid, pushName, content); + + return; + } + + public async processDify( + instance: any, + remoteJid: string, + dify: Dify, + session: IntegrationSession, + settings: DifySetting, + content: string, + pushName?: string, + ) { + if (session && session.status !== 'opened') { + return; + } + + if (session && settings.expire && settings.expire > 0) { + const now = Date.now(); + + const sessionUpdatedAt = new Date(session.updatedAt).getTime(); + + const diff = now - sessionUpdatedAt; + + const diffInMinutes = Math.floor(diff / 1000 / 60); + + if (diffInMinutes > settings.expire) { + if (settings.keepOpen) { + await this.prismaRepository.integrationSession.update({ + where: { + id: session.id, + }, + data: { + status: 'closed', + }, + }); + } else { + await this.prismaRepository.integrationSession.deleteMany({ + where: { + botId: dify.id, + remoteJid: remoteJid, + }, + }); + } + + await this.initNewSession(instance, remoteJid, dify, settings, session, content, pushName); + return; + } + } + + if (!session) { + await this.initNewSession(instance, remoteJid, dify, settings, session, content, pushName); + return; + } + + await this.prismaRepository.integrationSession.update({ + where: { + id: session.id, + }, + data: { + status: 'opened', + awaitUser: false, + }, + }); + + if (!content) { + if (settings.unknownMessage) { + this.waMonitor.waInstances[instance.instanceName].textMessage( + { + number: remoteJid.split('@')[0], + delay: settings.delayMessage || 1000, + text: settings.unknownMessage, + }, + false, + ); + + sendTelemetry('/message/sendText'); + } + return; + } + + if (settings.keywordFinish && content.toLowerCase() === settings.keywordFinish.toLowerCase()) { + if (settings.keepOpen) { + await this.prismaRepository.integrationSession.update({ + where: { + id: session.id, + }, + data: { + status: 'closed', + }, + }); + } else { + await this.prismaRepository.integrationSession.deleteMany({ + where: { + botId: dify.id, + remoteJid: remoteJid, + }, + }); + } + return; + } + + await this.sendMessageToBot(instance, session, settings, dify, remoteJid, pushName, content); + + return; + } +} diff --git a/src/api/integrations/chatbot/dify/validate/dify.schema.ts b/src/api/integrations/chatbot/dify/validate/dify.schema.ts new file mode 100644 index 00000000..3201a65f --- /dev/null +++ b/src/api/integrations/chatbot/dify/validate/dify.schema.ts @@ -0,0 +1,116 @@ +import { JSONSchema7 } from 'json-schema'; +import { v4 } from 'uuid'; + +const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => { + const properties = {}; + propertyNames.forEach( + (property) => + (properties[property] = { + minLength: 1, + description: `The "${property}" cannot be empty`, + }), + ); + return { + if: { + propertyNames: { + enum: [...propertyNames], + }, + }, + then: { properties }, + }; +}; + +export const difySchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + enabled: { type: 'boolean' }, + description: { type: 'string' }, + botType: { type: 'string', enum: ['chatBot', 'textGenerator', 'agent', 'workflow'] }, + apiUrl: { type: 'string' }, + apiKey: { type: 'string' }, + triggerType: { type: 'string', enum: ['all', 'keyword', 'none', 'advanced'] }, + triggerOperator: { type: 'string', enum: ['equals', 'contains', 'startsWith', 'endsWith', 'regex'] }, + triggerValue: { type: 'string' }, + expire: { type: 'integer' }, + keywordFinish: { type: 'string' }, + delayMessage: { type: 'integer' }, + unknownMessage: { type: 'string' }, + listeningFromMe: { type: 'boolean' }, + stopBotFromMe: { type: 'boolean' }, + keepOpen: { type: 'boolean' }, + debounceTime: { type: 'integer' }, + ignoreJids: { type: 'array', items: { type: 'string' } }, + splitMessages: { type: 'boolean' }, + timePerChar: { type: 'integer' }, + }, + required: ['enabled', 'botType', 'triggerType'], + ...isNotEmpty('enabled', 'botType', 'triggerType'), +}; + +export const difyStatusSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + remoteJid: { type: 'string' }, + status: { type: 'string', enum: ['opened', 'closed', 'paused', 'delete'] }, + }, + required: ['remoteJid', 'status'], + ...isNotEmpty('remoteJid', 'status'), +}; + +export const difySettingSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + expire: { type: 'integer' }, + keywordFinish: { type: 'string' }, + delayMessage: { type: 'integer' }, + unknownMessage: { type: 'string' }, + listeningFromMe: { type: 'boolean' }, + stopBotFromMe: { type: 'boolean' }, + keepOpen: { type: 'boolean' }, + debounceTime: { type: 'integer' }, + ignoreJids: { type: 'array', items: { type: 'string' } }, + difyIdFallback: { type: 'string' }, + splitMessages: { type: 'boolean' }, + timePerChar: { type: 'integer' }, + }, + required: [ + 'expire', + 'keywordFinish', + 'delayMessage', + 'unknownMessage', + 'listeningFromMe', + 'stopBotFromMe', + 'keepOpen', + 'debounceTime', + 'ignoreJids', + 'splitMessages', + 'timePerChar', + ], + ...isNotEmpty( + 'expire', + 'keywordFinish', + 'delayMessage', + 'unknownMessage', + 'listeningFromMe', + 'stopBotFromMe', + 'keepOpen', + 'debounceTime', + 'ignoreJids', + 'splitMessages', + 'timePerChar', + ), +}; + +export const difyIgnoreJidSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + remoteJid: { type: 'string' }, + action: { type: 'string', enum: ['add', 'remove'] }, + }, + required: ['remoteJid', 'action'], + ...isNotEmpty('remoteJid', 'action'), +}; diff --git a/src/api/integrations/chatbot/evolutionBot/controllers/evolutionBot.controller.ts b/src/api/integrations/chatbot/evolutionBot/controllers/evolutionBot.controller.ts new file mode 100644 index 00000000..0d5825de --- /dev/null +++ b/src/api/integrations/chatbot/evolutionBot/controllers/evolutionBot.controller.ts @@ -0,0 +1,860 @@ +import { IgnoreJidDto } from '@api/dto/chatbot.dto'; +import { InstanceDto } from '@api/dto/instance.dto'; +import { PrismaRepository } from '@api/repository/repository.service'; +import { WAMonitoringService } from '@api/services/monitor.service'; +import { Logger } from '@config/logger.config'; +import { EvolutionBot } from '@prisma/client'; +import { getConversationMessage } from '@utils/getConversationMessage'; + +import { ChatbotController, ChatbotControllerInterface, EmitData } from '../../chatbot.controller'; +import { EvolutionBotDto } from '../dto/evolutionBot.dto'; +import { EvolutionBotService } from '../services/evolutionBot.service'; + +export class EvolutionBotController extends ChatbotController implements ChatbotControllerInterface { + constructor( + private readonly evolutionBotService: EvolutionBotService, + prismaRepository: PrismaRepository, + waMonitor: WAMonitoringService, + ) { + super(prismaRepository, waMonitor); + + this.botRepository = this.prismaRepository.evolutionBot; + this.settingsRepository = this.prismaRepository.evolutionBotSetting; + this.sessionRepository = this.prismaRepository.integrationSession; + } + + public readonly logger = new Logger('EvolutionBotController'); + + integrationEnabled: boolean; + botRepository: any; + settingsRepository: any; + sessionRepository: any; + userMessageDebounce: { [key: string]: { message: string; timeoutId: NodeJS.Timeout } } = {}; + + // Bots + public async createBot(instance: InstanceDto, data: EvolutionBotDto) { + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + if ( + !data.expire || + !data.keywordFinish || + !data.delayMessage || + !data.unknownMessage || + !data.listeningFromMe || + !data.stopBotFromMe || + !data.keepOpen || + !data.debounceTime || + !data.ignoreJids || + !data.splitMessages || + !data.timePerChar + ) { + const defaultSettingCheck = await this.settingsRepository.findFirst({ + where: { + instanceId: instanceId, + }, + }); + + if (data.expire === undefined || data.expire === null) data.expire = defaultSettingCheck.expire; + if (data.keywordFinish === undefined || data.keywordFinish === null) + data.keywordFinish = defaultSettingCheck.keywordFinish; + if (data.delayMessage === undefined || data.delayMessage === null) + data.delayMessage = defaultSettingCheck.delayMessage; + if (data.unknownMessage === undefined || data.unknownMessage === null) + data.unknownMessage = defaultSettingCheck.unknownMessage; + if (data.listeningFromMe === undefined || data.listeningFromMe === null) + data.listeningFromMe = defaultSettingCheck.listeningFromMe; + if (data.stopBotFromMe === undefined || data.stopBotFromMe === null) + data.stopBotFromMe = defaultSettingCheck.stopBotFromMe; + if (data.keepOpen === undefined || data.keepOpen === null) data.keepOpen = defaultSettingCheck.keepOpen; + if (data.debounceTime === undefined || data.debounceTime === null) + data.debounceTime = defaultSettingCheck.debounceTime; + if (data.ignoreJids === undefined || data.ignoreJids === null) data.ignoreJids = defaultSettingCheck.ignoreJids; + if (data.splitMessages === undefined || data.splitMessages === null) + data.splitMessages = defaultSettingCheck?.splitMessages ?? false; + if (data.timePerChar === undefined || data.timePerChar === null) + data.timePerChar = defaultSettingCheck?.timePerChar ?? 0; + + if (!defaultSettingCheck) { + await this.settings(instance, { + expire: data.expire, + keywordFinish: data.keywordFinish, + delayMessage: data.delayMessage, + unknownMessage: data.unknownMessage, + listeningFromMe: data.listeningFromMe, + stopBotFromMe: data.stopBotFromMe, + keepOpen: data.keepOpen, + debounceTime: data.debounceTime, + ignoreJids: data.ignoreJids, + splitMessages: data.splitMessages, + timePerChar: data.timePerChar, + }); + } + } + + const checkTriggerAll = await this.botRepository.findFirst({ + where: { + enabled: true, + triggerType: 'all', + instanceId: instanceId, + }, + }); + + if (checkTriggerAll && data.triggerType === 'all') { + throw new Error('You already have a dify with an "All" trigger, you cannot have more bots while it is active'); + } + + const checkDuplicate = await this.botRepository.findFirst({ + where: { + instanceId: instanceId, + apiUrl: data.apiUrl, + apiKey: data.apiKey, + }, + }); + + if (checkDuplicate) { + throw new Error('Dify already exists'); + } + + if (data.triggerType === 'keyword') { + if (!data.triggerOperator || !data.triggerValue) { + throw new Error('Trigger operator and value are required'); + } + + const checkDuplicate = await this.botRepository.findFirst({ + where: { + triggerOperator: data.triggerOperator, + triggerValue: data.triggerValue, + instanceId: instanceId, + }, + }); + + if (checkDuplicate) { + throw new Error('Trigger already exists'); + } + } + + if (data.triggerType === 'advanced') { + if (!data.triggerValue) { + throw new Error('Trigger value is required'); + } + + const checkDuplicate = await this.botRepository.findFirst({ + where: { + triggerValue: data.triggerValue, + instanceId: instanceId, + }, + }); + + if (checkDuplicate) { + throw new Error('Trigger already exists'); + } + } + + try { + const bot = await this.botRepository.create({ + data: { + enabled: data?.enabled, + description: data.description, + apiUrl: data.apiUrl, + apiKey: data.apiKey, + expire: data.expire, + keywordFinish: data.keywordFinish, + delayMessage: data.delayMessage, + unknownMessage: data.unknownMessage, + listeningFromMe: data.listeningFromMe, + stopBotFromMe: data.stopBotFromMe, + keepOpen: data.keepOpen, + debounceTime: data.debounceTime, + instanceId: instanceId, + triggerType: data.triggerType, + triggerOperator: data.triggerOperator, + triggerValue: data.triggerValue, + ignoreJids: data.ignoreJids, + splitMessages: data.splitMessages, + timePerChar: data.timePerChar, + }, + }); + + return bot; + } catch (error) { + this.logger.error(error); + throw new Error('Error creating bot'); + } + } + + public async findBot(instance: InstanceDto) { + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const bots = await this.botRepository.findMany({ + where: { + instanceId: instanceId, + }, + }); + + if (!bots.length) { + return null; + } + + return bots; + } + + public async fetchBot(instance: InstanceDto, botId: string) { + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const bot = await this.botRepository.findFirst({ + where: { + id: botId, + }, + }); + + if (!bot) { + throw new Error('Bot not found'); + } + + if (bot.instanceId !== instanceId) { + throw new Error('Bot not found'); + } + + return bot; + } + + public async updateBot(instance: InstanceDto, botId: string, data: EvolutionBotDto) { + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const bot = await this.botRepository.findFirst({ + where: { + id: botId, + }, + }); + + if (!bot) { + throw new Error('Bot not found'); + } + + if (bot.instanceId !== instanceId) { + throw new Error('Bot not found'); + } + + if (data.triggerType === 'all') { + const checkTriggerAll = await this.botRepository.findFirst({ + where: { + enabled: true, + triggerType: 'all', + id: { + not: botId, + }, + instanceId: instanceId, + }, + }); + + if (checkTriggerAll) { + throw new Error('You already have a bot with an "All" trigger, you cannot have more bots while it is active'); + } + } + + const checkDuplicate = await this.botRepository.findFirst({ + where: { + id: { + not: botId, + }, + instanceId: instanceId, + apiUrl: data.apiUrl, + apiKey: data.apiKey, + }, + }); + + if (checkDuplicate) { + throw new Error('Bot already exists'); + } + + if (data.triggerType === 'keyword') { + if (!data.triggerOperator || !data.triggerValue) { + throw new Error('Trigger operator and value are required'); + } + + const checkDuplicate = await this.botRepository.findFirst({ + where: { + triggerOperator: data.triggerOperator, + triggerValue: data.triggerValue, + id: { not: botId }, + instanceId: instanceId, + }, + }); + + if (checkDuplicate) { + throw new Error('Trigger already exists'); + } + } + + if (data.triggerType === 'advanced') { + if (!data.triggerValue) { + throw new Error('Trigger value is required'); + } + + const checkDuplicate = await this.botRepository.findFirst({ + where: { + triggerValue: data.triggerValue, + id: { not: botId }, + instanceId: instanceId, + }, + }); + + if (checkDuplicate) { + throw new Error('Trigger already exists'); + } + } + + try { + const bot = await this.botRepository.update({ + where: { + id: botId, + }, + data: { + enabled: data?.enabled, + description: data.description, + apiUrl: data.apiUrl, + apiKey: data.apiKey, + expire: data.expire, + keywordFinish: data.keywordFinish, + delayMessage: data.delayMessage, + unknownMessage: data.unknownMessage, + listeningFromMe: data.listeningFromMe, + stopBotFromMe: data.stopBotFromMe, + keepOpen: data.keepOpen, + debounceTime: data.debounceTime, + instanceId: instanceId, + triggerType: data.triggerType, + triggerOperator: data.triggerOperator, + triggerValue: data.triggerValue, + ignoreJids: data.ignoreJids, + splitMessages: data.splitMessages, + timePerChar: data.timePerChar, + }, + }); + + return bot; + } catch (error) { + this.logger.error(error); + throw new Error('Error updating bot'); + } + } + + public async deleteBot(instance: InstanceDto, botId: string) { + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const bot = await this.botRepository.findFirst({ + where: { + id: botId, + }, + }); + + if (!bot) { + throw new Error('Bot not found'); + } + + if (bot.instanceId !== instanceId) { + throw new Error('Bot not found'); + } + try { + await this.prismaRepository.integrationSession.deleteMany({ + where: { + botId: botId, + }, + }); + + await this.botRepository.delete({ + where: { + id: botId, + }, + }); + + return { bot: { id: botId } }; + } catch (error) { + this.logger.error(error); + throw new Error('Error deleting bot'); + } + } + + // Settings + public async settings(instance: InstanceDto, data: any) { + try { + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const settings = await this.settingsRepository.findFirst({ + where: { + instanceId: instanceId, + }, + }); + + if (settings) { + const updateSettings = await this.settingsRepository.update({ + where: { + id: settings.id, + }, + data: { + expire: data.expire, + keywordFinish: data.keywordFinish, + delayMessage: data.delayMessage, + unknownMessage: data.unknownMessage, + listeningFromMe: data.listeningFromMe, + stopBotFromMe: data.stopBotFromMe, + keepOpen: data.keepOpen, + debounceTime: data.debounceTime, + botIdFallback: data.botIdFallback, + ignoreJids: data.ignoreJids, + splitMessages: data.splitMessages, + timePerChar: data.timePerChar, + }, + }); + + return { + expire: updateSettings.expire, + keywordFinish: updateSettings.keywordFinish, + delayMessage: updateSettings.delayMessage, + unknownMessage: updateSettings.unknownMessage, + listeningFromMe: updateSettings.listeningFromMe, + stopBotFromMe: updateSettings.stopBotFromMe, + keepOpen: updateSettings.keepOpen, + debounceTime: updateSettings.debounceTime, + botIdFallback: updateSettings.botIdFallback, + ignoreJids: updateSettings.ignoreJids, + splitMessages: updateSettings.splitMessages, + timePerChar: updateSettings.timePerChar, + }; + } + + const newSetttings = await this.settingsRepository.create({ + data: { + expire: data.expire, + keywordFinish: data.keywordFinish, + delayMessage: data.delayMessage, + unknownMessage: data.unknownMessage, + listeningFromMe: data.listeningFromMe, + stopBotFromMe: data.stopBotFromMe, + keepOpen: data.keepOpen, + debounceTime: data.debounceTime, + botIdFallback: data.botIdFallback, + ignoreJids: data.ignoreJids, + splitMessages: data.splitMessages, + timePerChar: data.timePerChar, + instanceId: instanceId, + }, + }); + + return { + expire: newSetttings.expire, + keywordFinish: newSetttings.keywordFinish, + delayMessage: newSetttings.delayMessage, + unknownMessage: newSetttings.unknownMessage, + listeningFromMe: newSetttings.listeningFromMe, + stopBotFromMe: newSetttings.stopBotFromMe, + keepOpen: newSetttings.keepOpen, + debounceTime: newSetttings.debounceTime, + botIdFallback: newSetttings.botIdFallback, + ignoreJids: newSetttings.ignoreJids, + splitMessages: newSetttings.splitMessages, + timePerChar: newSetttings.timePerChar, + }; + } catch (error) { + this.logger.error(error); + throw new Error('Error setting default settings'); + } + } + + public async fetchSettings(instance: InstanceDto) { + try { + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const settings = await this.settingsRepository.findFirst({ + where: { + instanceId: instanceId, + }, + include: { + Fallback: true, + }, + }); + + if (!settings) { + return { + expire: 0, + keywordFinish: '', + delayMessage: 0, + unknownMessage: '', + listeningFromMe: false, + stopBotFromMe: false, + keepOpen: false, + ignoreJids: [], + splitMessages: false, + timePerChar: 0, + botIdFallback: '', + fallback: null, + }; + } + + return { + expire: settings.expire, + keywordFinish: settings.keywordFinish, + delayMessage: settings.delayMessage, + unknownMessage: settings.unknownMessage, + listeningFromMe: settings.listeningFromMe, + stopBotFromMe: settings.stopBotFromMe, + keepOpen: settings.keepOpen, + ignoreJids: settings.ignoreJids, + splitMessages: settings.splitMessages, + timePerChar: settings.timePerChar, + botIdFallback: settings.botIdFallback, + fallback: settings.Fallback, + }; + } catch (error) { + this.logger.error(error); + throw new Error('Error fetching default settings'); + } + } + + // Sessions + public async changeStatus(instance: InstanceDto, data: any) { + try { + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const defaultSettingCheck = await this.settingsRepository.findFirst({ + where: { + instanceId, + }, + }); + + const remoteJid = data.remoteJid; + const status = data.status; + + if (status === 'delete') { + await this.sessionRepository.deleteMany({ + where: { + remoteJid: remoteJid, + botId: { not: null }, + }, + }); + + return { bot: { remoteJid: remoteJid, status: status } }; + } + + if (status === 'closed') { + if (defaultSettingCheck?.keepOpen) { + await this.sessionRepository.updateMany({ + where: { + remoteJid: remoteJid, + botId: { not: null }, + }, + data: { + status: 'closed', + }, + }); + } else { + await this.sessionRepository.deleteMany({ + where: { + remoteJid: remoteJid, + botId: { not: null }, + }, + }); + } + + return { bot: { ...instance, bot: { remoteJid: remoteJid, status: status } } }; + } else { + const session = await this.sessionRepository.updateMany({ + where: { + instanceId: instanceId, + remoteJid: remoteJid, + botId: { not: null }, + }, + data: { + status: status, + }, + }); + + const botData = { + remoteJid: remoteJid, + status: status, + session, + }; + + return { bot: { ...instance, bot: botData } }; + } + } catch (error) { + this.logger.error(error); + throw new Error('Error changing status'); + } + } + + public async fetchSessions(instance: InstanceDto, botId: string, remoteJid?: string) { + try { + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const bot = await this.botRepository.findFirst({ + where: { + id: botId, + }, + }); + + if (bot && bot.instanceId !== instanceId) { + throw new Error('Dify not found'); + } + + return await this.sessionRepository.findMany({ + where: { + instanceId: instanceId, + remoteJid, + botId: bot ? botId : { not: null }, + type: 'evolution', + }, + }); + } catch (error) { + this.logger.error(error); + throw new Error('Error fetching sessions'); + } + } + + public async ignoreJid(instance: InstanceDto, data: IgnoreJidDto) { + try { + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const settings = await this.settingsRepository.findFirst({ + where: { + instanceId: instanceId, + }, + }); + + if (!settings) { + throw new Error('Settings not found'); + } + + let ignoreJids: any = settings?.ignoreJids || []; + + if (data.action === 'add') { + if (ignoreJids.includes(data.remoteJid)) return { ignoreJids: ignoreJids }; + + ignoreJids.push(data.remoteJid); + } else { + ignoreJids = ignoreJids.filter((jid) => jid !== data.remoteJid); + } + + const updateSettings = await this.settingsRepository.update({ + where: { + id: settings.id, + }, + data: { + ignoreJids: ignoreJids, + }, + }); + + return { + ignoreJids: updateSettings.ignoreJids, + }; + } catch (error) { + this.logger.error(error); + throw new Error('Error setting default settings'); + } + } + + // Emit + public async emit({ instance, remoteJid, msg }: EmitData) { + try { + const settings = await this.settingsRepository.findFirst({ + where: { + instanceId: instance.instanceId, + }, + }); + + if (this.checkIgnoreJids(settings?.ignoreJids, remoteJid)) return; + + const session = await this.getSession(remoteJid, instance); + + const content = getConversationMessage(msg); + + let findBot = (await this.findBotTrigger(this.botRepository, content, instance, session)) as EvolutionBot; + + if (!findBot) { + const fallback = await this.settingsRepository.findFirst({ + where: { + instanceId: instance.instanceId, + }, + }); + + if (fallback?.botIdFallback) { + const findFallback = await this.botRepository.findFirst({ + where: { + id: fallback.botIdFallback, + }, + }); + + findBot = findFallback; + } else { + return; + } + } + + let expire = findBot?.expire; + let keywordFinish = findBot?.keywordFinish; + let delayMessage = findBot?.delayMessage; + let unknownMessage = findBot?.unknownMessage; + let listeningFromMe = findBot?.listeningFromMe; + let stopBotFromMe = findBot?.stopBotFromMe; + let keepOpen = findBot?.keepOpen; + let debounceTime = findBot?.debounceTime; + let ignoreJids = findBot?.ignoreJids; + let splitMessages = findBot?.splitMessages; + let timePerChar = findBot?.timePerChar; + + if (expire === undefined || expire === null) expire = settings.expire; + if (keywordFinish === undefined || keywordFinish === null) keywordFinish = settings.keywordFinish; + if (delayMessage === undefined || delayMessage === null) delayMessage = settings.delayMessage; + if (unknownMessage === undefined || unknownMessage === null) unknownMessage = settings.unknownMessage; + if (listeningFromMe === undefined || listeningFromMe === null) listeningFromMe = settings.listeningFromMe; + if (stopBotFromMe === undefined || stopBotFromMe === null) stopBotFromMe = settings.stopBotFromMe; + if (keepOpen === undefined || keepOpen === null) keepOpen = settings.keepOpen; + if (debounceTime === undefined || debounceTime === null) debounceTime = settings.debounceTime; + if (ignoreJids === undefined || ignoreJids === null) ignoreJids = settings.ignoreJids; + if (splitMessages === undefined || splitMessages === null) splitMessages = settings?.splitMessages ?? false; + if (timePerChar === undefined || timePerChar === null) timePerChar = settings?.timePerChar ?? 0; + + const key = msg.key as { + id: string; + remoteJid: string; + fromMe: boolean; + participant: string; + }; + + if (stopBotFromMe && key.fromMe && session) { + await this.prismaRepository.integrationSession.update({ + where: { + id: session.id, + }, + data: { + status: 'paused', + }, + }); + return; + } + + if (!listeningFromMe && key.fromMe) { + return; + } + + if (session && !session.awaitUser) { + return; + } + + if (debounceTime && debounceTime > 0) { + this.processDebounce(this.userMessageDebounce, content, remoteJid, debounceTime, async (debouncedContent) => { + await this.evolutionBotService.processBot( + this.waMonitor.waInstances[instance.instanceName], + remoteJid, + findBot, + session, + { + ...settings, + expire, + keywordFinish, + delayMessage, + unknownMessage, + listeningFromMe, + stopBotFromMe, + keepOpen, + debounceTime, + ignoreJids, + splitMessages, + timePerChar, + }, + debouncedContent, + msg?.pushName, + ); + }); + } else { + await this.evolutionBotService.processBot( + this.waMonitor.waInstances[instance.instanceName], + remoteJid, + findBot, + session, + { + ...settings, + expire, + keywordFinish, + delayMessage, + unknownMessage, + listeningFromMe, + stopBotFromMe, + keepOpen, + debounceTime, + ignoreJids, + splitMessages, + timePerChar, + }, + content, + msg?.pushName, + ); + } + + return; + } catch (error) { + this.logger.error(error); + return; + } + } +} diff --git a/src/api/integrations/chatbot/evolutionBot/dto/evolutionBot.dto.ts b/src/api/integrations/chatbot/evolutionBot/dto/evolutionBot.dto.ts new file mode 100644 index 00000000..de2d952c --- /dev/null +++ b/src/api/integrations/chatbot/evolutionBot/dto/evolutionBot.dto.ts @@ -0,0 +1,37 @@ +import { TriggerOperator, TriggerType } from '@prisma/client'; + +export class EvolutionBotDto { + enabled?: boolean; + description?: string; + apiUrl?: string; + apiKey?: string; + expire?: number; + keywordFinish?: string; + delayMessage?: number; + unknownMessage?: string; + listeningFromMe?: boolean; + stopBotFromMe?: boolean; + keepOpen?: boolean; + debounceTime?: number; + triggerType?: TriggerType; + triggerOperator?: TriggerOperator; + triggerValue?: string; + ignoreJids?: any; + splitMessages?: boolean; + timePerChar?: number; +} + +export class EvolutionBotSettingDto { + expire?: number; + keywordFinish?: string; + delayMessage?: number; + unknownMessage?: string; + listeningFromMe?: boolean; + stopBotFromMe?: boolean; + keepOpen?: boolean; + debounceTime?: number; + botIdFallback?: string; + ignoreJids?: any; + splitMessages?: boolean; + timePerChar?: number; +} diff --git a/src/api/integrations/chatbot/evolutionBot/routes/evolutionBot.router.ts b/src/api/integrations/chatbot/evolutionBot/routes/evolutionBot.router.ts new file mode 100644 index 00000000..15c1e743 --- /dev/null +++ b/src/api/integrations/chatbot/evolutionBot/routes/evolutionBot.router.ts @@ -0,0 +1,124 @@ +import { RouterBroker } from '@api/abstract/abstract.router'; +import { IgnoreJidDto } from '@api/dto/chatbot.dto'; +import { InstanceDto } from '@api/dto/instance.dto'; +import { HttpStatus } from '@api/routes/index.router'; +import { evolutionBotController } from '@api/server.module'; +import { instanceSchema } from '@validate/instance.schema'; +import { RequestHandler, Router } from 'express'; + +import { EvolutionBotDto, EvolutionBotSettingDto } from '../dto/evolutionBot.dto'; +import { + evolutionBotIgnoreJidSchema, + evolutionBotSchema, + evolutionBotSettingSchema, + evolutionBotStatusSchema, +} from '../validate/evolutionBot.schema'; + +export class EvolutionBotRouter extends RouterBroker { + constructor(...guards: RequestHandler[]) { + super(); + this.router + .post(this.routerPath('create'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: evolutionBotSchema, + ClassRef: EvolutionBotDto, + execute: (instance, data) => evolutionBotController.createBot(instance, data), + }); + + res.status(HttpStatus.CREATED).json(response); + }) + .get(this.routerPath('find'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => evolutionBotController.findBot(instance), + }); + + res.status(HttpStatus.OK).json(response); + }) + .get(this.routerPath('fetch/:evolutionBotId'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => evolutionBotController.fetchBot(instance, req.params.evolutionBotId), + }); + + res.status(HttpStatus.OK).json(response); + }) + .put(this.routerPath('update/:evolutionBotId'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: evolutionBotSchema, + ClassRef: EvolutionBotDto, + execute: (instance, data) => evolutionBotController.updateBot(instance, req.params.evolutionBotId, data), + }); + + res.status(HttpStatus.OK).json(response); + }) + .delete(this.routerPath('delete/:evolutionBotId'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => evolutionBotController.deleteBot(instance, req.params.evolutionBotId), + }); + + res.status(HttpStatus.OK).json(response); + }) + .post(this.routerPath('settings'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: evolutionBotSettingSchema, + ClassRef: EvolutionBotSettingDto, + execute: (instance, data) => evolutionBotController.settings(instance, data), + }); + + res.status(HttpStatus.OK).json(response); + }) + .get(this.routerPath('fetchSettings'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => evolutionBotController.fetchSettings(instance), + }); + + res.status(HttpStatus.OK).json(response); + }) + .post(this.routerPath('changeStatus'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: evolutionBotStatusSchema, + ClassRef: InstanceDto, + execute: (instance, data) => evolutionBotController.changeStatus(instance, data), + }); + + res.status(HttpStatus.OK).json(response); + }) + .get(this.routerPath('fetchSessions/:evolutionBotId'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => evolutionBotController.fetchSessions(instance, req.params.evolutionBotId), + }); + + res.status(HttpStatus.OK).json(response); + }) + .post(this.routerPath('ignoreJid'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: evolutionBotIgnoreJidSchema, + ClassRef: IgnoreJidDto, + execute: (instance, data) => evolutionBotController.ignoreJid(instance, data), + }); + + res.status(HttpStatus.OK).json(response); + }); + } + + public readonly router: Router = Router(); +} diff --git a/src/api/integrations/chatbot/evolutionBot/services/evolutionBot.service.ts b/src/api/integrations/chatbot/evolutionBot/services/evolutionBot.service.ts new file mode 100644 index 00000000..5275f9e1 --- /dev/null +++ b/src/api/integrations/chatbot/evolutionBot/services/evolutionBot.service.ts @@ -0,0 +1,428 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import { InstanceDto } from '@api/dto/instance.dto'; +import { PrismaRepository } from '@api/repository/repository.service'; +import { WAMonitoringService } from '@api/services/monitor.service'; +import { Integration } from '@api/types/wa.types'; +import { Auth, ConfigService, HttpServer } from '@config/env.config'; +import { Logger } from '@config/logger.config'; +import { EvolutionBot, EvolutionBotSetting, IntegrationSession } from '@prisma/client'; +import { sendTelemetry } from '@utils/sendTelemetry'; +import axios from 'axios'; + +export class EvolutionBotService { + constructor( + private readonly waMonitor: WAMonitoringService, + private readonly configService: ConfigService, + private readonly prismaRepository: PrismaRepository, + ) {} + + private readonly logger = new Logger('EvolutionBotService'); + + public async createNewSession(instance: InstanceDto, data: any) { + try { + const session = await this.prismaRepository.integrationSession.create({ + data: { + remoteJid: data.remoteJid, + pushName: data.pushName, + sessionId: data.remoteJid, + status: 'opened', + awaitUser: false, + botId: data.botId, + instanceId: instance.instanceId, + type: 'evolution', + }, + }); + + return { session }; + } catch (error) { + this.logger.error(error); + return; + } + } + + private isImageMessage(content: string) { + return content.includes('imageMessage'); + } + + private async sendMessageToBot( + instance: any, + session: IntegrationSession, + bot: EvolutionBot, + remoteJid: string, + pushName: string, + content: string, + ) { + const payload: any = { + inputs: { + sessionId: session.id, + remoteJid: remoteJid, + pushName: pushName, + instanceName: instance.instanceName, + serverUrl: this.configService.get('SERVER').URL, + apiKey: this.configService.get('AUTHENTICATION').API_KEY.KEY, + }, + query: content, + conversation_id: session.sessionId === remoteJid ? undefined : session.sessionId, + user: remoteJid, + }; + + if (this.isImageMessage(content)) { + const contentSplit = content.split('|'); + + payload.files = [ + { + type: 'image', + url: contentSplit[1].split('?')[0], + }, + ]; + payload.query = contentSplit[2] || content; + } + + if (instance.integration === Integration.WHATSAPP_BAILEYS) { + await instance.client.presenceSubscribe(remoteJid); + await instance.client.sendPresenceUpdate('composing', remoteJid); + } + + let headers: any = { + 'Content-Type': 'application/json', + }; + + if (bot.apiKey) { + headers = { + ...headers, + Authorization: `Bearer ${bot.apiKey}`, + }; + } + + const response = await axios.post(bot.apiUrl, payload, { + headers, + }); + + if (instance.integration === Integration.WHATSAPP_BAILEYS) + await instance.client.sendPresenceUpdate('paused', remoteJid); + + const message = response?.data?.message; + + return message; + } + + private async sendMessageWhatsApp( + instance: any, + remoteJid: string, + session: IntegrationSession, + settings: EvolutionBotSetting, + message: string, + ) { + const linkRegex = /(!?)\[(.*?)\]\((.*?)\)/g; + + let textBuffer = ''; + let lastIndex = 0; + + let match: RegExpExecArray | null; + + const getMediaType = (url: string): string | null => { + const extension = url.split('.').pop()?.toLowerCase(); + const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']; + const audioExtensions = ['mp3', 'wav', 'aac', 'ogg']; + const videoExtensions = ['mp4', 'avi', 'mkv', 'mov']; + const documentExtensions = ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt']; + + if (imageExtensions.includes(extension || '')) return 'image'; + if (audioExtensions.includes(extension || '')) return 'audio'; + if (videoExtensions.includes(extension || '')) return 'video'; + if (documentExtensions.includes(extension || '')) return 'document'; + return null; + }; + + while ((match = linkRegex.exec(message)) !== null) { + const [fullMatch, exclMark, altText, url] = match; + const mediaType = getMediaType(url); + + const beforeText = message.slice(lastIndex, match.index); + if (beforeText) { + textBuffer += beforeText; + } + + if (mediaType) { + const splitMessages = settings.splitMessages ?? false; + const timePerChar = settings.timePerChar ?? 0; + const minDelay = 1000; + const maxDelay = 20000; + + if (textBuffer.trim()) { + if (splitMessages) { + const multipleMessages = textBuffer.trim().split('\n\n'); + + for (let index = 0; index < multipleMessages.length; index++) { + const message = multipleMessages[index]; + + const delay = Math.min(Math.max(message.length * timePerChar, minDelay), maxDelay); + + if (instance.integration === Integration.WHATSAPP_BAILEYS) { + await instance.client.presenceSubscribe(remoteJid); + await instance.client.sendPresenceUpdate('composing', remoteJid); + } + + await new Promise((resolve) => { + setTimeout(async () => { + await instance.textMessage( + { + number: remoteJid.split('@')[0], + delay: settings?.delayMessage || 1000, + text: message, + }, + false, + ); + resolve(); + }, delay); + }); + + if (instance.integration === Integration.WHATSAPP_BAILEYS) { + await instance.client.sendPresenceUpdate('paused', remoteJid); + } + } + } else { + await instance.textMessage( + { + number: remoteJid.split('@')[0], + delay: settings?.delayMessage || 1000, + text: textBuffer.trim(), + }, + false, + ); + } + textBuffer = ''; + } + + if (mediaType === 'audio') { + await instance.audioWhatsapp({ + number: remoteJid.split('@')[0], + delay: settings?.delayMessage || 1000, + audio: url, + caption: altText, + }); + } else { + await instance.mediaMessage( + { + number: remoteJid.split('@')[0], + delay: settings?.delayMessage || 1000, + mediatype: mediaType, + media: url, + caption: altText, + }, + null, + false, + ); + } + } else { + textBuffer += `[${altText}](${url})`; + } + + lastIndex = linkRegex.lastIndex; + } + + if (lastIndex < message.length) { + const remainingText = message.slice(lastIndex); + if (remainingText.trim()) { + textBuffer += remainingText; + } + } + + const splitMessages = settings.splitMessages ?? false; + const timePerChar = settings.timePerChar ?? 0; + const minDelay = 1000; + const maxDelay = 20000; + + if (textBuffer.trim()) { + if (splitMessages) { + const multipleMessages = textBuffer.trim().split('\n\n'); + + for (let index = 0; index < multipleMessages.length; index++) { + const message = multipleMessages[index]; + + const delay = Math.min(Math.max(message.length * timePerChar, minDelay), maxDelay); + + if (instance.integration === Integration.WHATSAPP_BAILEYS) { + await instance.client.presenceSubscribe(remoteJid); + await instance.client.sendPresenceUpdate('composing', remoteJid); + } + + await new Promise((resolve) => { + setTimeout(async () => { + await instance.textMessage( + { + number: remoteJid.split('@')[0], + delay: settings?.delayMessage || 1000, + text: message, + }, + false, + ); + resolve(); + }, delay); + }); + + if (instance.integration === Integration.WHATSAPP_BAILEYS) { + await instance.client.sendPresenceUpdate('paused', remoteJid); + } + } + } else { + await instance.textMessage( + { + number: remoteJid.split('@')[0], + delay: settings?.delayMessage || 1000, + text: textBuffer.trim(), + }, + false, + ); + } + textBuffer = ''; + } + + sendTelemetry('/message/sendText'); + + await this.prismaRepository.integrationSession.update({ + where: { + id: session.id, + }, + data: { + status: 'opened', + awaitUser: true, + }, + }); + } + + private async initNewSession( + instance: any, + remoteJid: string, + bot: EvolutionBot, + settings: EvolutionBotSetting, + session: IntegrationSession, + content: string, + pushName?: string, + ) { + const data = await this.createNewSession(instance, { + remoteJid, + pushName, + botId: bot.id, + }); + + if (data.session) { + session = data.session; + } + + const message = await this.sendMessageToBot(instance, session, bot, remoteJid, pushName, content); + + if (!message) return; + + await this.sendMessageWhatsApp(instance, remoteJid, session, settings, message); + + return; + } + + public async processBot( + instance: any, + remoteJid: string, + bot: EvolutionBot, + session: IntegrationSession, + settings: EvolutionBotSetting, + content: string, + pushName?: string, + ) { + if (session && session.status !== 'opened') { + return; + } + + if (session && settings.expire && settings.expire > 0) { + const now = Date.now(); + + const sessionUpdatedAt = new Date(session.updatedAt).getTime(); + + const diff = now - sessionUpdatedAt; + + const diffInMinutes = Math.floor(diff / 1000 / 60); + + if (diffInMinutes > settings.expire) { + if (settings.keepOpen) { + await this.prismaRepository.integrationSession.update({ + where: { + id: session.id, + }, + data: { + status: 'closed', + }, + }); + } else { + await this.prismaRepository.integrationSession.deleteMany({ + where: { + botId: bot.id, + remoteJid: remoteJid, + }, + }); + } + + await this.initNewSession(instance, remoteJid, bot, settings, session, content, pushName); + return; + } + } + + if (!session) { + await this.initNewSession(instance, remoteJid, bot, settings, session, content, pushName); + return; + } + + await this.prismaRepository.integrationSession.update({ + where: { + id: session.id, + }, + data: { + status: 'opened', + awaitUser: false, + }, + }); + + if (!content) { + if (settings.unknownMessage) { + this.waMonitor.waInstances[instance.instanceName].textMessage( + { + number: remoteJid.split('@')[0], + delay: settings.delayMessage || 1000, + text: settings.unknownMessage, + }, + false, + ); + + sendTelemetry('/message/sendText'); + } + return; + } + + if (settings.keywordFinish && content.toLowerCase() === settings.keywordFinish.toLowerCase()) { + if (settings.keepOpen) { + await this.prismaRepository.integrationSession.update({ + where: { + id: session.id, + }, + data: { + status: 'closed', + }, + }); + } else { + await this.prismaRepository.integrationSession.deleteMany({ + where: { + botId: bot.id, + remoteJid: remoteJid, + }, + }); + } + return; + } + + const message = await this.sendMessageToBot(instance, session, bot, remoteJid, pushName, content); + + if (!message) return; + + await this.sendMessageWhatsApp(instance, remoteJid, session, settings, message); + + return; + } +} diff --git a/src/api/integrations/chatbot/evolutionBot/validate/evolutionBot.schema.ts b/src/api/integrations/chatbot/evolutionBot/validate/evolutionBot.schema.ts new file mode 100644 index 00000000..9fd541f4 --- /dev/null +++ b/src/api/integrations/chatbot/evolutionBot/validate/evolutionBot.schema.ts @@ -0,0 +1,115 @@ +import { JSONSchema7 } from 'json-schema'; +import { v4 } from 'uuid'; + +const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => { + const properties = {}; + propertyNames.forEach( + (property) => + (properties[property] = { + minLength: 1, + description: `The "${property}" cannot be empty`, + }), + ); + return { + if: { + propertyNames: { + enum: [...propertyNames], + }, + }, + then: { properties }, + }; +}; + +export const evolutionBotSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + enabled: { type: 'boolean' }, + description: { type: 'string' }, + apiUrl: { type: 'string' }, + apiKey: { type: 'string' }, + triggerType: { type: 'string', enum: ['all', 'keyword', 'none', 'advanced'] }, + triggerOperator: { type: 'string', enum: ['equals', 'contains', 'startsWith', 'endsWith', 'regex'] }, + triggerValue: { type: 'string' }, + expire: { type: 'integer' }, + keywordFinish: { type: 'string' }, + delayMessage: { type: 'integer' }, + unknownMessage: { type: 'string' }, + listeningFromMe: { type: 'boolean' }, + stopBotFromMe: { type: 'boolean' }, + keepOpen: { type: 'boolean' }, + debounceTime: { type: 'integer' }, + ignoreJids: { type: 'array', items: { type: 'string' } }, + splitMessages: { type: 'boolean' }, + timePerChar: { type: 'integer' }, + }, + required: ['enabled', 'apiUrl', 'triggerType'], + ...isNotEmpty('enabled', 'apiUrl', 'triggerType'), +}; + +export const evolutionBotStatusSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + remoteJid: { type: 'string' }, + status: { type: 'string', enum: ['opened', 'closed', 'paused', 'delete'] }, + }, + required: ['remoteJid', 'status'], + ...isNotEmpty('remoteJid', 'status'), +}; + +export const evolutionBotSettingSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + expire: { type: 'integer' }, + keywordFinish: { type: 'string' }, + delayMessage: { type: 'integer' }, + unknownMessage: { type: 'string' }, + listeningFromMe: { type: 'boolean' }, + stopBotFromMe: { type: 'boolean' }, + keepOpen: { type: 'boolean' }, + debounceTime: { type: 'integer' }, + ignoreJids: { type: 'array', items: { type: 'string' } }, + botIdFallback: { type: 'string' }, + splitMessages: { type: 'boolean' }, + timePerChar: { type: 'integer' }, + }, + required: [ + 'expire', + 'keywordFinish', + 'delayMessage', + 'unknownMessage', + 'listeningFromMe', + 'stopBotFromMe', + 'keepOpen', + 'debounceTime', + 'ignoreJids', + 'splitMessages', + 'timePerChar', + ], + ...isNotEmpty( + 'expire', + 'keywordFinish', + 'delayMessage', + 'unknownMessage', + 'listeningFromMe', + 'stopBotFromMe', + 'keepOpen', + 'debounceTime', + 'ignoreJids', + 'splitMessages', + 'timePerChar', + ), +}; + +export const evolutionBotIgnoreJidSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + remoteJid: { type: 'string' }, + action: { type: 'string', enum: ['add', 'remove'] }, + }, + required: ['remoteJid', 'action'], + ...isNotEmpty('remoteJid', 'action'), +}; diff --git a/src/api/integrations/chatbot/flowise/controllers/flowise.controller.ts b/src/api/integrations/chatbot/flowise/controllers/flowise.controller.ts new file mode 100644 index 00000000..c2d3300b --- /dev/null +++ b/src/api/integrations/chatbot/flowise/controllers/flowise.controller.ts @@ -0,0 +1,860 @@ +import { IgnoreJidDto } from '@api/dto/chatbot.dto'; +import { InstanceDto } from '@api/dto/instance.dto'; +import { PrismaRepository } from '@api/repository/repository.service'; +import { WAMonitoringService } from '@api/services/monitor.service'; +import { Logger } from '@config/logger.config'; +import { Flowise } from '@prisma/client'; +import { getConversationMessage } from '@utils/getConversationMessage'; + +import { ChatbotController, ChatbotControllerInterface, EmitData } from '../../chatbot.controller'; +import { FlowiseDto } from '../dto/flowise.dto'; +import { FlowiseService } from '../services/flowise.service'; + +export class FlowiseController extends ChatbotController implements ChatbotControllerInterface { + constructor( + private readonly flowiseService: FlowiseService, + prismaRepository: PrismaRepository, + waMonitor: WAMonitoringService, + ) { + super(prismaRepository, waMonitor); + + this.botRepository = this.prismaRepository.flowise; + this.settingsRepository = this.prismaRepository.flowiseSetting; + this.sessionRepository = this.prismaRepository.integrationSession; + } + + public readonly logger = new Logger('FlowiseController'); + + integrationEnabled: boolean; + botRepository: any; + settingsRepository: any; + sessionRepository: any; + userMessageDebounce: { [key: string]: { message: string; timeoutId: NodeJS.Timeout } } = {}; + + // Bots + public async createBot(instance: InstanceDto, data: FlowiseDto) { + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + if ( + !data.expire || + !data.keywordFinish || + !data.delayMessage || + !data.unknownMessage || + !data.listeningFromMe || + !data.stopBotFromMe || + !data.keepOpen || + !data.debounceTime || + !data.ignoreJids || + !data.splitMessages || + !data.timePerChar + ) { + const defaultSettingCheck = await this.settingsRepository.findFirst({ + where: { + instanceId: instanceId, + }, + }); + + if (data.expire === undefined || data.expire === null) data.expire = defaultSettingCheck.expire; + if (data.keywordFinish === undefined || data.keywordFinish === null) + data.keywordFinish = defaultSettingCheck.keywordFinish; + if (data.delayMessage === undefined || data.delayMessage === null) + data.delayMessage = defaultSettingCheck.delayMessage; + if (data.unknownMessage === undefined || data.unknownMessage === null) + data.unknownMessage = defaultSettingCheck.unknownMessage; + if (data.listeningFromMe === undefined || data.listeningFromMe === null) + data.listeningFromMe = defaultSettingCheck.listeningFromMe; + if (data.stopBotFromMe === undefined || data.stopBotFromMe === null) + data.stopBotFromMe = defaultSettingCheck.stopBotFromMe; + if (data.keepOpen === undefined || data.keepOpen === null) data.keepOpen = defaultSettingCheck.keepOpen; + if (data.debounceTime === undefined || data.debounceTime === null) + data.debounceTime = defaultSettingCheck.debounceTime; + if (data.ignoreJids === undefined || data.ignoreJids === null) data.ignoreJids = defaultSettingCheck.ignoreJids; + if (data.splitMessages === undefined || data.splitMessages === null) + data.splitMessages = defaultSettingCheck?.splitMessages ?? false; + if (data.timePerChar === undefined || data.timePerChar === null) + data.timePerChar = defaultSettingCheck?.timePerChar ?? 0; + + if (!defaultSettingCheck) { + await this.settings(instance, { + expire: data.expire, + keywordFinish: data.keywordFinish, + delayMessage: data.delayMessage, + unknownMessage: data.unknownMessage, + listeningFromMe: data.listeningFromMe, + stopBotFromMe: data.stopBotFromMe, + keepOpen: data.keepOpen, + debounceTime: data.debounceTime, + ignoreJids: data.ignoreJids, + splitMessages: data.splitMessages, + timePerChar: data.timePerChar, + }); + } + } + + const checkTriggerAll = await this.botRepository.findFirst({ + where: { + enabled: true, + triggerType: 'all', + instanceId: instanceId, + }, + }); + + if (checkTriggerAll && data.triggerType === 'all') { + throw new Error('You already have a Flowise with an "All" trigger, you cannot have more bots while it is active'); + } + + const checkDuplicate = await this.botRepository.findFirst({ + where: { + instanceId: instanceId, + apiUrl: data.apiUrl, + apiKey: data.apiKey, + }, + }); + + if (checkDuplicate) { + throw new Error('Flowise already exists'); + } + + if (data.triggerType === 'keyword') { + if (!data.triggerOperator || !data.triggerValue) { + throw new Error('Trigger operator and value are required'); + } + + const checkDuplicate = await this.botRepository.findFirst({ + where: { + triggerOperator: data.triggerOperator, + triggerValue: data.triggerValue, + instanceId: instanceId, + }, + }); + + if (checkDuplicate) { + throw new Error('Trigger already exists'); + } + } + + if (data.triggerType === 'advanced') { + if (!data.triggerValue) { + throw new Error('Trigger value is required'); + } + + const checkDuplicate = await this.botRepository.findFirst({ + where: { + triggerValue: data.triggerValue, + instanceId: instanceId, + }, + }); + + if (checkDuplicate) { + throw new Error('Trigger already exists'); + } + } + + try { + const bot = await this.botRepository.create({ + data: { + enabled: data?.enabled, + description: data.description, + apiUrl: data.apiUrl, + apiKey: data.apiKey, + expire: data.expire, + keywordFinish: data.keywordFinish, + delayMessage: data.delayMessage, + unknownMessage: data.unknownMessage, + listeningFromMe: data.listeningFromMe, + stopBotFromMe: data.stopBotFromMe, + keepOpen: data.keepOpen, + debounceTime: data.debounceTime, + instanceId: instanceId, + triggerType: data.triggerType, + triggerOperator: data.triggerOperator, + triggerValue: data.triggerValue, + ignoreJids: data.ignoreJids, + splitMessages: data.splitMessages, + timePerChar: data.timePerChar, + }, + }); + + return bot; + } catch (error) { + this.logger.error(error); + throw new Error('Error creating bot'); + } + } + + public async findBot(instance: InstanceDto) { + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const bots = await this.botRepository.findMany({ + where: { + instanceId: instanceId, + }, + }); + + if (!bots.length) { + return null; + } + + return bots; + } + + public async fetchBot(instance: InstanceDto, botId: string) { + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const bot = await this.botRepository.findFirst({ + where: { + id: botId, + }, + }); + + if (!bot) { + throw new Error('Bot not found'); + } + + if (bot.instanceId !== instanceId) { + throw new Error('Bot not found'); + } + + return bot; + } + + public async updateBot(instance: InstanceDto, botId: string, data: FlowiseDto) { + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const bot = await this.botRepository.findFirst({ + where: { + id: botId, + }, + }); + + if (!bot) { + throw new Error('Bot not found'); + } + + if (bot.instanceId !== instanceId) { + throw new Error('Bot not found'); + } + + if (data.triggerType === 'all') { + const checkTriggerAll = await this.botRepository.findFirst({ + where: { + enabled: true, + triggerType: 'all', + id: { + not: botId, + }, + instanceId: instanceId, + }, + }); + + if (checkTriggerAll) { + throw new Error('You already have a bot with an "All" trigger, you cannot have more bots while it is active'); + } + } + + const checkDuplicate = await this.botRepository.findFirst({ + where: { + id: { + not: botId, + }, + instanceId: instanceId, + apiUrl: data.apiUrl, + apiKey: data.apiKey, + }, + }); + + if (checkDuplicate) { + throw new Error('Bot already exists'); + } + + if (data.triggerType === 'keyword') { + if (!data.triggerOperator || !data.triggerValue) { + throw new Error('Trigger operator and value are required'); + } + + const checkDuplicate = await this.botRepository.findFirst({ + where: { + triggerOperator: data.triggerOperator, + triggerValue: data.triggerValue, + id: { not: botId }, + instanceId: instanceId, + }, + }); + + if (checkDuplicate) { + throw new Error('Trigger already exists'); + } + } + + if (data.triggerType === 'advanced') { + if (!data.triggerValue) { + throw new Error('Trigger value is required'); + } + + const checkDuplicate = await this.botRepository.findFirst({ + where: { + triggerValue: data.triggerValue, + id: { not: botId }, + instanceId: instanceId, + }, + }); + + if (checkDuplicate) { + throw new Error('Trigger already exists'); + } + } + + try { + const bot = await this.botRepository.update({ + where: { + id: botId, + }, + data: { + enabled: data?.enabled, + description: data.description, + apiUrl: data.apiUrl, + apiKey: data.apiKey, + expire: data.expire, + keywordFinish: data.keywordFinish, + delayMessage: data.delayMessage, + unknownMessage: data.unknownMessage, + listeningFromMe: data.listeningFromMe, + stopBotFromMe: data.stopBotFromMe, + keepOpen: data.keepOpen, + debounceTime: data.debounceTime, + instanceId: instanceId, + triggerType: data.triggerType, + triggerOperator: data.triggerOperator, + triggerValue: data.triggerValue, + ignoreJids: data.ignoreJids, + splitMessages: data.splitMessages, + timePerChar: data.timePerChar, + }, + }); + + return bot; + } catch (error) { + this.logger.error(error); + throw new Error('Error updating bot'); + } + } + + public async deleteBot(instance: InstanceDto, botId: string) { + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const bot = await this.botRepository.findFirst({ + where: { + id: botId, + }, + }); + + if (!bot) { + throw new Error('Bot not found'); + } + + if (bot.instanceId !== instanceId) { + throw new Error('Bot not found'); + } + try { + await this.prismaRepository.integrationSession.deleteMany({ + where: { + botId: botId, + }, + }); + + await this.botRepository.delete({ + where: { + id: botId, + }, + }); + + return { bot: { id: botId } }; + } catch (error) { + this.logger.error(error); + throw new Error('Error deleting bot'); + } + } + + // Settings + public async settings(instance: InstanceDto, data: any) { + try { + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const settings = await this.settingsRepository.findFirst({ + where: { + instanceId: instanceId, + }, + }); + + if (settings) { + const updateSettings = await this.settingsRepository.update({ + where: { + id: settings.id, + }, + data: { + expire: data.expire, + keywordFinish: data.keywordFinish, + delayMessage: data.delayMessage, + unknownMessage: data.unknownMessage, + listeningFromMe: data.listeningFromMe, + stopBotFromMe: data.stopBotFromMe, + keepOpen: data.keepOpen, + debounceTime: data.debounceTime, + flowiseIdFallback: data.flowiseIdFallback, + ignoreJids: data.ignoreJids, + splitMessages: data.splitMessages, + timePerChar: data.timePerChar, + }, + }); + + return { + expire: updateSettings.expire, + keywordFinish: updateSettings.keywordFinish, + delayMessage: updateSettings.delayMessage, + unknownMessage: updateSettings.unknownMessage, + listeningFromMe: updateSettings.listeningFromMe, + stopBotFromMe: updateSettings.stopBotFromMe, + keepOpen: updateSettings.keepOpen, + debounceTime: updateSettings.debounceTime, + flowiseIdFallback: updateSettings.flowiseIdFallback, + ignoreJids: updateSettings.ignoreJids, + splitMessages: updateSettings.splitMessages, + timePerChar: updateSettings.timePerChar, + }; + } + + const newSetttings = await this.settingsRepository.create({ + data: { + expire: data.expire, + keywordFinish: data.keywordFinish, + delayMessage: data.delayMessage, + unknownMessage: data.unknownMessage, + listeningFromMe: data.listeningFromMe, + stopBotFromMe: data.stopBotFromMe, + keepOpen: data.keepOpen, + debounceTime: data.debounceTime, + flowiseIdFallback: data.flowiseIdFallback, + ignoreJids: data.ignoreJids, + instanceId: instanceId, + splitMessages: data.splitMessages, + timePerChar: data.timePerChar, + }, + }); + + return { + expire: newSetttings.expire, + keywordFinish: newSetttings.keywordFinish, + delayMessage: newSetttings.delayMessage, + unknownMessage: newSetttings.unknownMessage, + listeningFromMe: newSetttings.listeningFromMe, + stopBotFromMe: newSetttings.stopBotFromMe, + keepOpen: newSetttings.keepOpen, + debounceTime: newSetttings.debounceTime, + flowiseIdFallback: newSetttings.flowiseIdFallback, + ignoreJids: newSetttings.ignoreJids, + splitMessages: newSetttings.splitMessages, + timePerChar: newSetttings.timePerChar, + }; + } catch (error) { + this.logger.error(error); + throw new Error('Error setting default settings'); + } + } + + public async fetchSettings(instance: InstanceDto) { + try { + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const settings = await this.settingsRepository.findFirst({ + where: { + instanceId: instanceId, + }, + include: { + Fallback: true, + }, + }); + + if (!settings) { + return { + expire: 0, + keywordFinish: '', + delayMessage: 0, + unknownMessage: '', + listeningFromMe: false, + stopBotFromMe: false, + keepOpen: false, + ignoreJids: [], + splitMessages: false, + timePerChar: 0, + flowiseIdFallback: '', + fallback: null, + }; + } + + return { + expire: settings.expire, + keywordFinish: settings.keywordFinish, + delayMessage: settings.delayMessage, + unknownMessage: settings.unknownMessage, + listeningFromMe: settings.listeningFromMe, + stopBotFromMe: settings.stopBotFromMe, + keepOpen: settings.keepOpen, + ignoreJids: settings.ignoreJids, + splitMessages: settings.splitMessages, + timePerChar: settings.timePerChar, + flowiseIdFallback: settings.flowiseIdFallback, + fallback: settings.Fallback, + }; + } catch (error) { + this.logger.error(error); + throw new Error('Error fetching default settings'); + } + } + + // Sessions + public async changeStatus(instance: InstanceDto, data: any) { + try { + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const defaultSettingCheck = await this.settingsRepository.findFirst({ + where: { + instanceId, + }, + }); + + const remoteJid = data.remoteJid; + const status = data.status; + + if (status === 'delete') { + await this.sessionRepository.deleteMany({ + where: { + remoteJid: remoteJid, + botId: { not: null }, + }, + }); + + return { bot: { remoteJid: remoteJid, status: status } }; + } + + if (status === 'closed') { + if (defaultSettingCheck?.keepOpen) { + await this.sessionRepository.updateMany({ + where: { + remoteJid: remoteJid, + botId: { not: null }, + }, + data: { + status: 'closed', + }, + }); + } else { + await this.sessionRepository.deleteMany({ + where: { + remoteJid: remoteJid, + botId: { not: null }, + }, + }); + } + + return { bot: { ...instance, bot: { remoteJid: remoteJid, status: status } } }; + } else { + const session = await this.sessionRepository.updateMany({ + where: { + instanceId: instanceId, + remoteJid: remoteJid, + botId: { not: null }, + }, + data: { + status: status, + }, + }); + + const botData = { + remoteJid: remoteJid, + status: status, + session, + }; + + return { bot: { ...instance, bot: botData } }; + } + } catch (error) { + this.logger.error(error); + throw new Error('Error changing status'); + } + } + + public async fetchSessions(instance: InstanceDto, botId: string, remoteJid?: string) { + try { + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const bot = await this.botRepository.findFirst({ + where: { + id: botId, + }, + }); + + if (bot && bot.instanceId !== instanceId) { + throw new Error('Dify not found'); + } + + return await this.sessionRepository.findMany({ + where: { + instanceId: instanceId, + remoteJid, + botId: bot ? botId : { not: null }, + type: 'flowise', + }, + }); + } catch (error) { + this.logger.error(error); + throw new Error('Error fetching sessions'); + } + } + + public async ignoreJid(instance: InstanceDto, data: IgnoreJidDto) { + try { + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const settings = await this.settingsRepository.findFirst({ + where: { + instanceId: instanceId, + }, + }); + + if (!settings) { + throw new Error('Settings not found'); + } + + let ignoreJids: any = settings?.ignoreJids || []; + + if (data.action === 'add') { + if (ignoreJids.includes(data.remoteJid)) return { ignoreJids: ignoreJids }; + + ignoreJids.push(data.remoteJid); + } else { + ignoreJids = ignoreJids.filter((jid) => jid !== data.remoteJid); + } + + const updateSettings = await this.settingsRepository.update({ + where: { + id: settings.id, + }, + data: { + ignoreJids: ignoreJids, + }, + }); + + return { + ignoreJids: updateSettings.ignoreJids, + }; + } catch (error) { + this.logger.error(error); + throw new Error('Error setting default settings'); + } + } + + // Emit + public async emit({ instance, remoteJid, msg }: EmitData) { + try { + const settings = await this.settingsRepository.findFirst({ + where: { + instanceId: instance.instanceId, + }, + }); + + if (this.checkIgnoreJids(settings?.ignoreJids, remoteJid)) return; + + const session = await this.getSession(remoteJid, instance); + + const content = getConversationMessage(msg); + + let findBot = (await this.findBotTrigger(this.botRepository, content, instance, session)) as Flowise; + + if (!findBot) { + const fallback = await this.settingsRepository.findFirst({ + where: { + instanceId: instance.instanceId, + }, + }); + + if (fallback?.flowiseIdFallback) { + const findFallback = await this.botRepository.findFirst({ + where: { + id: fallback.flowiseIdFallback, + }, + }); + + findBot = findFallback; + } else { + return; + } + } + + let expire = findBot?.expire; + let keywordFinish = findBot?.keywordFinish; + let delayMessage = findBot?.delayMessage; + let unknownMessage = findBot?.unknownMessage; + let listeningFromMe = findBot?.listeningFromMe; + let stopBotFromMe = findBot?.stopBotFromMe; + let keepOpen = findBot?.keepOpen; + let debounceTime = findBot?.debounceTime; + let ignoreJids = findBot?.ignoreJids; + let splitMessages = findBot?.splitMessages; + let timePerChar = findBot?.timePerChar; + + if (expire === undefined || expire === null) expire = settings.expire; + if (keywordFinish === undefined || keywordFinish === null) keywordFinish = settings.keywordFinish; + if (delayMessage === undefined || delayMessage === null) delayMessage = settings.delayMessage; + if (unknownMessage === undefined || unknownMessage === null) unknownMessage = settings.unknownMessage; + if (listeningFromMe === undefined || listeningFromMe === null) listeningFromMe = settings.listeningFromMe; + if (stopBotFromMe === undefined || stopBotFromMe === null) stopBotFromMe = settings.stopBotFromMe; + if (keepOpen === undefined || keepOpen === null) keepOpen = settings.keepOpen; + if (debounceTime === undefined || debounceTime === null) debounceTime = settings.debounceTime; + if (ignoreJids === undefined || ignoreJids === null) ignoreJids = settings.ignoreJids; + if (splitMessages === undefined || splitMessages === null) splitMessages = settings?.splitMessages ?? false; + if (timePerChar === undefined || timePerChar === null) timePerChar = settings?.timePerChar ?? 0; + + const key = msg.key as { + id: string; + remoteJid: string; + fromMe: boolean; + participant: string; + }; + + if (stopBotFromMe && key.fromMe && session) { + await this.prismaRepository.integrationSession.update({ + where: { + id: session.id, + }, + data: { + status: 'paused', + }, + }); + return; + } + + if (!listeningFromMe && key.fromMe) { + return; + } + + if (session && !session.awaitUser) { + return; + } + + if (debounceTime && debounceTime > 0) { + this.processDebounce(this.userMessageDebounce, content, remoteJid, debounceTime, async (debouncedContent) => { + await this.flowiseService.processBot( + this.waMonitor.waInstances[instance.instanceName], + remoteJid, + findBot, + session, + { + ...settings, + expire, + keywordFinish, + delayMessage, + unknownMessage, + listeningFromMe, + stopBotFromMe, + keepOpen, + debounceTime, + ignoreJids, + splitMessages, + timePerChar, + }, + debouncedContent, + msg?.pushName, + ); + }); + } else { + await this.flowiseService.processBot( + this.waMonitor.waInstances[instance.instanceName], + remoteJid, + findBot, + session, + { + ...settings, + expire, + keywordFinish, + delayMessage, + unknownMessage, + listeningFromMe, + stopBotFromMe, + keepOpen, + debounceTime, + ignoreJids, + splitMessages, + timePerChar, + }, + content, + msg?.pushName, + ); + } + + return; + } catch (error) { + this.logger.error(error); + return; + } + } +} diff --git a/src/api/integrations/chatbot/flowise/dto/flowise.dto.ts b/src/api/integrations/chatbot/flowise/dto/flowise.dto.ts new file mode 100644 index 00000000..98e612ad --- /dev/null +++ b/src/api/integrations/chatbot/flowise/dto/flowise.dto.ts @@ -0,0 +1,37 @@ +import { TriggerOperator, TriggerType } from '@prisma/client'; + +export class FlowiseDto { + enabled?: boolean; + description?: string; + apiUrl?: string; + apiKey?: string; + expire?: number; + keywordFinish?: string; + delayMessage?: number; + unknownMessage?: string; + listeningFromMe?: boolean; + stopBotFromMe?: boolean; + keepOpen?: boolean; + debounceTime?: number; + triggerType?: TriggerType; + triggerOperator?: TriggerOperator; + triggerValue?: string; + ignoreJids?: any; + splitMessages?: boolean; + timePerChar?: number; +} + +export class FlowiseSettingDto { + expire?: number; + keywordFinish?: string; + delayMessage?: number; + unknownMessage?: string; + listeningFromMe?: boolean; + stopBotFromMe?: boolean; + keepOpen?: boolean; + debounceTime?: number; + flowiseIdFallback?: string; + ignoreJids?: any; + splitMessages?: boolean; + timePerChar?: number; +} diff --git a/src/api/integrations/chatbot/flowise/routes/flowise.router.ts b/src/api/integrations/chatbot/flowise/routes/flowise.router.ts new file mode 100644 index 00000000..3527f7ce --- /dev/null +++ b/src/api/integrations/chatbot/flowise/routes/flowise.router.ts @@ -0,0 +1,124 @@ +import { RouterBroker } from '@api/abstract/abstract.router'; +import { IgnoreJidDto } from '@api/dto/chatbot.dto'; +import { InstanceDto } from '@api/dto/instance.dto'; +import { HttpStatus } from '@api/routes/index.router'; +import { flowiseController } from '@api/server.module'; +import { instanceSchema } from '@validate/instance.schema'; +import { RequestHandler, Router } from 'express'; + +import { FlowiseDto, FlowiseSettingDto } from '../dto/flowise.dto'; +import { + flowiseIgnoreJidSchema, + flowiseSchema, + flowiseSettingSchema, + flowiseStatusSchema, +} from '../validate/flowise.schema'; + +export class FlowiseRouter extends RouterBroker { + constructor(...guards: RequestHandler[]) { + super(); + this.router + .post(this.routerPath('create'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: flowiseSchema, + ClassRef: FlowiseDto, + execute: (instance, data) => flowiseController.createBot(instance, data), + }); + + res.status(HttpStatus.CREATED).json(response); + }) + .get(this.routerPath('find'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => flowiseController.findBot(instance), + }); + + res.status(HttpStatus.OK).json(response); + }) + .get(this.routerPath('fetch/:flowiseId'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => flowiseController.fetchBot(instance, req.params.flowiseId), + }); + + res.status(HttpStatus.OK).json(response); + }) + .put(this.routerPath('update/:flowiseId'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: flowiseSchema, + ClassRef: FlowiseDto, + execute: (instance, data) => flowiseController.updateBot(instance, req.params.flowiseId, data), + }); + + res.status(HttpStatus.OK).json(response); + }) + .delete(this.routerPath('delete/:flowiseId'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => flowiseController.deleteBot(instance, req.params.flowiseId), + }); + + res.status(HttpStatus.OK).json(response); + }) + .post(this.routerPath('settings'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: flowiseSettingSchema, + ClassRef: FlowiseSettingDto, + execute: (instance, data) => flowiseController.settings(instance, data), + }); + + res.status(HttpStatus.OK).json(response); + }) + .get(this.routerPath('fetchSettings'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => flowiseController.fetchSettings(instance), + }); + + res.status(HttpStatus.OK).json(response); + }) + .post(this.routerPath('changeStatus'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: flowiseStatusSchema, + ClassRef: InstanceDto, + execute: (instance, data) => flowiseController.changeStatus(instance, data), + }); + + res.status(HttpStatus.OK).json(response); + }) + .get(this.routerPath('fetchSessions/:flowiseId'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => flowiseController.fetchSessions(instance, req.params.flowiseId), + }); + + res.status(HttpStatus.OK).json(response); + }) + .post(this.routerPath('ignoreJid'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: flowiseIgnoreJidSchema, + ClassRef: IgnoreJidDto, + execute: (instance, data) => flowiseController.ignoreJid(instance, data), + }); + + res.status(HttpStatus.OK).json(response); + }); + } + + public readonly router: Router = Router(); +} diff --git a/src/api/integrations/chatbot/flowise/services/flowise.service.ts b/src/api/integrations/chatbot/flowise/services/flowise.service.ts new file mode 100644 index 00000000..6e4cdbd5 --- /dev/null +++ b/src/api/integrations/chatbot/flowise/services/flowise.service.ts @@ -0,0 +1,425 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import { InstanceDto } from '@api/dto/instance.dto'; +import { PrismaRepository } from '@api/repository/repository.service'; +import { WAMonitoringService } from '@api/services/monitor.service'; +import { Integration } from '@api/types/wa.types'; +import { Auth, ConfigService, HttpServer } from '@config/env.config'; +import { Logger } from '@config/logger.config'; +import { Flowise, FlowiseSetting, IntegrationSession } from '@prisma/client'; +import { sendTelemetry } from '@utils/sendTelemetry'; +import axios from 'axios'; + +export class FlowiseService { + constructor( + private readonly waMonitor: WAMonitoringService, + private readonly configService: ConfigService, + private readonly prismaRepository: PrismaRepository, + ) {} + + private readonly logger = new Logger('FlowiseService'); + + public async createNewSession(instance: InstanceDto, data: any) { + try { + const session = await this.prismaRepository.integrationSession.create({ + data: { + remoteJid: data.remoteJid, + pushName: data.pushName, + sessionId: data.remoteJid, + status: 'opened', + awaitUser: false, + botId: data.botId, + instanceId: instance.instanceId, + type: 'flowise', + }, + }); + + return { session }; + } catch (error) { + this.logger.error(error); + return; + } + } + + private isImageMessage(content: string) { + return content.includes('imageMessage'); + } + + private async sendMessageToBot(instance: any, bot: Flowise, remoteJid: string, pushName: string, content: string) { + const payload: any = { + question: content, + overrideConfig: { + sessionId: remoteJid, + vars: { + remoteJid: remoteJid, + pushName: pushName, + instanceName: instance.instanceName, + serverUrl: this.configService.get('SERVER').URL, + apiKey: this.configService.get('AUTHENTICATION').API_KEY.KEY, + }, + }, + }; + + if (this.isImageMessage(content)) { + const contentSplit = content.split('|'); + + payload.uploads = [ + { + data: contentSplit[1].split('?')[0], + type: 'url', + name: 'Flowise.png', + mime: 'image/png', + }, + ]; + payload.question = contentSplit[2] || content; + } + + if (instance.integration === Integration.WHATSAPP_BAILEYS) { + await instance.client.presenceSubscribe(remoteJid); + await instance.client.sendPresenceUpdate('composing', remoteJid); + } + + let headers: any = { + 'Content-Type': 'application/json', + }; + + if (bot.apiKey) { + headers = { + ...headers, + Authorization: `Bearer ${bot.apiKey}`, + }; + } + + const endpoint = bot.apiUrl; + + if (!endpoint) return null; + + const response = await axios.post(endpoint, payload, { + headers, + }); + + if (instance.integration === Integration.WHATSAPP_BAILEYS) + await instance.client.sendPresenceUpdate('paused', remoteJid); + + const message = response?.data?.text; + + return message; + } + + private async sendMessageWhatsApp( + instance: any, + remoteJid: string, + session: IntegrationSession, + settings: FlowiseSetting, + message: string, + ) { + const linkRegex = /(!?)\[(.*?)\]\((.*?)\)/g; + + let textBuffer = ''; + let lastIndex = 0; + + let match: RegExpExecArray | null; + + const getMediaType = (url: string): string | null => { + const extension = url.split('.').pop()?.toLowerCase(); + const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']; + const audioExtensions = ['mp3', 'wav', 'aac', 'ogg']; + const videoExtensions = ['mp4', 'avi', 'mkv', 'mov']; + const documentExtensions = ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt']; + + if (imageExtensions.includes(extension || '')) return 'image'; + if (audioExtensions.includes(extension || '')) return 'audio'; + if (videoExtensions.includes(extension || '')) return 'video'; + if (documentExtensions.includes(extension || '')) return 'document'; + return null; + }; + + while ((match = linkRegex.exec(message)) !== null) { + const [fullMatch, exclMark, altText, url] = match; + const mediaType = getMediaType(url); + + const beforeText = message.slice(lastIndex, match.index); + if (beforeText) { + textBuffer += beforeText; + } + + if (mediaType) { + const splitMessages = settings.splitMessages ?? false; + const timePerChar = settings.timePerChar ?? 0; + const minDelay = 1000; + const maxDelay = 20000; + + if (textBuffer.trim()) { + if (splitMessages) { + const multipleMessages = textBuffer.trim().split('\n\n'); + + for (let index = 0; index < multipleMessages.length; index++) { + const message = multipleMessages[index]; + + const delay = Math.min(Math.max(message.length * timePerChar, minDelay), maxDelay); + + if (instance.integration === Integration.WHATSAPP_BAILEYS) { + await instance.client.presenceSubscribe(remoteJid); + await instance.client.sendPresenceUpdate('composing', remoteJid); + } + + await new Promise((resolve) => { + setTimeout(async () => { + await instance.textMessage( + { + number: remoteJid.split('@')[0], + delay: settings?.delayMessage || 1000, + text: message, + }, + false, + ); + resolve(); + }, delay); + }); + + if (instance.integration === Integration.WHATSAPP_BAILEYS) { + await instance.client.sendPresenceUpdate('paused', remoteJid); + } + } + } else { + await instance.textMessage( + { + number: remoteJid.split('@')[0], + delay: settings?.delayMessage || 1000, + text: textBuffer.trim(), + }, + false, + ); + } + textBuffer = ''; + } + + if (mediaType === 'audio') { + await instance.audioWhatsapp({ + number: remoteJid.split('@')[0], + delay: settings?.delayMessage || 1000, + audio: url, + caption: altText, + }); + } else { + await instance.mediaMessage( + { + number: remoteJid.split('@')[0], + delay: settings?.delayMessage || 1000, + mediatype: mediaType, + media: url, + caption: altText, + }, + null, + false, + ); + } + } else { + textBuffer += `[${altText}](${url})`; + } + + lastIndex = linkRegex.lastIndex; + } + + if (lastIndex < message.length) { + const remainingText = message.slice(lastIndex); + if (remainingText.trim()) { + textBuffer += remainingText; + } + } + + const splitMessages = settings.splitMessages ?? false; + const timePerChar = settings.timePerChar ?? 0; + const minDelay = 1000; + const maxDelay = 20000; + + if (textBuffer.trim()) { + if (splitMessages) { + const multipleMessages = textBuffer.trim().split('\n\n'); + + for (let index = 0; index < multipleMessages.length; index++) { + const message = multipleMessages[index]; + + const delay = Math.min(Math.max(message.length * timePerChar, minDelay), maxDelay); + + if (instance.integration === Integration.WHATSAPP_BAILEYS) { + await instance.client.presenceSubscribe(remoteJid); + await instance.client.sendPresenceUpdate('composing', remoteJid); + } + + await new Promise((resolve) => { + setTimeout(async () => { + await instance.textMessage( + { + number: remoteJid.split('@')[0], + delay: settings?.delayMessage || 1000, + text: message, + }, + false, + ); + resolve(); + }, delay); + }); + + if (instance.integration === Integration.WHATSAPP_BAILEYS) { + await instance.client.sendPresenceUpdate('paused', remoteJid); + } + } + } else { + await instance.textMessage( + { + number: remoteJid.split('@')[0], + delay: settings?.delayMessage || 1000, + text: textBuffer.trim(), + }, + false, + ); + } + textBuffer = ''; + } + + sendTelemetry('/message/sendText'); + + await this.prismaRepository.integrationSession.update({ + where: { + id: session.id, + }, + data: { + status: 'opened', + awaitUser: true, + }, + }); + + return; + } + + private async initNewSession( + instance: any, + remoteJid: string, + bot: Flowise, + settings: FlowiseSetting, + session: IntegrationSession, + content: string, + pushName?: string, + ) { + const data = await this.createNewSession(instance, { + remoteJid, + pushName, + botId: bot.id, + }); + + if (data.session) { + session = data.session; + } + + const message = await this.sendMessageToBot(instance, bot, remoteJid, pushName, content); + + await this.sendMessageWhatsApp(instance, remoteJid, session, settings, message); + + return; + } + + public async processBot( + instance: any, + remoteJid: string, + bot: Flowise, + session: IntegrationSession, + settings: FlowiseSetting, + content: string, + pushName?: string, + ) { + if (session && session.status !== 'opened') { + return; + } + + if (session && settings.expire && settings.expire > 0) { + const now = Date.now(); + + const sessionUpdatedAt = new Date(session.updatedAt).getTime(); + + const diff = now - sessionUpdatedAt; + + const diffInMinutes = Math.floor(diff / 1000 / 60); + + if (diffInMinutes > settings.expire) { + if (settings.keepOpen) { + await this.prismaRepository.integrationSession.update({ + where: { + id: session.id, + }, + data: { + status: 'closed', + }, + }); + } else { + await this.prismaRepository.integrationSession.deleteMany({ + where: { + botId: bot.id, + remoteJid: remoteJid, + }, + }); + } + + await this.initNewSession(instance, remoteJid, bot, settings, session, content, pushName); + return; + } + } + + if (!session) { + await this.initNewSession(instance, remoteJid, bot, settings, session, content, pushName); + return; + } + + await this.prismaRepository.integrationSession.update({ + where: { + id: session.id, + }, + data: { + status: 'opened', + awaitUser: false, + }, + }); + + if (!content) { + if (settings.unknownMessage) { + this.waMonitor.waInstances[instance.instanceName].textMessage( + { + number: remoteJid.split('@')[0], + delay: settings.delayMessage || 1000, + text: settings.unknownMessage, + }, + false, + ); + + sendTelemetry('/message/sendText'); + } + return; + } + + if (settings.keywordFinish && content.toLowerCase() === settings.keywordFinish.toLowerCase()) { + if (settings.keepOpen) { + await this.prismaRepository.integrationSession.update({ + where: { + id: session.id, + }, + data: { + status: 'closed', + }, + }); + } else { + await this.prismaRepository.integrationSession.deleteMany({ + where: { + botId: bot.id, + remoteJid: remoteJid, + }, + }); + } + return; + } + + const message = await this.sendMessageToBot(instance, bot, remoteJid, pushName, content); + + await this.sendMessageWhatsApp(instance, remoteJid, session, settings, message); + + return; + } +} diff --git a/src/api/integrations/chatbot/flowise/validate/flowise.schema.ts b/src/api/integrations/chatbot/flowise/validate/flowise.schema.ts new file mode 100644 index 00000000..83f9d1ea --- /dev/null +++ b/src/api/integrations/chatbot/flowise/validate/flowise.schema.ts @@ -0,0 +1,107 @@ +import { JSONSchema7 } from 'json-schema'; +import { v4 } from 'uuid'; + +const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => { + const properties = {}; + propertyNames.forEach( + (property) => + (properties[property] = { + minLength: 1, + description: `The "${property}" cannot be empty`, + }), + ); + return { + if: { + propertyNames: { + enum: [...propertyNames], + }, + }, + then: { properties }, + }; +}; + +export const flowiseSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + enabled: { type: 'boolean' }, + description: { type: 'string' }, + apiUrl: { type: 'string' }, + apiKey: { type: 'string' }, + triggerType: { type: 'string', enum: ['all', 'keyword', 'none', 'advanced'] }, + triggerOperator: { type: 'string', enum: ['equals', 'contains', 'startsWith', 'endsWith', 'regex'] }, + triggerValue: { type: 'string' }, + expire: { type: 'integer' }, + keywordFinish: { type: 'string' }, + delayMessage: { type: 'integer' }, + unknownMessage: { type: 'string' }, + listeningFromMe: { type: 'boolean' }, + stopBotFromMe: { type: 'boolean' }, + keepOpen: { type: 'boolean' }, + debounceTime: { type: 'integer' }, + ignoreJids: { type: 'array', items: { type: 'string' } }, + }, + required: ['enabled', 'apiUrl', 'triggerType'], + ...isNotEmpty('enabled', 'apiUrl', 'triggerType'), +}; + +export const flowiseStatusSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + remoteJid: { type: 'string' }, + status: { type: 'string', enum: ['opened', 'closed', 'paused', 'delete'] }, + }, + required: ['remoteJid', 'status'], + ...isNotEmpty('remoteJid', 'status'), +}; + +export const flowiseSettingSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + expire: { type: 'integer' }, + keywordFinish: { type: 'string' }, + delayMessage: { type: 'integer' }, + unknownMessage: { type: 'string' }, + listeningFromMe: { type: 'boolean' }, + stopBotFromMe: { type: 'boolean' }, + keepOpen: { type: 'boolean' }, + debounceTime: { type: 'integer' }, + ignoreJids: { type: 'array', items: { type: 'string' } }, + botIdFallback: { type: 'string' }, + }, + required: [ + 'expire', + 'keywordFinish', + 'delayMessage', + 'unknownMessage', + 'listeningFromMe', + 'stopBotFromMe', + 'keepOpen', + 'debounceTime', + 'ignoreJids', + ], + ...isNotEmpty( + 'expire', + 'keywordFinish', + 'delayMessage', + 'unknownMessage', + 'listeningFromMe', + 'stopBotFromMe', + 'keepOpen', + 'debounceTime', + 'ignoreJids', + ), +}; + +export const flowiseIgnoreJidSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + remoteJid: { type: 'string' }, + action: { type: 'string', enum: ['add', 'remove'] }, + }, + required: ['remoteJid', 'action'], + ...isNotEmpty('remoteJid', 'action'), +}; diff --git a/src/api/integrations/chatbot/openai/controllers/openai.controller.ts b/src/api/integrations/chatbot/openai/controllers/openai.controller.ts new file mode 100644 index 00000000..4bb2bcdb --- /dev/null +++ b/src/api/integrations/chatbot/openai/controllers/openai.controller.ts @@ -0,0 +1,1126 @@ +import { IgnoreJidDto } from '@api/dto/chatbot.dto'; +import { InstanceDto } from '@api/dto/instance.dto'; +import { OpenaiCredsDto, OpenaiDto } from '@api/integrations/chatbot/openai/dto/openai.dto'; +import { OpenaiService } from '@api/integrations/chatbot/openai/services/openai.service'; +import { PrismaRepository } from '@api/repository/repository.service'; +import { WAMonitoringService } from '@api/services/monitor.service'; +import { configService, Openai } from '@config/env.config'; +import { Logger } from '@config/logger.config'; +import { BadRequestException } from '@exceptions'; +import { OpenaiBot } from '@prisma/client'; +import { getConversationMessage } from '@utils/getConversationMessage'; +import OpenAI from 'openai'; + +import { ChatbotController, ChatbotControllerInterface, EmitData } from '../../chatbot.controller'; + +export class OpenaiController extends ChatbotController implements ChatbotControllerInterface { + constructor( + private readonly openaiService: OpenaiService, + prismaRepository: PrismaRepository, + waMonitor: WAMonitoringService, + ) { + super(prismaRepository, waMonitor); + + this.botRepository = this.prismaRepository.openaiBot; + this.settingsRepository = this.prismaRepository.openaiSetting; + this.sessionRepository = this.prismaRepository.integrationSession; + this.credsRepository = this.prismaRepository.openaiCreds; + } + + public readonly logger = new Logger('OpenaiController'); + + integrationEnabled = configService.get('OPENAI').ENABLED; + botRepository: any; + settingsRepository: any; + sessionRepository: any; + userMessageDebounce: { [key: string]: { message: string; timeoutId: NodeJS.Timeout } } = {}; + private client: OpenAI; + private credsRepository: any; + + // Credentials + public async createOpenaiCreds(instance: InstanceDto, data: OpenaiCredsDto) { + if (!this.integrationEnabled) throw new BadRequestException('Openai is disabled'); + + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + if (!data.apiKey) throw new Error('API Key is required'); + if (!data.name) throw new Error('Name is required'); + + try { + const creds = await this.credsRepository.create({ + data: { + name: data.name, + apiKey: data.apiKey, + instanceId: instanceId, + }, + }); + + return creds; + } catch (error) { + this.logger.error(error); + throw new Error('Error creating openai creds'); + } + } + + public async findOpenaiCreds(instance: InstanceDto) { + if (!this.integrationEnabled) throw new BadRequestException('Openai is disabled'); + + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const creds = await this.credsRepository.findMany({ + where: { + instanceId: instanceId, + }, + include: { + OpenaiAssistant: true, + }, + }); + + return creds; + } + + public async deleteCreds(instance: InstanceDto, openaiCredsId: string) { + if (!this.integrationEnabled) throw new BadRequestException('Openai is disabled'); + + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const creds = await this.credsRepository.findFirst({ + where: { + id: openaiCredsId, + }, + }); + + if (!creds) { + throw new Error('Openai Creds not found'); + } + + if (creds.instanceId !== instanceId) { + throw new Error('Openai Creds not found'); + } + + try { + await this.credsRepository.delete({ + where: { + id: openaiCredsId, + }, + }); + + return { openaiCreds: { id: openaiCredsId } }; + } catch (error) { + this.logger.error(error); + throw new Error('Error deleting openai creds'); + } + } + + // Models + public async getModels(instance: InstanceDto) { + if (!this.integrationEnabled) throw new BadRequestException('Openai is disabled'); + + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + if (!instanceId) throw new Error('Instance not found'); + + const defaultSettings = await this.settingsRepository.findFirst({ + where: { + instanceId: instanceId, + }, + include: { + OpenaiCreds: true, + }, + }); + + if (!defaultSettings) throw new Error('Settings not found'); + + const { apiKey } = defaultSettings.OpenaiCreds; + + try { + this.client = new OpenAI({ apiKey }); + + const models: any = await this.client.models.list(); + + return models?.body?.data; + } catch (error) { + this.logger.error(error); + throw new Error('Error fetching models'); + } + } + + // Bots + public async createBot(instance: InstanceDto, data: OpenaiDto) { + if (!this.integrationEnabled) throw new BadRequestException('Openai is disabled'); + + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + if ( + !data.openaiCredsId || + !data.expire || + !data.keywordFinish || + !data.delayMessage || + !data.unknownMessage || + !data.listeningFromMe || + !data.stopBotFromMe || + !data.keepOpen || + !data.debounceTime || + !data.ignoreJids || + !data.splitMessages || + !data.timePerChar + ) { + const defaultSettingCheck = await this.settingsRepository.findFirst({ + where: { + instanceId: instanceId, + }, + }); + + if (data.expire === undefined || data.expire === null) data.expire = defaultSettingCheck.expire; + if (data.keywordFinish === undefined || data.keywordFinish === null) + data.keywordFinish = defaultSettingCheck.keywordFinish; + if (data.delayMessage === undefined || data.delayMessage === null) + data.delayMessage = defaultSettingCheck.delayMessage; + if (data.unknownMessage === undefined || data.unknownMessage === null) + data.unknownMessage = defaultSettingCheck.unknownMessage; + if (data.listeningFromMe === undefined || data.listeningFromMe === null) + data.listeningFromMe = defaultSettingCheck.listeningFromMe; + if (data.stopBotFromMe === undefined || data.stopBotFromMe === null) + data.stopBotFromMe = defaultSettingCheck.stopBotFromMe; + if (data.keepOpen === undefined || data.keepOpen === null) data.keepOpen = defaultSettingCheck.keepOpen; + if (data.debounceTime === undefined || data.debounceTime === null) + data.debounceTime = defaultSettingCheck.debounceTime; + if (data.ignoreJids === undefined || data.ignoreJids === null) data.ignoreJids = defaultSettingCheck.ignoreJids; + if (data.splitMessages === undefined || data.splitMessages === null) + data.splitMessages = defaultSettingCheck?.splitMessages ?? false; + if (data.timePerChar === undefined || data.timePerChar === null) + data.timePerChar = defaultSettingCheck?.timePerChar ?? 0; + + if (!data.openaiCredsId) { + throw new Error('Openai Creds Id is required'); + } + + if (!defaultSettingCheck) { + await this.settings(instance, { + openaiCredsId: data.openaiCredsId, + expire: data.expire, + keywordFinish: data.keywordFinish, + delayMessage: data.delayMessage, + unknownMessage: data.unknownMessage, + listeningFromMe: data.listeningFromMe, + stopBotFromMe: data.stopBotFromMe, + keepOpen: data.keepOpen, + debounceTime: data.debounceTime, + ignoreJids: data.ignoreJids, + splitMessages: data.splitMessages, + timePerChar: data.timePerChar, + }); + } + } + + const checkTriggerAll = await this.botRepository.findFirst({ + where: { + enabled: true, + triggerType: 'all', + instanceId: instanceId, + }, + }); + + if (checkTriggerAll && data.triggerType === 'all') { + throw new Error('You already have a openai with an "All" trigger, you cannot have more bots while it is active'); + } + + let whereDuplication: any = { + instanceId: instanceId, + }; + + if (data.botType === 'assistant') { + if (!data.assistantId) throw new Error('Assistant ID is required'); + + whereDuplication = { + ...whereDuplication, + assistantId: data.assistantId, + botType: data.botType, + }; + } else if (data.botType === 'chatCompletion') { + if (!data.model) throw new Error('Model is required'); + if (!data.maxTokens) throw new Error('Max tokens is required'); + + whereDuplication = { + ...whereDuplication, + model: data.model, + maxTokens: data.maxTokens, + botType: data.botType, + }; + } else { + throw new Error('Bot type is required'); + } + + const checkDuplicate = await this.botRepository.findFirst({ + where: whereDuplication, + }); + + if (checkDuplicate) { + throw new Error('Openai Bot already exists'); + } + + if (data.triggerType === 'keyword') { + if (!data.triggerOperator || !data.triggerValue) { + throw new Error('Trigger operator and value are required'); + } + + const checkDuplicate = await this.botRepository.findFirst({ + where: { + triggerOperator: data.triggerOperator, + triggerValue: data.triggerValue, + instanceId: instanceId, + }, + }); + + if (checkDuplicate) { + throw new Error('Trigger already exists'); + } + } + + if (data.triggerType === 'advanced') { + if (!data.triggerValue) { + throw new Error('Trigger value is required'); + } + + const checkDuplicate = await this.botRepository.findFirst({ + where: { + triggerValue: data.triggerValue, + instanceId: instanceId, + }, + }); + + if (checkDuplicate) { + throw new Error('Trigger already exists'); + } + } + + try { + const bot = await this.botRepository.create({ + data: { + enabled: data?.enabled, + description: data.description, + openaiCredsId: data.openaiCredsId, + botType: data.botType, + assistantId: data.assistantId, + functionUrl: data.functionUrl, + model: data.model, + systemMessages: data.systemMessages, + assistantMessages: data.assistantMessages, + userMessages: data.userMessages, + maxTokens: data.maxTokens, + expire: data.expire, + keywordFinish: data.keywordFinish, + delayMessage: data.delayMessage, + unknownMessage: data.unknownMessage, + listeningFromMe: data.listeningFromMe, + stopBotFromMe: data.stopBotFromMe, + keepOpen: data.keepOpen, + debounceTime: data.debounceTime, + instanceId: instanceId, + triggerType: data.triggerType, + triggerOperator: data.triggerOperator, + triggerValue: data.triggerValue, + ignoreJids: data.ignoreJids, + splitMessages: data.splitMessages, + timePerChar: data.timePerChar, + }, + }); + + return bot; + } catch (error) { + this.logger.error(error); + throw new Error('Error creating openai bot'); + } + } + + public async findBot(instance: InstanceDto) { + if (!this.integrationEnabled) throw new BadRequestException('Openai is disabled'); + + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const bots = await this.botRepository.findMany({ + where: { + instanceId, + }, + }); + + if (!bots.length) { + return null; + } + + return bots; + } + + public async fetchBot(instance: InstanceDto, botId: string) { + if (!this.integrationEnabled) throw new BadRequestException('Openai is disabled'); + + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const bot = await this.botRepository.findFirst({ + where: { + id: botId, + }, + }); + + if (!bot) { + throw new Error('Openai Bot not found'); + } + + if (bot.instanceId !== instanceId) { + throw new Error('Openai Bot not found'); + } + + return bot; + } + + public async updateBot(instance: InstanceDto, botId: string, data: OpenaiDto) { + if (!this.integrationEnabled) throw new BadRequestException('Openai is disabled'); + + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const bot = await this.botRepository.findFirst({ + where: { + id: botId, + }, + }); + + if (!bot) { + throw new Error('Openai Bot not found'); + } + + if (bot.instanceId !== instanceId) { + throw new Error('Openai Bot not found'); + } + + if (data.triggerType === 'all') { + const checkTriggerAll = await this.botRepository.findFirst({ + where: { + enabled: true, + triggerType: 'all', + id: { + not: botId, + }, + instanceId: instanceId, + }, + }); + + if (checkTriggerAll) { + throw new Error( + 'You already have a openai bot with an "All" trigger, you cannot have more bots while it is active', + ); + } + } + + let whereDuplication: any = { + id: { + not: botId, + }, + instanceId: instanceId, + }; + + if (data.botType === 'assistant') { + if (!data.assistantId) throw new Error('Assistant ID is required'); + + whereDuplication = { + ...whereDuplication, + assistantId: data.assistantId, + }; + } else if (data.botType === 'chatCompletion') { + if (!data.model) throw new Error('Model is required'); + if (!data.maxTokens) throw new Error('Max tokens is required'); + + whereDuplication = { + ...whereDuplication, + model: data.model, + maxTokens: data.maxTokens, + }; + } else { + throw new Error('Bot type is required'); + } + + const checkDuplicate = await this.botRepository.findFirst({ + where: whereDuplication, + }); + + if (checkDuplicate) { + throw new Error('Openai Bot already exists'); + } + + if (data.triggerType === 'keyword') { + if (!data.triggerOperator || !data.triggerValue) { + throw new Error('Trigger operator and value are required'); + } + + const checkDuplicate = await this.botRepository.findFirst({ + where: { + triggerOperator: data.triggerOperator, + triggerValue: data.triggerValue, + id: { not: botId }, + instanceId: instanceId, + }, + }); + + if (checkDuplicate) { + throw new Error('Trigger already exists'); + } + } + + if (data.triggerType === 'advanced') { + if (!data.triggerValue) { + throw new Error('Trigger value is required'); + } + + const checkDuplicate = await this.botRepository.findFirst({ + where: { + triggerValue: data.triggerValue, + id: { not: botId }, + instanceId: instanceId, + }, + }); + + if (checkDuplicate) { + throw new Error('Trigger already exists'); + } + } + + try { + const bot = await this.botRepository.update({ + where: { + id: botId, + }, + data: { + enabled: data?.enabled, + description: data.description, + openaiCredsId: data.openaiCredsId, + botType: data.botType, + assistantId: data.assistantId, + functionUrl: data.functionUrl, + model: data.model, + systemMessages: data.systemMessages, + assistantMessages: data.assistantMessages, + userMessages: data.userMessages, + maxTokens: data.maxTokens, + expire: data.expire, + keywordFinish: data.keywordFinish, + delayMessage: data.delayMessage, + unknownMessage: data.unknownMessage, + listeningFromMe: data.listeningFromMe, + stopBotFromMe: data.stopBotFromMe, + keepOpen: data.keepOpen, + debounceTime: data.debounceTime, + instanceId: instanceId, + triggerType: data.triggerType, + triggerOperator: data.triggerOperator, + triggerValue: data.triggerValue, + ignoreJids: data.ignoreJids, + splitMessages: data.splitMessages, + timePerChar: data.timePerChar, + }, + }); + + return bot; + } catch (error) { + this.logger.error(error); + throw new Error('Error updating openai bot'); + } + } + + public async deleteBot(instance: InstanceDto, botId: string) { + if (!this.integrationEnabled) throw new BadRequestException('Openai is disabled'); + + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const bot = await this.botRepository.findFirst({ + where: { + id: botId, + }, + }); + + if (!bot) { + throw new Error('Openai bot not found'); + } + + if (bot.instanceId !== instanceId) { + throw new Error('Openai bot not found'); + } + try { + await this.sessionRepository.deleteMany({ + where: { + botId: botId, + }, + }); + + await this.botRepository.delete({ + where: { + id: botId, + }, + }); + + return { bot: { id: botId } }; + } catch (error) { + this.logger.error(error); + throw new Error('Error deleting openai bot'); + } + } + + // Settings + public async settings(instance: InstanceDto, data: any) { + if (!this.integrationEnabled) throw new BadRequestException('Openai is disabled'); + + try { + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const settings = await this.settingsRepository.findFirst({ + where: { + instanceId: instanceId, + }, + }); + + if (settings) { + const updateSettings = await this.settingsRepository.update({ + where: { + id: settings.id, + }, + data: { + openaiCredsId: data.openaiCredsId, + expire: data.expire, + keywordFinish: data.keywordFinish, + delayMessage: data.delayMessage, + unknownMessage: data.unknownMessage, + listeningFromMe: data.listeningFromMe, + stopBotFromMe: data.stopBotFromMe, + keepOpen: data.keepOpen, + debounceTime: data.debounceTime, + speechToText: data.speechToText, + openaiIdFallback: data.openaiIdFallback, + ignoreJids: data.ignoreJids, + splitMessages: data.splitMessages, + timePerChar: data.timePerChar, + }, + }); + + return { + openaiCredsId: updateSettings.openaiCredsId, + expire: updateSettings.expire, + keywordFinish: updateSettings.keywordFinish, + delayMessage: updateSettings.delayMessage, + unknownMessage: updateSettings.unknownMessage, + listeningFromMe: updateSettings.listeningFromMe, + stopBotFromMe: updateSettings.stopBotFromMe, + keepOpen: updateSettings.keepOpen, + debounceTime: updateSettings.debounceTime, + speechToText: updateSettings.speechToText, + openaiIdFallback: updateSettings.openaiIdFallback, + ignoreJids: updateSettings.ignoreJids, + splitMessages: updateSettings.splitMessages, + timePerChar: updateSettings.timePerChar, + }; + } + + const newSetttings = await this.settingsRepository.create({ + data: { + openaiCredsId: data.openaiCredsId, + expire: data.expire, + keywordFinish: data.keywordFinish, + delayMessage: data.delayMessage, + unknownMessage: data.unknownMessage, + listeningFromMe: data.listeningFromMe, + stopBotFromMe: data.stopBotFromMe, + keepOpen: data.keepOpen, + debounceTime: data.debounceTime, + openaiIdFallback: data.openaiIdFallback, + ignoreJids: data.ignoreJids, + speechToText: data.speechToText, + instanceId: instanceId, + splitMessages: data.splitMessages, + timePerChar: data.timePerChar, + }, + }); + + return { + openaiCredsId: newSetttings.openaiCredsId, + expire: newSetttings.expire, + keywordFinish: newSetttings.keywordFinish, + delayMessage: newSetttings.delayMessage, + unknownMessage: newSetttings.unknownMessage, + listeningFromMe: newSetttings.listeningFromMe, + stopBotFromMe: newSetttings.stopBotFromMe, + keepOpen: newSetttings.keepOpen, + debounceTime: newSetttings.debounceTime, + openaiIdFallback: newSetttings.openaiIdFallback, + ignoreJids: newSetttings.ignoreJids, + speechToText: newSetttings.speechToText, + splitMessages: newSetttings.splitMessages, + timePerChar: newSetttings.timePerChar, + }; + } catch (error) { + this.logger.error(error); + throw new Error('Error setting default settings'); + } + } + + public async fetchSettings(instance: InstanceDto) { + if (!this.integrationEnabled) throw new BadRequestException('Openai is disabled'); + + try { + const instanceId = ( + await this.prismaRepository.instance.findFirst({ + select: { id: true }, + where: { + name: instance.instanceName, + }, + }) + )?.id; + + const settings = await this.settingsRepository.findFirst({ + where: { + instanceId: instanceId, + }, + include: { + Fallback: true, + }, + }); + + if (!settings) { + return { + openaiCredsId: null, + expire: 0, + keywordFinish: '', + delayMessage: 0, + unknownMessage: '', + listeningFromMe: false, + stopBotFromMe: false, + keepOpen: false, + ignoreJids: [], + splitMessages: false, + timePerChar: 0, + openaiIdFallback: null, + speechToText: false, + fallback: null, + }; + } + + return { + openaiCredsId: settings.openaiCredsId, + expire: settings.expire, + keywordFinish: settings.keywordFinish, + delayMessage: settings.delayMessage, + unknownMessage: settings.unknownMessage, + listeningFromMe: settings.listeningFromMe, + stopBotFromMe: settings.stopBotFromMe, + keepOpen: settings.keepOpen, + ignoreJids: settings.ignoreJids, + splitMessages: settings.splitMessages, + timePerChar: settings.timePerChar, + openaiIdFallback: settings.openaiIdFallback, + speechToText: settings.speechToText, + fallback: settings.Fallback, + }; + } catch (error) { + this.logger.error(error); + throw new Error('Error fetching default settings'); + } + } + + // Sessions + public async changeStatus(instance: InstanceDto, data: any) { + if (!this.integrationEnabled) throw new BadRequestException('Openai is disabled'); + + try { + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const defaultSettingCheck = await this.settingsRepository.findFirst({ + where: { + instanceId, + }, + }); + + const remoteJid = data.remoteJid; + const status = data.status; + + if (status === 'delete') { + await this.sessionRepository.deleteMany({ + where: { + remoteJid: remoteJid, + botId: { not: null }, + }, + }); + + return { openai: { remoteJid: remoteJid, status: status } }; + } + + if (status === 'closed') { + if (defaultSettingCheck?.keepOpen) { + await this.sessionRepository.updateMany({ + where: { + remoteJid: remoteJid, + botId: { not: null }, + status: { not: 'closed' }, + }, + data: { + status: 'closed', + }, + }); + } else { + await this.sessionRepository.deleteMany({ + where: { + remoteJid: remoteJid, + }, + }); + } + + return { openai: { ...instance, openai: { remoteJid: remoteJid, status: status } } }; + } else { + const session = await this.sessionRepository.updateMany({ + where: { + instanceId: instanceId, + remoteJid: remoteJid, + botId: { not: null }, + }, + data: { + status: status, + }, + }); + + const openaiData = { + remoteJid: remoteJid, + status: status, + session, + }; + + return { openai: { ...instance, openai: openaiData } }; + } + } catch (error) { + this.logger.error(error); + throw new Error('Error changing status'); + } + } + + public async fetchSessions(instance: InstanceDto, botId: string, remoteJid?: string) { + if (!this.integrationEnabled) throw new BadRequestException('Openai is disabled'); + + try { + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const openaiBot = await this.botRepository.findFirst({ + where: { + id: botId, + }, + }); + + if (openaiBot && openaiBot.instanceId !== instanceId) { + throw new Error('Openai Bot not found'); + } + + return await this.sessionRepository.findMany({ + where: { + instanceId: instanceId, + remoteJid, + botId: openaiBot ? botId : { not: null }, + type: 'openai', + }, + }); + } catch (error) { + this.logger.error(error); + throw new Error('Error fetching sessions'); + } + } + + public async ignoreJid(instance: InstanceDto, data: IgnoreJidDto) { + if (!this.integrationEnabled) throw new BadRequestException('Openai is disabled'); + + try { + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const settings = await this.settingsRepository.findFirst({ + where: { + instanceId: instanceId, + }, + }); + + if (!settings) { + throw new Error('Settings not found'); + } + + let ignoreJids: any = settings?.ignoreJids || []; + + if (data.action === 'add') { + if (ignoreJids.includes(data.remoteJid)) return { ignoreJids: ignoreJids }; + + ignoreJids.push(data.remoteJid); + } else { + ignoreJids = ignoreJids.filter((jid) => jid !== data.remoteJid); + } + + const updateSettings = await this.settingsRepository.update({ + where: { + id: settings.id, + }, + data: { + ignoreJids: ignoreJids, + }, + }); + + return { + ignoreJids: updateSettings.ignoreJids, + }; + } catch (error) { + this.logger.error(error); + throw new Error('Error setting default settings'); + } + } + + // Emit + public async emit({ instance, remoteJid, msg, pushName }: EmitData) { + if (!this.integrationEnabled) return; + + try { + const settings = await this.settingsRepository.findFirst({ + where: { + instanceId: instance.instanceId, + }, + }); + + if (this.checkIgnoreJids(settings?.ignoreJids, remoteJid)) return; + + let session = await this.getSession(remoteJid, instance); + + const content = getConversationMessage(msg); + + let findBot = (await this.findBotTrigger(this.botRepository, content, instance, session)) as OpenaiBot; + + if (!findBot) { + const fallback = await this.settingsRepository.findFirst({ + where: { + instanceId: instance.instanceId, + }, + }); + + if (fallback?.openaiIdFallback) { + const findFallback = await this.botRepository.findFirst({ + where: { + id: fallback.openaiIdFallback, + }, + }); + + findBot = findFallback; + } else { + return; + } + } + + let expire = findBot?.expire; + let keywordFinish = findBot?.keywordFinish; + let delayMessage = findBot?.delayMessage; + let unknownMessage = findBot?.unknownMessage; + let listeningFromMe = findBot?.listeningFromMe; + let stopBotFromMe = findBot?.stopBotFromMe; + let keepOpen = findBot?.keepOpen; + let debounceTime = findBot?.debounceTime; + let ignoreJids = findBot?.ignoreJids; + let splitMessages = findBot?.splitMessages; + let timePerChar = findBot?.timePerChar; + + if (expire === undefined || expire === null) expire = settings.expire; + if (keywordFinish === undefined || keywordFinish === null) keywordFinish = settings.keywordFinish; + if (delayMessage === undefined || delayMessage === null) delayMessage = settings.delayMessage; + if (unknownMessage === undefined || unknownMessage === null) unknownMessage = settings.unknownMessage; + if (listeningFromMe === undefined || listeningFromMe === null) listeningFromMe = settings.listeningFromMe; + if (stopBotFromMe === undefined || stopBotFromMe === null) stopBotFromMe = settings.stopBotFromMe; + if (keepOpen === undefined || keepOpen === null) keepOpen = settings.keepOpen; + if (debounceTime === undefined || debounceTime === null) debounceTime = settings.debounceTime; + if (ignoreJids === undefined || ignoreJids === null) ignoreJids = settings.ignoreJids; + if (splitMessages === undefined || splitMessages === null) splitMessages = settings?.splitMessages ?? false; + if (timePerChar === undefined || timePerChar === null) timePerChar = settings?.timePerChar ?? 0; + + const key = msg.key as { + id: string; + remoteJid: string; + fromMe: boolean; + participant: string; + }; + + if (stopBotFromMe && key.fromMe && session) { + session = await this.sessionRepository.update({ + where: { + id: session.id, + }, + data: { + status: 'paused', + }, + }); + } + + if (!listeningFromMe && key.fromMe) { + return; + } + + if (session && !session.awaitUser) { + return; + } + + if (debounceTime && debounceTime > 0) { + this.processDebounce(this.userMessageDebounce, content, remoteJid, debounceTime, async (debouncedContent) => { + if (findBot.botType === 'assistant') { + await this.openaiService.processOpenaiAssistant( + this.waMonitor.waInstances[instance.instanceName], + remoteJid, + pushName, + key.fromMe, + findBot, + session, + { + ...settings, + expire, + keywordFinish, + delayMessage, + unknownMessage, + listeningFromMe, + stopBotFromMe, + keepOpen, + debounceTime, + ignoreJids, + splitMessages, + timePerChar, + }, + debouncedContent, + ); + } + + if (findBot.botType === 'chatCompletion') { + await this.openaiService.processOpenaiChatCompletion( + this.waMonitor.waInstances[instance.instanceName], + remoteJid, + pushName, + findBot, + session, + { + ...settings, + expire, + keywordFinish, + delayMessage, + unknownMessage, + listeningFromMe, + stopBotFromMe, + keepOpen, + debounceTime, + ignoreJids, + splitMessages, + timePerChar, + }, + debouncedContent, + ); + } + }); + } else { + if (findBot.botType === 'assistant') { + await this.openaiService.processOpenaiAssistant( + this.waMonitor.waInstances[instance.instanceName], + remoteJid, + pushName, + key.fromMe, + findBot, + session, + settings, + content, + ); + } + + if (findBot.botType === 'chatCompletion') { + await this.openaiService.processOpenaiChatCompletion( + this.waMonitor.waInstances[instance.instanceName], + remoteJid, + pushName, + findBot, + session, + settings, + content, + ); + } + } + + return; + } catch (error) { + this.logger.error(error); + return; + } + } +} diff --git a/src/api/integrations/chatbot/openai/dto/openai.dto.ts b/src/api/integrations/chatbot/openai/dto/openai.dto.ts new file mode 100644 index 00000000..a8ac2e4d --- /dev/null +++ b/src/api/integrations/chatbot/openai/dto/openai.dto.ts @@ -0,0 +1,51 @@ +import { TriggerOperator, TriggerType } from '@prisma/client'; + +export class OpenaiCredsDto { + name: string; + apiKey: string; +} + +export class OpenaiDto { + enabled?: boolean; + description?: string; + openaiCredsId: string; + botType?: string; + assistantId?: string; + functionUrl?: string; + model?: string; + systemMessages?: string[]; + assistantMessages?: string[]; + userMessages?: string[]; + maxTokens?: number; + expire?: number; + keywordFinish?: string; + delayMessage?: number; + unknownMessage?: string; + listeningFromMe?: boolean; + stopBotFromMe?: boolean; + keepOpen?: boolean; + debounceTime?: number; + triggerType?: TriggerType; + triggerOperator?: TriggerOperator; + triggerValue?: string; + ignoreJids?: any; + splitMessages?: boolean; + timePerChar?: number; +} + +export class OpenaiSettingDto { + openaiCredsId?: string; + expire?: number; + keywordFinish?: string; + delayMessage?: number; + unknownMessage?: string; + listeningFromMe?: boolean; + stopBotFromMe?: boolean; + keepOpen?: boolean; + debounceTime?: number; + openaiIdFallback?: string; + ignoreJids?: any; + speechToText?: boolean; + splitMessages?: boolean; + timePerChar?: number; +} diff --git a/src/api/integrations/chatbot/openai/routes/openai.router.ts b/src/api/integrations/chatbot/openai/routes/openai.router.ts new file mode 100644 index 00000000..ed55a4e7 --- /dev/null +++ b/src/api/integrations/chatbot/openai/routes/openai.router.ts @@ -0,0 +1,164 @@ +import { RouterBroker } from '@api/abstract/abstract.router'; +import { IgnoreJidDto } from '@api/dto/chatbot.dto'; +import { InstanceDto } from '@api/dto/instance.dto'; +import { OpenaiCredsDto, OpenaiDto, OpenaiSettingDto } from '@api/integrations/chatbot/openai/dto/openai.dto'; +import { HttpStatus } from '@api/routes/index.router'; +import { openaiController } from '@api/server.module'; +import { + instanceSchema, + openaiCredsSchema, + openaiIgnoreJidSchema, + openaiSchema, + openaiSettingSchema, + openaiStatusSchema, +} from '@validate/validate.schema'; +import { RequestHandler, Router } from 'express'; + +export class OpenaiRouter extends RouterBroker { + constructor(...guards: RequestHandler[]) { + super(); + this.router + .post(this.routerPath('creds'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: openaiCredsSchema, + ClassRef: OpenaiCredsDto, + execute: (instance, data) => openaiController.createOpenaiCreds(instance, data), + }); + + res.status(HttpStatus.CREATED).json(response); + }) + .get(this.routerPath('creds'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => openaiController.findOpenaiCreds(instance), + }); + + res.status(HttpStatus.OK).json(response); + }) + .delete(this.routerPath('creds/:openaiCredsId'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => openaiController.deleteCreds(instance, req.params.openaiCredsId), + }); + + res.status(HttpStatus.OK).json(response); + }) + .post(this.routerPath('create'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: openaiSchema, + ClassRef: OpenaiDto, + execute: (instance, data) => openaiController.createBot(instance, data), + }); + + res.status(HttpStatus.CREATED).json(response); + }) + .get(this.routerPath('find'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => openaiController.findBot(instance), + }); + + res.status(HttpStatus.OK).json(response); + }) + .get(this.routerPath('fetch/:openaiBotId'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => openaiController.fetchBot(instance, req.params.openaiBotId), + }); + + res.status(HttpStatus.OK).json(response); + }) + .put(this.routerPath('update/:openaiBotId'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: openaiSchema, + ClassRef: OpenaiDto, + execute: (instance, data) => openaiController.updateBot(instance, req.params.openaiBotId, data), + }); + + res.status(HttpStatus.OK).json(response); + }) + .delete(this.routerPath('delete/:openaiBotId'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => openaiController.deleteBot(instance, req.params.openaiBotId), + }); + + res.status(HttpStatus.OK).json(response); + }) + .post(this.routerPath('settings'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: openaiSettingSchema, + ClassRef: OpenaiSettingDto, + execute: (instance, data) => openaiController.settings(instance, data), + }); + + res.status(HttpStatus.OK).json(response); + }) + .get(this.routerPath('fetchSettings'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => openaiController.fetchSettings(instance), + }); + + res.status(HttpStatus.OK).json(response); + }) + .post(this.routerPath('changeStatus'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: openaiStatusSchema, + ClassRef: InstanceDto, + execute: (instance, data) => openaiController.changeStatus(instance, data), + }); + + res.status(HttpStatus.OK).json(response); + }) + .get(this.routerPath('fetchSessions/:openaiBotId'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => openaiController.fetchSessions(instance, req.params.openaiBotId), + }); + + res.status(HttpStatus.OK).json(response); + }) + .post(this.routerPath('ignoreJid'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: openaiIgnoreJidSchema, + ClassRef: IgnoreJidDto, + execute: (instance, data) => openaiController.ignoreJid(instance, data), + }); + + res.status(HttpStatus.OK).json(response); + }) + .get(this.routerPath('getModels'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => openaiController.getModels(instance), + }); + + res.status(HttpStatus.OK).json(response); + }); + } + + public readonly router: Router = Router(); +} diff --git a/src/api/integrations/chatbot/openai/services/openai.service.ts b/src/api/integrations/chatbot/openai/services/openai.service.ts new file mode 100644 index 00000000..16f4ce80 --- /dev/null +++ b/src/api/integrations/chatbot/openai/services/openai.service.ts @@ -0,0 +1,855 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import { InstanceDto } from '@api/dto/instance.dto'; +import { PrismaRepository } from '@api/repository/repository.service'; +import { WAMonitoringService } from '@api/services/monitor.service'; +import { Integration } from '@api/types/wa.types'; +import { ConfigService, Language } from '@config/env.config'; +import { Logger } from '@config/logger.config'; +import { IntegrationSession, OpenaiBot, OpenaiCreds, OpenaiSetting } from '@prisma/client'; +import { sendTelemetry } from '@utils/sendTelemetry'; +import axios from 'axios'; +import { downloadMediaMessage } from 'baileys'; +import FormData from 'form-data'; +import OpenAI from 'openai'; +import P from 'pino'; + +export class OpenaiService { + constructor( + private readonly waMonitor: WAMonitoringService, + private readonly configService: ConfigService, + private readonly prismaRepository: PrismaRepository, + ) {} + + private client: OpenAI; + + private readonly logger = new Logger('OpenaiService'); + + private async sendMessageToBot(instance: any, openaiBot: OpenaiBot, remoteJid: string, content: string) { + const systemMessages: any = openaiBot.systemMessages; + + const messagesSystem: any[] = systemMessages.map((message) => { + return { + role: 'system', + content: message, + }; + }); + + const assistantMessages: any = openaiBot.assistantMessages; + + const messagesAssistant: any[] = assistantMessages.map((message) => { + return { + role: 'assistant', + content: message, + }; + }); + + const userMessages: any = openaiBot.userMessages; + + const messagesUser: any[] = userMessages.map((message) => { + return { + role: 'user', + content: message, + }; + }); + + const messageData: any = { + role: 'user', + content: [{ type: 'text', text: content }], + }; + + if (this.isImageMessage(content)) { + const contentSplit = content.split('|'); + + const url = contentSplit[1].split('?')[0]; + + messageData.content = [ + { type: 'text', text: contentSplit[2] || content }, + { + type: 'image_url', + image_url: { + url: url, + }, + }, + ]; + } + + const messages: any[] = [...messagesSystem, ...messagesAssistant, ...messagesUser, messageData]; + + if (instance.integration === Integration.WHATSAPP_BAILEYS) { + await instance.client.presenceSubscribe(remoteJid); + await instance.client.sendPresenceUpdate('composing', remoteJid); + } + + const completions = await this.client.chat.completions.create({ + model: openaiBot.model, + messages: messages, + max_tokens: openaiBot.maxTokens, + }); + + if (instance.integration === Integration.WHATSAPP_BAILEYS) + await instance.client.sendPresenceUpdate('paused', remoteJid); + + const message = completions.choices[0].message.content; + + return message; + } + + private async sendMessageToAssistant( + instance: any, + openaiBot: OpenaiBot, + remoteJid: string, + pushName: string, + fromMe: boolean, + content: string, + threadId: string, + ) { + const messageData: any = { + role: fromMe ? 'assistant' : 'user', + content: [{ type: 'text', text: content }], + }; + + if (this.isImageMessage(content)) { + const contentSplit = content.split('|'); + + const url = contentSplit[1].split('?')[0]; + + messageData.content = [ + { type: 'text', text: contentSplit[2] || content }, + { + type: 'image_url', + image_url: { + url: url, + }, + }, + ]; + } + + await this.client.beta.threads.messages.create(threadId, messageData); + + if (fromMe) { + sendTelemetry('/message/sendText'); + return; + } + + const runAssistant = await this.client.beta.threads.runs.create(threadId, { + assistant_id: openaiBot.assistantId, + }); + + if (instance.integration === Integration.WHATSAPP_BAILEYS) { + await instance.client.presenceSubscribe(remoteJid); + await instance.client.sendPresenceUpdate('composing', remoteJid); + } + + const response = await this.getAIResponse(threadId, runAssistant.id, openaiBot.functionUrl, remoteJid, pushName); + + if (instance.integration === Integration.WHATSAPP_BAILEYS) + await instance.client.sendPresenceUpdate('paused', remoteJid); + + const message = response?.data[0].content[0].text.value; + + return message; + } + + private async sendMessageWhatsapp( + instance: any, + session: IntegrationSession, + remoteJid: string, + settings: OpenaiSetting, + message: string, + ) { + const linkRegex = /(!?)\[(.*?)\]\((.*?)\)/g; + + let textBuffer = ''; + let lastIndex = 0; + + let match: RegExpExecArray | null; + + const getMediaType = (url: string): string | null => { + const extension = url.split('.').pop()?.toLowerCase(); + const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']; + const audioExtensions = ['mp3', 'wav', 'aac', 'ogg']; + const videoExtensions = ['mp4', 'avi', 'mkv', 'mov']; + const documentExtensions = ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt']; + + if (imageExtensions.includes(extension || '')) return 'image'; + if (audioExtensions.includes(extension || '')) return 'audio'; + if (videoExtensions.includes(extension || '')) return 'video'; + if (documentExtensions.includes(extension || '')) return 'document'; + return null; + }; + + while ((match = linkRegex.exec(message)) !== null) { + const [fullMatch, exclMark, altText, url] = match; + const mediaType = getMediaType(url); + + const beforeText = message.slice(lastIndex, match.index); + if (beforeText) { + textBuffer += beforeText; + } + + if (mediaType) { + const splitMessages = settings.splitMessages ?? false; + const timePerChar = settings.timePerChar ?? 0; + const minDelay = 1000; + const maxDelay = 20000; + + if (textBuffer.trim()) { + if (splitMessages) { + const multipleMessages = textBuffer.trim().split('\n\n'); + + for (let index = 0; index < multipleMessages.length; index++) { + const message = multipleMessages[index]; + + const delay = Math.min(Math.max(message.length * timePerChar, minDelay), maxDelay); + + if (instance.integration === Integration.WHATSAPP_BAILEYS) { + await instance.client.presenceSubscribe(remoteJid); + await instance.client.sendPresenceUpdate('composing', remoteJid); + } + + await new Promise((resolve) => { + setTimeout(async () => { + await instance.textMessage( + { + number: remoteJid.split('@')[0], + delay: settings?.delayMessage || 1000, + text: message, + }, + false, + ); + resolve(); + }, delay); + }); + + if (instance.integration === Integration.WHATSAPP_BAILEYS) { + await instance.client.sendPresenceUpdate('paused', remoteJid); + } + } + } else { + await instance.textMessage( + { + number: remoteJid.split('@')[0], + delay: settings?.delayMessage || 1000, + text: textBuffer.trim(), + }, + false, + ); + } + textBuffer = ''; + } + + if (mediaType === 'audio') { + await instance.audioWhatsapp({ + number: remoteJid.split('@')[0], + delay: settings?.delayMessage || 1000, + audio: url, + caption: altText, + }); + } else { + await instance.mediaMessage( + { + number: remoteJid.split('@')[0], + delay: settings?.delayMessage || 1000, + mediatype: mediaType, + media: url, + caption: altText, + }, + null, + false, + ); + } + } else { + textBuffer += `[${altText}](${url})`; + } + + lastIndex = linkRegex.lastIndex; + } + + if (lastIndex < message.length) { + const remainingText = message.slice(lastIndex); + if (remainingText.trim()) { + textBuffer += remainingText; + } + } + + const splitMessages = settings.splitMessages ?? false; + const timePerChar = settings.timePerChar ?? 0; + const minDelay = 1000; + const maxDelay = 20000; + + if (textBuffer.trim()) { + if (splitMessages) { + const multipleMessages = textBuffer.trim().split('\n\n'); + + for (let index = 0; index < multipleMessages.length; index++) { + const message = multipleMessages[index]; + + const delay = Math.min(Math.max(message.length * timePerChar, minDelay), maxDelay); + + if (instance.integration === Integration.WHATSAPP_BAILEYS) { + await instance.client.presenceSubscribe(remoteJid); + await instance.client.sendPresenceUpdate('composing', remoteJid); + } + + await new Promise((resolve) => { + setTimeout(async () => { + await instance.textMessage( + { + number: remoteJid.split('@')[0], + delay: settings?.delayMessage || 1000, + text: message, + }, + false, + ); + resolve(); + }, delay); + }); + + if (instance.integration === Integration.WHATSAPP_BAILEYS) { + await instance.client.sendPresenceUpdate('paused', remoteJid); + } + } + } else { + await instance.textMessage( + { + number: remoteJid.split('@')[0], + delay: settings?.delayMessage || 1000, + text: textBuffer.trim(), + }, + false, + ); + } + textBuffer = ''; + } + + sendTelemetry('/message/sendText'); + + await this.prismaRepository.integrationSession.update({ + where: { + id: session.id, + }, + data: { + status: 'opened', + awaitUser: true, + }, + }); + } + + public async createAssistantNewSession(instance: InstanceDto, data: any) { + if (data.remoteJid === 'status@broadcast') return; + + const creds = await this.prismaRepository.openaiCreds.findFirst({ + where: { + id: data.openaiCredsId, + }, + }); + + if (!creds) throw new Error('Openai Creds not found'); + + try { + this.client = new OpenAI({ + apiKey: creds.apiKey, + }); + + const threadId = (await this.client.beta.threads.create({})).id; + + let session = null; + if (threadId) { + session = await this.prismaRepository.integrationSession.create({ + data: { + remoteJid: data.remoteJid, + pushName: data.pushName, + sessionId: threadId, + status: 'opened', + awaitUser: false, + botId: data.botId, + instanceId: instance.instanceId, + type: 'openai', + }, + }); + } + return { session }; + } catch (error) { + this.logger.error(error); + return; + } + } + + private async initAssistantNewSession( + instance: any, + remoteJid: string, + pushName: string, + fromMe: boolean, + openaiBot: OpenaiBot, + settings: OpenaiSetting, + session: IntegrationSession, + content: string, + ) { + const data = await this.createAssistantNewSession(instance, { + remoteJid, + pushName, + openaiCredsId: openaiBot.openaiCredsId, + botId: openaiBot.id, + }); + + if (data.session) { + session = data.session; + } + + const message = await this.sendMessageToAssistant( + instance, + openaiBot, + remoteJid, + pushName, + fromMe, + content, + session.sessionId, + ); + + await this.sendMessageWhatsapp(instance, session, remoteJid, settings, message); + + return; + } + + private isJSON(str: string): boolean { + try { + JSON.parse(str); + return true; + } catch (e) { + return false; + } + } + + private async getAIResponse( + threadId: string, + runId: string, + functionUrl: string, + remoteJid: string, + pushName: string, + ) { + const getRun = await this.client.beta.threads.runs.retrieve(threadId, runId); + let toolCalls; + switch (getRun.status) { + case 'requires_action': + toolCalls = getRun?.required_action?.submit_tool_outputs?.tool_calls; + + if (toolCalls) { + for (const toolCall of toolCalls) { + const id = toolCall.id; + const functionName = toolCall?.function?.name; + const functionArgument = this.isJSON(toolCall?.function?.arguments) + ? JSON.parse(toolCall?.function?.arguments) + : toolCall?.function?.arguments; + + let output = null; + + try { + const { data } = await axios.post(functionUrl, { + name: functionName, + arguments: { ...functionArgument, remoteJid, pushName }, + }); + + output = JSON.stringify(data) + .replace(/\\/g, '\\\\') + .replace(/"/g, '\\"') + .replace(/\n/g, '\\n') + .replace(/\r/g, '\\r') + .replace(/\t/g, '\\t'); + } catch (error) { + output = JSON.stringify(error) + .replace(/\\/g, '\\\\') + .replace(/"/g, '\\"') + .replace(/\n/g, '\\n') + .replace(/\r/g, '\\r') + .replace(/\t/g, '\\t'); + } + + await this.client.beta.threads.runs.submitToolOutputs(threadId, runId, { + tool_outputs: [ + { + tool_call_id: id, + output, + }, + ], + }); + } + } + + return this.getAIResponse(threadId, runId, functionUrl, remoteJid, pushName); + case 'queued': + await new Promise((resolve) => setTimeout(resolve, 1000)); + return this.getAIResponse(threadId, runId, functionUrl, remoteJid, pushName); + case 'in_progress': + await new Promise((resolve) => setTimeout(resolve, 1000)); + return this.getAIResponse(threadId, runId, functionUrl, remoteJid, pushName); + case 'completed': + return await this.client.beta.threads.messages.list(threadId, { + run_id: runId, + limit: 1, + }); + } + } + + private isImageMessage(content: string) { + return content.includes('imageMessage'); + } + + public async processOpenaiAssistant( + instance: any, + remoteJid: string, + pushName: string, + fromMe: boolean, + openaiBot: OpenaiBot, + session: IntegrationSession, + settings: OpenaiSetting, + content: string, + ) { + if (session && session.status === 'closed') { + return; + } + + if (session && settings.expire && settings.expire > 0) { + const now = Date.now(); + + const sessionUpdatedAt = new Date(session.updatedAt).getTime(); + + const diff = now - sessionUpdatedAt; + + const diffInMinutes = Math.floor(diff / 1000 / 60); + + if (diffInMinutes > settings.expire) { + if (settings.keepOpen) { + await this.prismaRepository.integrationSession.update({ + where: { + id: session.id, + }, + data: { + status: 'closed', + }, + }); + } else { + await this.prismaRepository.integrationSession.deleteMany({ + where: { + botId: openaiBot.id, + remoteJid: remoteJid, + }, + }); + } + + await this.initAssistantNewSession( + instance, + remoteJid, + pushName, + fromMe, + openaiBot, + settings, + session, + content, + ); + return; + } + } + + if (!session) { + await this.initAssistantNewSession(instance, remoteJid, pushName, fromMe, openaiBot, settings, session, content); + return; + } + + if (session.status !== 'paused') + await this.prismaRepository.integrationSession.update({ + where: { + id: session.id, + }, + data: { + status: 'opened', + awaitUser: false, + }, + }); + + if (!content) { + if (settings.unknownMessage) { + this.waMonitor.waInstances[instance.instanceName].textMessage( + { + number: remoteJid.split('@')[0], + delay: settings.delayMessage || 1000, + text: settings.unknownMessage, + }, + false, + ); + + sendTelemetry('/message/sendText'); + } + return; + } + + if (settings.keywordFinish && content.toLowerCase() === settings.keywordFinish.toLowerCase()) { + if (settings.keepOpen) { + await this.prismaRepository.integrationSession.update({ + where: { + id: session.id, + }, + data: { + status: 'closed', + }, + }); + } else { + await this.prismaRepository.integrationSession.deleteMany({ + where: { + botId: openaiBot.id, + remoteJid: remoteJid, + }, + }); + } + return; + } + + const creds = await this.prismaRepository.openaiCreds.findFirst({ + where: { + id: openaiBot.openaiCredsId, + }, + }); + + if (!creds) throw new Error('Openai Creds not found'); + + this.client = new OpenAI({ + apiKey: creds.apiKey, + }); + + const threadId = session.sessionId; + + const message = await this.sendMessageToAssistant( + instance, + openaiBot, + remoteJid, + pushName, + fromMe, + content, + threadId, + ); + + await this.sendMessageWhatsapp(instance, session, remoteJid, settings, message); + + return; + } + + public async createChatCompletionNewSession(instance: InstanceDto, data: any) { + if (data.remoteJid === 'status@broadcast') return; + + const id = Math.floor(Math.random() * 10000000000).toString(); + + const creds = await this.prismaRepository.openaiCreds.findFirst({ + where: { + id: data.openaiCredsId, + }, + }); + + if (!creds) throw new Error('Openai Creds not found'); + + try { + const session = await this.prismaRepository.integrationSession.create({ + data: { + remoteJid: data.remoteJid, + pushName: data.pushName, + sessionId: id, + status: 'opened', + awaitUser: false, + botId: data.botId, + instanceId: instance.instanceId, + type: 'openai', + }, + }); + + return { session, creds }; + } catch (error) { + this.logger.error(error); + return; + } + } + + private async initChatCompletionNewSession( + instance: any, + remoteJid: string, + pushName: string, + openaiBot: OpenaiBot, + settings: OpenaiSetting, + session: IntegrationSession, + content: string, + ) { + const data = await this.createChatCompletionNewSession(instance, { + remoteJid, + pushName, + openaiCredsId: openaiBot.openaiCredsId, + botId: openaiBot.id, + }); + + session = data.session; + + const creds = data.creds; + + this.client = new OpenAI({ + apiKey: creds.apiKey, + }); + + const message = await this.sendMessageToBot(instance, openaiBot, remoteJid, content); + + await this.sendMessageWhatsapp(instance, session, remoteJid, settings, message); + + return; + } + + public async processOpenaiChatCompletion( + instance: any, + remoteJid: string, + pushName: string, + openaiBot: OpenaiBot, + session: IntegrationSession, + settings: OpenaiSetting, + content: string, + ) { + if (session && session.status !== 'opened') { + return; + } + + if (session && settings.expire && settings.expire > 0) { + const now = Date.now(); + + const sessionUpdatedAt = new Date(session.updatedAt).getTime(); + + const diff = now - sessionUpdatedAt; + + const diffInMinutes = Math.floor(diff / 1000 / 60); + + if (diffInMinutes > settings.expire) { + if (settings.keepOpen) { + await this.prismaRepository.integrationSession.update({ + where: { + id: session.id, + }, + data: { + status: 'closed', + }, + }); + } else { + await this.prismaRepository.integrationSession.deleteMany({ + where: { + botId: openaiBot.id, + remoteJid: remoteJid, + }, + }); + } + + await this.initChatCompletionNewSession(instance, remoteJid, pushName, openaiBot, settings, session, content); + return; + } + } + + if (!session) { + await this.initChatCompletionNewSession(instance, remoteJid, pushName, openaiBot, settings, session, content); + return; + } + + await this.prismaRepository.integrationSession.update({ + where: { + id: session.id, + }, + data: { + status: 'opened', + awaitUser: false, + }, + }); + + if (!content) { + if (settings.unknownMessage) { + this.waMonitor.waInstances[instance.instanceName].textMessage( + { + number: remoteJid.split('@')[0], + delay: settings.delayMessage || 1000, + text: settings.unknownMessage, + }, + false, + ); + + sendTelemetry('/message/sendText'); + } + return; + } + + if (settings.keywordFinish && content.toLowerCase() === settings.keywordFinish.toLowerCase()) { + if (settings.keepOpen) { + await this.prismaRepository.integrationSession.update({ + where: { + id: session.id, + }, + data: { + status: 'closed', + }, + }); + } else { + await this.prismaRepository.integrationSession.deleteMany({ + where: { + botId: openaiBot.id, + remoteJid: remoteJid, + }, + }); + } + return; + } + + const creds = await this.prismaRepository.openaiCreds.findFirst({ + where: { + id: openaiBot.openaiCredsId, + }, + }); + + if (!creds) throw new Error('Openai Creds not found'); + + this.client = new OpenAI({ + apiKey: creds.apiKey, + }); + + const message = await this.sendMessageToBot(instance, openaiBot, remoteJid, content); + + await this.sendMessageWhatsapp(instance, session, remoteJid, settings, message); + + return; + } + + public async speechToText(creds: OpenaiCreds, msg: any, updateMediaMessage: any) { + let audio; + + if (msg?.message?.mediaUrl) { + audio = await axios.get(msg.message.mediaUrl, { responseType: 'arraybuffer' }).then((response) => { + return Buffer.from(response.data, 'binary'); + }); + } else { + audio = await downloadMediaMessage( + { key: msg.key, message: msg?.message }, + 'buffer', + {}, + { + logger: P({ level: 'error' }) as any, + reuploadRequest: updateMediaMessage, + }, + ); + } + + const lang = this.configService.get('LANGUAGE').includes('pt') + ? 'pt' + : this.configService.get('LANGUAGE'); + + const formData = new FormData(); + + formData.append('file', audio, 'audio.ogg'); + formData.append('model', 'whisper-1'); + formData.append('language', lang); + + const response = await axios.post('https://api.openai.com/v1/audio/transcriptions', formData, { + headers: { + 'Content-Type': 'multipart/form-data', + Authorization: `Bearer ${creds.apiKey}`, + }, + }); + + return response?.data?.text; + } +} diff --git a/src/api/integrations/chatbot/openai/validate/openai.schema.ts b/src/api/integrations/chatbot/openai/validate/openai.schema.ts new file mode 100644 index 00000000..a4ccfe56 --- /dev/null +++ b/src/api/integrations/chatbot/openai/validate/openai.schema.ts @@ -0,0 +1,129 @@ +import { JSONSchema7 } from 'json-schema'; +import { v4 } from 'uuid'; + +const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => { + const properties = {}; + propertyNames.forEach( + (property) => + (properties[property] = { + minLength: 1, + description: `The "${property}" cannot be empty`, + }), + ); + return { + if: { + propertyNames: { + enum: [...propertyNames], + }, + }, + then: { properties }, + }; +}; + +export const openaiSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + enabled: { type: 'boolean' }, + description: { type: 'string' }, + openaiCredsId: { type: 'string' }, + botType: { type: 'string', enum: ['assistant', 'chatCompletion'] }, + assistantId: { type: 'string' }, + functionUrl: { type: 'string' }, + model: { type: 'string' }, + systemMessages: { type: 'array', items: { type: 'string' } }, + assistantMessages: { type: 'array', items: { type: 'string' } }, + userMessages: { type: 'array', items: { type: 'string' } }, + maxTokens: { type: 'integer' }, + triggerType: { type: 'string', enum: ['all', 'keyword', 'none', 'advanced'] }, + triggerOperator: { type: 'string', enum: ['equals', 'contains', 'startsWith', 'endsWith', 'regex'] }, + triggerValue: { type: 'string' }, + expire: { type: 'integer' }, + keywordFinish: { type: 'string' }, + delayMessage: { type: 'integer' }, + unknownMessage: { type: 'string' }, + listeningFromMe: { type: 'boolean' }, + stopBotFromMe: { type: 'boolean' }, + keepOpen: { type: 'boolean' }, + debounceTime: { type: 'integer' }, + ignoreJids: { type: 'array', items: { type: 'string' } }, + }, + required: ['enabled', 'openaiCredsId', 'botType', 'triggerType'], + ...isNotEmpty('enabled', 'openaiCredsId', 'botType', 'triggerType'), +}; + +export const openaiCredsSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + name: { type: 'string' }, + apiKey: { type: 'string' }, + }, + required: ['name', 'apiKey'], + ...isNotEmpty('name', 'apiKey'), +}; + +export const openaiStatusSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + remoteJid: { type: 'string' }, + status: { type: 'string', enum: ['opened', 'closed', 'paused', 'delete'] }, + }, + required: ['remoteJid', 'status'], + ...isNotEmpty('remoteJid', 'status'), +}; + +export const openaiSettingSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + openaiCredsId: { type: 'string' }, + expire: { type: 'integer' }, + keywordFinish: { type: 'string' }, + delayMessage: { type: 'integer' }, + unknownMessage: { type: 'string' }, + listeningFromMe: { type: 'boolean' }, + stopBotFromMe: { type: 'boolean' }, + keepOpen: { type: 'boolean' }, + debounceTime: { type: 'integer' }, + speechToText: { type: 'boolean' }, + ignoreJids: { type: 'array', items: { type: 'string' } }, + openaiIdFallback: { type: 'string' }, + }, + required: [ + 'openaiCredsId', + 'expire', + 'keywordFinish', + 'delayMessage', + 'unknownMessage', + 'listeningFromMe', + 'stopBotFromMe', + 'keepOpen', + 'debounceTime', + 'ignoreJids', + ], + ...isNotEmpty( + 'openaiCredsId', + 'expire', + 'keywordFinish', + 'delayMessage', + 'unknownMessage', + 'listeningFromMe', + 'stopBotFromMe', + 'keepOpen', + 'debounceTime', + 'ignoreJids', + ), +}; + +export const openaiIgnoreJidSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + remoteJid: { type: 'string' }, + action: { type: 'string', enum: ['add', 'remove'] }, + }, + required: ['remoteJid', 'action'], + ...isNotEmpty('remoteJid', 'action'), +}; diff --git a/src/api/integrations/chatbot/typebot/controllers/typebot.controller.ts b/src/api/integrations/chatbot/typebot/controllers/typebot.controller.ts new file mode 100644 index 00000000..14975234 --- /dev/null +++ b/src/api/integrations/chatbot/typebot/controllers/typebot.controller.ts @@ -0,0 +1,1071 @@ +import { IgnoreJidDto } from '@api/dto/chatbot.dto'; +import { InstanceDto } from '@api/dto/instance.dto'; +import { TypebotDto } from '@api/integrations/chatbot/typebot/dto/typebot.dto'; +import { TypebotService } from '@api/integrations/chatbot/typebot/services/typebot.service'; +import { PrismaRepository } from '@api/repository/repository.service'; +import { WAMonitoringService } from '@api/services/monitor.service'; +import { Events } from '@api/types/wa.types'; +import { configService, Typebot } from '@config/env.config'; +import { Logger } from '@config/logger.config'; +import { BadRequestException } from '@exceptions'; +import { Typebot as TypebotModel } from '@prisma/client'; +import { getConversationMessage } from '@utils/getConversationMessage'; +import axios from 'axios'; + +import { ChatbotController, ChatbotControllerInterface } from '../../chatbot.controller'; + +export class TypebotController extends ChatbotController implements ChatbotControllerInterface { + constructor( + private readonly typebotService: TypebotService, + prismaRepository: PrismaRepository, + waMonitor: WAMonitoringService, + ) { + super(prismaRepository, waMonitor); + + this.botRepository = this.prismaRepository.typebot; + this.settingsRepository = this.prismaRepository.typebotSetting; + this.sessionRepository = this.prismaRepository.integrationSession; + } + + public readonly logger = new Logger('TypebotController'); + + integrationEnabled = configService.get('TYPEBOT').ENABLED; + botRepository: any; + settingsRepository: any; + sessionRepository: any; + userMessageDebounce: { [key: string]: { message: string; timeoutId: NodeJS.Timeout } } = {}; + + // Bots + public async createBot(instance: InstanceDto, data: TypebotDto) { + if (!this.integrationEnabled) throw new BadRequestException('Typebot is disabled'); + + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + if ( + !data.expire || + !data.keywordFinish || + !data.delayMessage || + !data.unknownMessage || + !data.listeningFromMe || + !data.stopBotFromMe || + !data.keepOpen || + !data.debounceTime || + !data.ignoreJids + ) { + const defaultSettingCheck = await this.settingsRepository.findFirst({ + where: { + instanceId: instanceId, + }, + }); + + if (!data.expire) data.expire = defaultSettingCheck?.expire || 0; + if (!data.keywordFinish) data.keywordFinish = defaultSettingCheck?.keywordFinish || '#SAIR'; + if (!data.delayMessage) data.delayMessage = defaultSettingCheck?.delayMessage || 1000; + if (!data.unknownMessage) data.unknownMessage = defaultSettingCheck?.unknownMessage || 'Desculpe, não entendi'; + if (!data.listeningFromMe) data.listeningFromMe = defaultSettingCheck?.listeningFromMe || false; + if (!data.stopBotFromMe) data.stopBotFromMe = defaultSettingCheck?.stopBotFromMe || false; + if (!data.keepOpen) data.keepOpen = defaultSettingCheck?.keepOpen || false; + if (!data.debounceTime) data.debounceTime = defaultSettingCheck?.debounceTime || 0; + if (!data.ignoreJids) data.ignoreJids = defaultSettingCheck?.ignoreJids || []; + + if (!defaultSettingCheck) { + await this.settings(instance, { + expire: data.expire, + keywordFinish: data.keywordFinish, + delayMessage: data.delayMessage, + unknownMessage: data.unknownMessage, + listeningFromMe: data.listeningFromMe, + stopBotFromMe: data.stopBotFromMe, + keepOpen: data.keepOpen, + debounceTime: data.debounceTime, + ignoreJids: data.ignoreJids, + }); + } + } + + const checkTriggerAll = await this.botRepository.findFirst({ + where: { + enabled: true, + triggerType: 'all', + instanceId: instanceId, + }, + }); + + if (checkTriggerAll && data.triggerType === 'all') { + throw new Error('You already have a typebot with an "All" trigger, you cannot have more bots while it is active'); + } + + const checkDuplicate = await this.botRepository.findFirst({ + where: { + url: data.url, + typebot: data.typebot, + instanceId: instanceId, + }, + }); + + if (checkDuplicate) { + throw new Error('Typebot already exists'); + } + + if (data.triggerType === 'keyword') { + if (!data.triggerOperator || !data.triggerValue) { + throw new Error('Trigger operator and value are required'); + } + + const checkDuplicate = await this.botRepository.findFirst({ + where: { + triggerOperator: data.triggerOperator, + triggerValue: data.triggerValue, + instanceId: instanceId, + }, + }); + + if (checkDuplicate) { + throw new Error('Trigger already exists'); + } + } + + if (data.triggerType === 'advanced') { + if (!data.triggerValue) { + throw new Error('Trigger value is required'); + } + + const checkDuplicate = await this.botRepository.findFirst({ + where: { + triggerValue: data.triggerValue, + instanceId: instanceId, + }, + }); + + if (checkDuplicate) { + throw new Error('Trigger already exists'); + } + } + + try { + const bot = await this.botRepository.create({ + data: { + enabled: data?.enabled, + description: data.description, + url: data.url, + typebot: data.typebot, + expire: data.expire, + keywordFinish: data.keywordFinish, + delayMessage: data.delayMessage, + unknownMessage: data.unknownMessage, + listeningFromMe: data.listeningFromMe, + stopBotFromMe: data.stopBotFromMe, + keepOpen: data.keepOpen, + debounceTime: data.debounceTime, + instanceId: instanceId, + triggerType: data.triggerType, + triggerOperator: data.triggerOperator, + triggerValue: data.triggerValue, + ignoreJids: data.ignoreJids, + }, + }); + + return bot; + } catch (error) { + this.logger.error(error); + throw new Error('Error creating typebot'); + } + } + + public async findBot(instance: InstanceDto) { + if (!this.integrationEnabled) throw new BadRequestException('Typebot is disabled'); + + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const bots = await this.botRepository.findMany({ + where: { + instanceId: instanceId, + }, + }); + + if (!bots.length) { + return null; + } + + return bots; + } + + public async fetchBot(instance: InstanceDto, botId: string) { + if (!this.integrationEnabled) throw new BadRequestException('Typebot is disabled'); + + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const bot = await this.botRepository.findFirst({ + where: { + id: botId, + }, + }); + + if (!bot) { + throw new Error('Typebot not found'); + } + + if (bot.instanceId !== instanceId) { + throw new Error('Typebot not found'); + } + + return bot; + } + + public async updateBot(instance: InstanceDto, botId: string, data: TypebotDto) { + if (!this.integrationEnabled) throw new BadRequestException('Typebot is disabled'); + + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const typebot = await this.botRepository.findFirst({ + where: { + id: botId, + }, + }); + + if (!typebot) { + throw new Error('Typebot not found'); + } + + if (typebot.instanceId !== instanceId) { + throw new Error('Typebot not found'); + } + + if (data.triggerType === 'all') { + const checkTriggerAll = await this.botRepository.findFirst({ + where: { + enabled: true, + triggerType: 'all', + id: { + not: botId, + }, + instanceId: instanceId, + }, + }); + + if (checkTriggerAll) { + throw new Error( + 'You already have a typebot with an "All" trigger, you cannot have more bots while it is active', + ); + } + } + + const checkDuplicate = await this.botRepository.findFirst({ + where: { + url: data.url, + typebot: data.typebot, + id: { + not: botId, + }, + instanceId: instanceId, + }, + }); + + if (checkDuplicate) { + throw new Error('Typebot already exists'); + } + + if (data.triggerType === 'keyword') { + if (!data.triggerOperator || !data.triggerValue) { + throw new Error('Trigger operator and value are required'); + } + + const checkDuplicate = await this.botRepository.findFirst({ + where: { + triggerOperator: data.triggerOperator, + triggerValue: data.triggerValue, + id: { + not: botId, + }, + instanceId: instanceId, + }, + }); + + if (checkDuplicate) { + throw new Error('Trigger already exists'); + } + } + + if (data.triggerType === 'advanced') { + if (!data.triggerValue) { + throw new Error('Trigger value is required'); + } + + const checkDuplicate = await this.botRepository.findFirst({ + where: { + triggerValue: data.triggerValue, + id: { not: botId }, + instanceId: instanceId, + }, + }); + + if (checkDuplicate) { + throw new Error('Trigger already exists'); + } + } + + try { + const bot = await this.botRepository.update({ + where: { + id: botId, + }, + data: { + enabled: data?.enabled, + description: data.description, + url: data.url, + typebot: data.typebot, + expire: data.expire, + keywordFinish: data.keywordFinish, + delayMessage: data.delayMessage, + unknownMessage: data.unknownMessage, + listeningFromMe: data.listeningFromMe, + stopBotFromMe: data.stopBotFromMe, + keepOpen: data.keepOpen, + debounceTime: data.debounceTime, + triggerType: data.triggerType, + triggerOperator: data.triggerOperator, + triggerValue: data.triggerValue, + ignoreJids: data.ignoreJids, + }, + }); + + return bot; + } catch (error) { + this.logger.error(error); + throw new Error('Error updating typebot'); + } + } + + public async deleteBot(instance: InstanceDto, botId: string) { + if (!this.integrationEnabled) throw new BadRequestException('Typebot is disabled'); + + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const typebot = await this.botRepository.findFirst({ + where: { + id: botId, + }, + }); + + if (!typebot) { + throw new Error('Typebot not found'); + } + + if (typebot.instanceId !== instanceId) { + throw new Error('Typebot not found'); + } + try { + await this.prismaRepository.integrationSession.deleteMany({ + where: { + botId: botId, + }, + }); + + await this.botRepository.delete({ + where: { + id: botId, + }, + }); + + return { typebot: { id: botId } }; + } catch (error) { + this.logger.error(error); + throw new Error('Error deleting typebot'); + } + } + + // Settings + public async settings(instance: InstanceDto, data: any) { + if (!this.integrationEnabled) throw new BadRequestException('Typebot is disabled'); + + try { + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const settings = await this.settingsRepository.findFirst({ + where: { + instanceId: instanceId, + }, + }); + + if (settings) { + const updateSettings = await this.settingsRepository.update({ + where: { + id: settings.id, + }, + data: { + expire: data.expire, + keywordFinish: data.keywordFinish, + delayMessage: data.delayMessage, + unknownMessage: data.unknownMessage, + listeningFromMe: data.listeningFromMe, + stopBotFromMe: data.stopBotFromMe, + keepOpen: data.keepOpen, + debounceTime: data.debounceTime, + typebotIdFallback: data.typebotIdFallback, + ignoreJids: data.ignoreJids, + }, + }); + + return { + expire: updateSettings.expire, + keywordFinish: updateSettings.keywordFinish, + delayMessage: updateSettings.delayMessage, + unknownMessage: updateSettings.unknownMessage, + listeningFromMe: updateSettings.listeningFromMe, + stopBotFromMe: updateSettings.stopBotFromMe, + keepOpen: updateSettings.keepOpen, + debounceTime: updateSettings.debounceTime, + typebotIdFallback: updateSettings.typebotIdFallback, + ignoreJids: updateSettings.ignoreJids, + }; + } + + const newSetttings = await this.settingsRepository.create({ + data: { + expire: data.expire, + keywordFinish: data.keywordFinish, + delayMessage: data.delayMessage, + unknownMessage: data.unknownMessage, + listeningFromMe: data.listeningFromMe, + stopBotFromMe: data.stopBotFromMe, + keepOpen: data.keepOpen, + debounceTime: data.debounceTime, + typebotIdFallback: data.typebotIdFallback, + ignoreJids: data.ignoreJids, + instanceId: instanceId, + }, + }); + + return { + expire: newSetttings.expire, + keywordFinish: newSetttings.keywordFinish, + delayMessage: newSetttings.delayMessage, + unknownMessage: newSetttings.unknownMessage, + listeningFromMe: newSetttings.listeningFromMe, + stopBotFromMe: newSetttings.stopBotFromMe, + keepOpen: newSetttings.keepOpen, + debounceTime: newSetttings.debounceTime, + typebotIdFallback: newSetttings.typebotIdFallback, + ignoreJids: newSetttings.ignoreJids, + }; + } catch (error) { + this.logger.error(error); + throw new Error('Error setting default settings'); + } + } + + public async fetchSettings(instance: InstanceDto) { + if (!this.integrationEnabled) throw new BadRequestException('Typebot is disabled'); + + try { + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const settings = await this.settingsRepository.findFirst({ + where: { + instanceId: instanceId, + }, + include: { + Fallback: true, + }, + }); + + if (!settings) { + return { + expire: 0, + keywordFinish: '', + delayMessage: 0, + unknownMessage: '', + listeningFromMe: false, + stopBotFromMe: false, + keepOpen: false, + ignoreJids: [], + typebotIdFallback: null, + fallback: null, + }; + } + + return { + expire: settings.expire, + keywordFinish: settings.keywordFinish, + delayMessage: settings.delayMessage, + unknownMessage: settings.unknownMessage, + listeningFromMe: settings.listeningFromMe, + stopBotFromMe: settings.stopBotFromMe, + keepOpen: settings.keepOpen, + ignoreJids: settings.ignoreJids, + typebotIdFallback: settings.typebotIdFallback, + fallback: settings.Fallback, + }; + } catch (error) { + this.logger.error(error); + throw new Error('Error fetching default settings'); + } + } + + // Sessions + public async startBot(instance: InstanceDto, data: any) { + if (!this.integrationEnabled) throw new BadRequestException('Typebot is disabled'); + + if (data.remoteJid === 'status@broadcast') return; + + const instanceData = await this.prismaRepository.instance.findFirst({ + where: { + name: instance.instanceName, + }, + }); + + if (!instanceData) throw new Error('Instance not found'); + + const remoteJid = data.remoteJid; + const url = data.url; + const typebot = data.typebot; + const startSession = data.startSession; + const variables = data.variables; + let expire = data?.typebot?.expire; + let keywordFinish = data?.typebot?.keywordFinish; + let delayMessage = data?.typebot?.delayMessage; + let unknownMessage = data?.typebot?.unknownMessage; + let listeningFromMe = data?.typebot?.listeningFromMe; + let stopBotFromMe = data?.typebot?.stopBotFromMe; + let keepOpen = data?.typebot?.keepOpen; + let debounceTime = data?.typebot?.debounceTime; + let ignoreJids = data?.typebot?.ignoreJids; + + const defaultSettingCheck = await this.settingsRepository.findFirst({ + where: { + instanceId: instanceData.id, + }, + }); + + if (this.checkIgnoreJids(defaultSettingCheck?.ignoreJids, remoteJid)) throw new Error('Jid not allowed'); + + if ( + !expire || + !keywordFinish || + !delayMessage || + !unknownMessage || + !listeningFromMe || + !stopBotFromMe || + !keepOpen || + !debounceTime || + !ignoreJids + ) { + if (expire === undefined || expire === null) expire = defaultSettingCheck.expire; + if (keywordFinish === undefined || keywordFinish === null) keywordFinish = defaultSettingCheck.keywordFinish; + if (delayMessage === undefined || delayMessage === null) delayMessage = defaultSettingCheck.delayMessage; + if (unknownMessage === undefined || unknownMessage === null) unknownMessage = defaultSettingCheck.unknownMessage; + if (listeningFromMe === undefined || listeningFromMe === null) + listeningFromMe = defaultSettingCheck.listeningFromMe; + if (stopBotFromMe === undefined || stopBotFromMe === null) stopBotFromMe = defaultSettingCheck.stopBotFromMe; + if (keepOpen === undefined || keepOpen === null) keepOpen = defaultSettingCheck.keepOpen; + if (debounceTime === undefined || debounceTime === null) debounceTime = defaultSettingCheck.debounceTime; + if (ignoreJids === undefined || ignoreJids === null) ignoreJids = defaultSettingCheck.ignoreJids; + + if (!defaultSettingCheck) { + await this.settings(instance, { + expire: expire, + keywordFinish: keywordFinish, + delayMessage: delayMessage, + unknownMessage: unknownMessage, + listeningFromMe: listeningFromMe, + stopBotFromMe: stopBotFromMe, + keepOpen: keepOpen, + debounceTime: debounceTime, + ignoreJids: ignoreJids, + }); + } + } + + const prefilledVariables: any = {}; + + if (variables?.length) { + variables.forEach((variable: { name: string | number; value: string }) => { + prefilledVariables[variable.name] = variable.value; + }); + } + + if (startSession) { + let findBot: any = await this.botRepository.findFirst({ + where: { + url: url, + typebot: typebot, + instanceId: instanceData.id, + }, + }); + + if (!findBot) { + findBot = await this.botRepository.create({ + data: { + enabled: true, + url: url, + typebot: typebot, + instanceId: instanceData.id, + expire: expire, + keywordFinish: keywordFinish, + delayMessage: delayMessage, + unknownMessage: unknownMessage, + listeningFromMe: listeningFromMe, + stopBotFromMe: stopBotFromMe, + keepOpen: keepOpen, + }, + }); + } + + await this.prismaRepository.integrationSession.deleteMany({ + where: { + remoteJid: remoteJid, + instanceId: instanceData.id, + botId: { not: null }, + }, + }); + + await this.typebotService.processTypebot( + instanceData, + remoteJid, + null, + null, + findBot, + url, + expire, + typebot, + keywordFinish, + delayMessage, + unknownMessage, + listeningFromMe, + stopBotFromMe, + keepOpen, + 'init', + prefilledVariables, + ); + } else { + const id = Math.floor(Math.random() * 10000000000).toString(); + + try { + const version = configService.get('TYPEBOT').API_VERSION; + let url: string; + let reqData: {}; + if (version === 'latest') { + url = `${data.url}/api/v1/typebots/${data.typebot}/startChat`; + + reqData = { + prefilledVariables: prefilledVariables, + }; + } else { + url = `${data.url}/api/v1/sendMessage`; + + reqData = { + startParams: { + publicId: data.typebot, + prefilledVariables: prefilledVariables, + }, + }; + } + const request = await axios.post(url, reqData); + + await this.typebotService.sendWAMessage( + instanceData, + null, + { + expire: expire, + keywordFinish: keywordFinish, + delayMessage: delayMessage, + unknownMessage: unknownMessage, + listeningFromMe: listeningFromMe, + stopBotFromMe: stopBotFromMe, + keepOpen: keepOpen, + }, + remoteJid, + request.data.messages, + request.data.input, + request.data.clientSideActions, + ); + + this.waMonitor.waInstances[instance.instanceName].sendDataWebhook(Events.TYPEBOT_START, { + remoteJid: remoteJid, + url: url, + typebot: typebot, + variables: variables, + sessionId: id, + }); + } catch (error) { + this.logger.error(error); + return; + } + } + + return { + typebot: { + ...instance, + typebot: { + url: url, + remoteJid: remoteJid, + typebot: typebot, + prefilledVariables: prefilledVariables, + }, + }, + }; + } + + public async changeStatus(instance: InstanceDto, data: any) { + if (!this.integrationEnabled) throw new BadRequestException('Typebot is disabled'); + + try { + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const remoteJid = data.remoteJid; + const status = data.status; + + const defaultSettingCheck = await this.settingsRepository.findFirst({ + where: { + instanceId, + }, + }); + + if (status === 'delete') { + await this.sessionRepository.deleteMany({ + where: { + remoteJid: remoteJid, + instanceId: instanceId, + botId: { not: null }, + }, + }); + + return { typebot: { ...instance, typebot: { remoteJid: remoteJid, status: status } } }; + } + + if (status === 'closed') { + if (defaultSettingCheck?.keepOpen) { + await this.sessionRepository.updateMany({ + where: { + instanceId: instanceId, + remoteJid: remoteJid, + botId: { not: null }, + }, + data: { + status: status, + }, + }); + } else { + await this.sessionRepository.deleteMany({ + where: { + remoteJid: remoteJid, + instanceId: instanceId, + botId: { not: null }, + }, + }); + } + + return { typebot: { ...instance, typebot: { remoteJid: remoteJid, status: status } } }; + } + + const session = await this.sessionRepository.updateMany({ + where: { + instanceId: instanceId, + remoteJid: remoteJid, + botId: { not: null }, + }, + data: { + status: status, + }, + }); + + const typebotData = { + remoteJid: remoteJid, + status: status, + session, + }; + + this.waMonitor.waInstances[instance.instanceName].sendDataWebhook(Events.TYPEBOT_CHANGE_STATUS, typebotData); + + return { typebot: { ...instance, typebot: typebotData } }; + } catch (error) { + this.logger.error(error); + throw new Error('Error changing status'); + } + } + + public async fetchSessions(instance: InstanceDto, botId: string, remoteJid?: string) { + if (!this.integrationEnabled) throw new BadRequestException('Typebot is disabled'); + + try { + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const typebot = await this.botRepository.findFirst({ + where: { + id: botId, + }, + }); + + if (typebot && typebot.instanceId !== instanceId) { + throw new Error('Typebot not found'); + } + + return await this.sessionRepository.findMany({ + where: { + instanceId: instanceId, + remoteJid, + botId: botId ?? { not: null }, + type: 'typebot', + }, + }); + } catch (error) { + this.logger.error(error); + throw new Error('Error fetching sessions'); + } + } + + public async ignoreJid(instance: InstanceDto, data: IgnoreJidDto) { + if (!this.integrationEnabled) throw new BadRequestException('Typebot is disabled'); + + try { + const instanceId = await this.prismaRepository.instance + .findFirst({ + where: { + name: instance.instanceName, + }, + }) + .then((instance) => instance.id); + + const settings = await this.settingsRepository.findFirst({ + where: { + instanceId: instanceId, + }, + }); + + if (!settings) { + throw new Error('Settings not found'); + } + + let ignoreJids: any = settings?.ignoreJids || []; + + if (data.action === 'add') { + if (ignoreJids.includes(data.remoteJid)) return { ignoreJids: ignoreJids }; + + ignoreJids.push(data.remoteJid); + } else { + ignoreJids = ignoreJids.filter((jid) => jid !== data.remoteJid); + } + + const updateSettings = await this.settingsRepository.update({ + where: { + id: settings.id, + }, + data: { + ignoreJids: ignoreJids, + }, + }); + + return { + ignoreJids: updateSettings.ignoreJids, + }; + } catch (error) { + this.logger.error(error); + throw new Error('Error setting default settings'); + } + } + + public async emit({ + instance, + remoteJid, + msg, + }: { + instance: InstanceDto; + remoteJid: string; + msg: any; + pushName?: string; + }) { + if (!this.integrationEnabled) return; + + try { + const instanceData = await this.prismaRepository.instance.findFirst({ + where: { + name: instance.instanceName, + }, + }); + + if (!instanceData) throw new Error('Instance not found'); + + const session = await this.getSession(remoteJid, instance); + + const content = getConversationMessage(msg); + + let findBot = (await this.findBotTrigger(this.botRepository, content, instance, session)) as TypebotModel; + + if (!findBot) { + const fallback = await this.settingsRepository.findFirst({ + where: { + instanceId: instance.instanceId, + }, + }); + + if (fallback?.typebotIdFallback) { + const findFallback = await this.botRepository.findFirst({ + where: { + id: fallback.typebotIdFallback, + }, + }); + + findBot = findFallback; + } else { + return; + } + } + + const settings = await this.prismaRepository.typebotSetting.findFirst({ + where: { + instanceId: instance.instanceId, + }, + }); + + const url = findBot?.url; + const typebot = findBot?.typebot; + let expire = findBot?.expire; + let keywordFinish = findBot?.keywordFinish; + let delayMessage = findBot?.delayMessage; + let unknownMessage = findBot?.unknownMessage; + let listeningFromMe = findBot?.listeningFromMe; + let stopBotFromMe = findBot?.stopBotFromMe; + let keepOpen = findBot?.keepOpen; + let debounceTime = findBot?.debounceTime; + let ignoreJids = findBot?.ignoreJids; + + if (expire === undefined || expire === null) expire = settings.expire; + if (keywordFinish === undefined || keywordFinish === null) keywordFinish = settings.keywordFinish; + if (delayMessage === undefined || delayMessage === null) delayMessage = settings.delayMessage; + if (unknownMessage === undefined || unknownMessage === null) unknownMessage = settings.unknownMessage; + if (listeningFromMe === undefined || listeningFromMe === null) listeningFromMe = settings.listeningFromMe; + if (stopBotFromMe === undefined || stopBotFromMe === null) stopBotFromMe = settings.stopBotFromMe; + if (keepOpen === undefined || keepOpen === null) keepOpen = settings.keepOpen; + if (debounceTime === undefined || debounceTime === null) debounceTime = settings.debounceTime; + if (ignoreJids === undefined || ignoreJids === null) ignoreJids = settings.ignoreJids; + + if (this.checkIgnoreJids(ignoreJids, remoteJid)) return; + + const key = msg.key as { + id: string; + remoteJid: string; + fromMe: boolean; + participant: string; + }; + + if (stopBotFromMe && key.fromMe && session) { + await this.sessionRepository.update({ + where: { + id: session.id, + }, + data: { + status: 'paused', + }, + }); + return; + } + + if (!listeningFromMe && key.fromMe) { + return; + } + + if (session && !session.awaitUser) { + return; + } + + if (debounceTime && debounceTime > 0) { + this.processDebounce(this.userMessageDebounce, content, remoteJid, debounceTime, async (debouncedContent) => { + await this.typebotService.processTypebot( + instanceData, + remoteJid, + msg, + session, + findBot, + url, + expire, + typebot, + keywordFinish, + delayMessage, + unknownMessage, + listeningFromMe, + stopBotFromMe, + keepOpen, + debouncedContent, + ); + }); + } else { + await this.typebotService.processTypebot( + instanceData, + remoteJid, + msg, + session, + findBot, + url, + expire, + typebot, + keywordFinish, + delayMessage, + unknownMessage, + listeningFromMe, + stopBotFromMe, + keepOpen, + content, + ); + } + + if (session && !session.awaitUser) return; + } catch (error) { + this.logger.error(error); + return; + } + } +} diff --git a/src/api/integrations/chatbot/typebot/dto/typebot.dto.ts b/src/api/integrations/chatbot/typebot/dto/typebot.dto.ts new file mode 100644 index 00000000..a7565236 --- /dev/null +++ b/src/api/integrations/chatbot/typebot/dto/typebot.dto.ts @@ -0,0 +1,40 @@ +import { TriggerOperator, TriggerType } from '@prisma/client'; + +export class PrefilledVariables { + remoteJid?: string; + pushName?: string; + messageType?: string; + additionalData?: { [key: string]: any }; +} + +export class TypebotDto { + enabled?: boolean; + description?: string; + url: string; + typebot?: string; + expire?: number; + keywordFinish?: string; + delayMessage?: number; + unknownMessage?: string; + listeningFromMe?: boolean; + stopBotFromMe?: boolean; + keepOpen?: boolean; + debounceTime?: number; + triggerType?: TriggerType; + triggerOperator?: TriggerOperator; + triggerValue?: string; + ignoreJids?: any; +} + +export class TypebotSettingDto { + expire?: number; + keywordFinish?: string; + delayMessage?: number; + unknownMessage?: string; + listeningFromMe?: boolean; + stopBotFromMe?: boolean; + keepOpen?: boolean; + debounceTime?: number; + typebotIdFallback?: string; + ignoreJids?: any; +} diff --git a/src/api/integrations/chatbot/typebot/routes/typebot.router.ts b/src/api/integrations/chatbot/typebot/routes/typebot.router.ts new file mode 100644 index 00000000..f556f94f --- /dev/null +++ b/src/api/integrations/chatbot/typebot/routes/typebot.router.ts @@ -0,0 +1,134 @@ +import { RouterBroker } from '@api/abstract/abstract.router'; +import { IgnoreJidDto } from '@api/dto/chatbot.dto'; +import { InstanceDto } from '@api/dto/instance.dto'; +import { TypebotDto, TypebotSettingDto } from '@api/integrations/chatbot/typebot/dto/typebot.dto'; +import { HttpStatus } from '@api/routes/index.router'; +import { typebotController } from '@api/server.module'; +import { + instanceSchema, + typebotIgnoreJidSchema, + typebotSchema, + typebotSettingSchema, + typebotStartSchema, + typebotStatusSchema, +} from '@validate/validate.schema'; +import { RequestHandler, Router } from 'express'; + +export class TypebotRouter extends RouterBroker { + constructor(...guards: RequestHandler[]) { + super(); + this.router + .post(this.routerPath('create'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: typebotSchema, + ClassRef: TypebotDto, + execute: (instance, data) => typebotController.createBot(instance, data), + }); + + res.status(HttpStatus.CREATED).json(response); + }) + .get(this.routerPath('find'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => typebotController.findBot(instance), + }); + + res.status(HttpStatus.OK).json(response); + }) + .get(this.routerPath('fetch/:typebotId'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => typebotController.fetchBot(instance, req.params.typebotId), + }); + + res.status(HttpStatus.OK).json(response); + }) + .put(this.routerPath('update/:typebotId'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: typebotSchema, + ClassRef: TypebotDto, + execute: (instance, data) => typebotController.updateBot(instance, req.params.typebotId, data), + }); + + res.status(HttpStatus.OK).json(response); + }) + .delete(this.routerPath('delete/:typebotId'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => typebotController.deleteBot(instance, req.params.typebotId), + }); + + res.status(HttpStatus.OK).json(response); + }) + .post(this.routerPath('settings'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: typebotSettingSchema, + ClassRef: TypebotSettingDto, + execute: (instance, data) => typebotController.settings(instance, data), + }); + + res.status(HttpStatus.OK).json(response); + }) + .get(this.routerPath('fetchSettings'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => typebotController.fetchSettings(instance), + }); + + res.status(HttpStatus.OK).json(response); + }) + .post(this.routerPath('start'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: typebotStartSchema, + ClassRef: InstanceDto, + execute: (instance, data) => typebotController.startBot(instance, data), + }); + + res.status(HttpStatus.OK).json(response); + }) + .post(this.routerPath('changeStatus'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: typebotStatusSchema, + ClassRef: InstanceDto, + execute: (instance, data) => typebotController.changeStatus(instance, data), + }); + + res.status(HttpStatus.OK).json(response); + }) + .get(this.routerPath('fetchSessions/:typebotId'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => typebotController.fetchSessions(instance, req.params.typebotId), + }); + + res.status(HttpStatus.OK).json(response); + }) + .post(this.routerPath('ignoreJid'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: typebotIgnoreJidSchema, + ClassRef: IgnoreJidDto, + execute: (instance, data) => typebotController.ignoreJid(instance, data), + }); + + res.status(HttpStatus.OK).json(response); + }); + } + + public readonly router: Router = Router(); +} diff --git a/src/api/integrations/chatbot/typebot/services/typebot.service.ts b/src/api/integrations/chatbot/typebot/services/typebot.service.ts new file mode 100644 index 00000000..f0e4dc7f --- /dev/null +++ b/src/api/integrations/chatbot/typebot/services/typebot.service.ts @@ -0,0 +1,953 @@ +import { PrismaRepository } from '@api/repository/repository.service'; +import { WAMonitoringService } from '@api/services/monitor.service'; +import { Auth, ConfigService, HttpServer, Typebot } from '@config/env.config'; +import { Logger } from '@config/logger.config'; +import { Instance, IntegrationSession, Message, Typebot as TypebotModel } from '@prisma/client'; +import { getConversationMessage } from '@utils/getConversationMessage'; +import { sendTelemetry } from '@utils/sendTelemetry'; +import axios from 'axios'; + +export class TypebotService { + constructor( + private readonly waMonitor: WAMonitoringService, + private readonly configService: ConfigService, + private readonly prismaRepository: PrismaRepository, + ) {} + + private readonly logger = new Logger('TypebotService'); + + public async createNewSession(instance: Instance, data: any) { + if (data.remoteJid === 'status@broadcast') return; + const id = Math.floor(Math.random() * 10000000000).toString(); + + try { + const version = this.configService.get('TYPEBOT').API_VERSION; + let url: string; + let reqData: {}; + if (version === 'latest') { + url = `${data.url}/api/v1/typebots/${data.typebot}/startChat`; + + reqData = { + prefilledVariables: { + ...data.prefilledVariables, + remoteJid: data.remoteJid, + pushName: data.pushName || data.prefilledVariables?.pushName || '', + instanceName: instance.name, + serverUrl: this.configService.get('SERVER').URL, + apiKey: this.configService.get('AUTHENTICATION').API_KEY.KEY, + ownerJid: instance.number, + }, + }; + } else { + url = `${data.url}/api/v1/sendMessage`; + + reqData = { + startParams: { + publicId: data.typebot, + prefilledVariables: { + ...data.prefilledVariables, + remoteJid: data.remoteJid, + pushName: data.pushName || data.prefilledVariables?.pushName || '', + instanceName: instance.name, + serverUrl: this.configService.get('SERVER').URL, + apiKey: this.configService.get('AUTHENTICATION').API_KEY.KEY, + ownerJid: instance.number, + }, + }, + }; + } + const request = await axios.post(url, reqData); + + let session = null; + if (request?.data?.sessionId) { + session = await this.prismaRepository.integrationSession.create({ + data: { + remoteJid: data.remoteJid, + pushName: data.pushName || '', + sessionId: `${id}-${request.data.sessionId}`, + status: 'opened', + parameters: { + ...data.prefilledVariables, + remoteJid: data.remoteJid, + pushName: data.pushName || '', + instanceName: instance.name, + serverUrl: this.configService.get('SERVER').URL, + apiKey: this.configService.get('AUTHENTICATION').API_KEY.KEY, + ownerJid: instance.number, + }, + awaitUser: false, + botId: data.botId, + instanceId: instance.id, + type: 'typebot', + }, + }); + } + return { ...request.data, session }; + } catch (error) { + this.logger.error(error); + return; + } + } + + public async sendWAMessage( + instance: Instance, + session: IntegrationSession, + settings: { + expire: number; + keywordFinish: string; + delayMessage: number; + unknownMessage: string; + listeningFromMe: boolean; + stopBotFromMe: boolean; + keepOpen: boolean; + }, + remoteJid: string, + messages: any, + input: any, + clientSideActions: any, + ) { + processMessages( + this.waMonitor.waInstances[instance.name], + session, + settings, + messages, + input, + clientSideActions, + applyFormatting, + this.prismaRepository, + ).catch((err) => { + console.error('Erro ao processar mensagens:', err); + }); + + function findItemAndGetSecondsToWait(array, targetId) { + if (!array) return null; + + for (const item of array) { + if (item.lastBubbleBlockId === targetId) { + return item.wait?.secondsToWaitFor; + } + } + return null; + } + + function applyFormatting(element) { + let text = ''; + + if (element.text) { + text += element.text; + } + + if (element.children && element.type !== 'a') { + for (const child of element.children) { + text += applyFormatting(child); + } + } + + if (element.type === 'p' && element.type !== 'inline-variable') { + text = text.trim() + '\n'; + } + + if (element.type === 'inline-variable') { + text = text.trim(); + } + + if (element.type === 'ol') { + text = + '\n' + + text + .split('\n') + .map((line, index) => (line ? `${index + 1}. ${line}` : '')) + .join('\n'); + } + + if (element.type === 'li') { + text = text + .split('\n') + .map((line) => (line ? ` ${line}` : '')) + .join('\n'); + } + + let formats = ''; + + if (element.bold) { + formats += '*'; + } + + if (element.italic) { + formats += '_'; + } + + if (element.underline) { + formats += '~'; + } + + let formattedText = `${formats}${text}${formats.split('').reverse().join('')}`; + + if (element.url) { + formattedText = element.children[0]?.text ? `[${formattedText}]\n(${element.url})` : `${element.url}`; + } + + return formattedText; + } + + async function processMessages( + instance: any, + session: IntegrationSession, + settings: { + expire: number; + keywordFinish: string; + delayMessage: number; + unknownMessage: string; + listeningFromMe: boolean; + stopBotFromMe: boolean; + keepOpen: boolean; + }, + messages: any, + input: any, + clientSideActions: any, + applyFormatting: any, + prismaRepository: PrismaRepository, + ) { + for (const message of messages) { + if (message.type === 'text') { + let formattedText = ''; + + for (const richText of message.content.richText) { + for (const element of richText.children) { + formattedText += applyFormatting(element); + } + formattedText += '\n'; + } + + formattedText = formattedText.replace(/\*\*/g, '').replace(/__/, '').replace(/~~/, '').replace(/\n$/, ''); + + formattedText = formattedText.replace(/\n$/, ''); + + if (formattedText.includes('[list]')) { + const listJson = { + number: remoteJid.split('@')[0], + title: '', + description: '', + buttonText: '', + footerText: '', + sections: [], + }; + + const titleMatch = formattedText.match(/\[title\]([\s\S]*?)(?=\[description\])/); + const descriptionMatch = formattedText.match(/\[description\]([\s\S]*?)(?=\[buttonText\])/); + const buttonTextMatch = formattedText.match(/\[buttonText\]([\s\S]*?)(?=\[footerText\])/); + const footerTextMatch = formattedText.match(/\[footerText\]([\s\S]*?)(?=\[menu\])/); + + if (titleMatch) listJson.title = titleMatch[1].trim(); + if (descriptionMatch) listJson.description = descriptionMatch[1].trim(); + if (buttonTextMatch) listJson.buttonText = buttonTextMatch[1].trim(); + if (footerTextMatch) listJson.footerText = footerTextMatch[1].trim(); + + const menuContent = formattedText.match(/\[menu\]([\s\S]*?)\[\/menu\]/)?.[1]; + if (menuContent) { + const sections = menuContent.match(/\[section\]([\s\S]*?)(?=\[section\]|\[\/section\]|\[\/menu\])/g); + if (sections) { + sections.forEach((section) => { + const sectionTitle = section.match(/title: (.*?)(?:\n|$)/)?.[1]?.trim(); + const rows = section.match(/\[row\]([\s\S]*?)(?=\[row\]|\[\/row\]|\[\/section\]|\[\/menu\])/g); + + const sectionData = { + title: sectionTitle, + rows: + rows?.map((row) => ({ + title: row.match(/title: (.*?)(?:\n|$)/)?.[1]?.trim(), + description: row.match(/description: (.*?)(?:\n|$)/)?.[1]?.trim(), + rowId: row.match(/rowId: (.*?)(?:\n|$)/)?.[1]?.trim(), + })) || [], + }; + + listJson.sections.push(sectionData); + }); + } + } + + await instance.listMessage(listJson); + } else if (formattedText.includes('[buttons]')) { + const buttonJson = { + number: remoteJid.split('@')[0], + thumbnailUrl: undefined, + title: '', + description: '', + footer: '', + buttons: [], + }; + + const thumbnailUrlMatch = formattedText.match(/\[thumbnailUrl\]([\s\S]*?)(?=\[title\])/); + const titleMatch = formattedText.match(/\[title\]([\s\S]*?)(?=\[description\])/); + const descriptionMatch = formattedText.match(/\[description\]([\s\S]*?)(?=\[footer\])/); + const footerMatch = formattedText.match(/\[footer\]([\s\S]*?)(?=\[(?:reply|pix|copy|call|url))/); + + if (titleMatch) buttonJson.title = titleMatch[1].trim(); + if (thumbnailUrlMatch) buttonJson.thumbnailUrl = thumbnailUrlMatch[1].trim(); + if (descriptionMatch) buttonJson.description = descriptionMatch[1].trim(); + if (footerMatch) buttonJson.footer = footerMatch[1].trim(); + + const buttonTypes = { + reply: /\[reply\]([\s\S]*?)(?=\[(?:reply|pix|copy|call|url)|$)/g, + pix: /\[pix\]([\s\S]*?)(?=\[(?:reply|pix|copy|call|url)|$)/g, + copy: /\[copy\]([\s\S]*?)(?=\[(?:reply|pix|copy|call|url)|$)/g, + call: /\[call\]([\s\S]*?)(?=\[(?:reply|pix|copy|call|url)|$)/g, + url: /\[url\]([\s\S]*?)(?=\[(?:reply|pix|copy|call|url)|$)/g, + }; + + for (const [type, pattern] of Object.entries(buttonTypes)) { + let match; + while ((match = pattern.exec(formattedText)) !== null) { + const content = match[1].trim(); + const button: any = { type }; + + switch (type) { + case 'pix': + button.currency = content.match(/currency: (.*?)(?:\n|$)/)?.[1]?.trim(); + button.name = content.match(/name: (.*?)(?:\n|$)/)?.[1]?.trim(); + button.keyType = content.match(/keyType: (.*?)(?:\n|$)/)?.[1]?.trim(); + button.key = content.match(/key: (.*?)(?:\n|$)/)?.[1]?.trim(); + break; + + case 'reply': + button.displayText = content.match(/displayText: (.*?)(?:\n|$)/)?.[1]?.trim(); + button.id = content.match(/id: (.*?)(?:\n|$)/)?.[1]?.trim(); + break; + + case 'copy': + button.displayText = content.match(/displayText: (.*?)(?:\n|$)/)?.[1]?.trim(); + button.copyCode = content.match(/copyCode: (.*?)(?:\n|$)/)?.[1]?.trim(); + break; + + case 'call': + button.displayText = content.match(/displayText: (.*?)(?:\n|$)/)?.[1]?.trim(); + button.phoneNumber = content.match(/phone: (.*?)(?:\n|$)/)?.[1]?.trim(); + break; + + case 'url': + button.displayText = content.match(/displayText: (.*?)(?:\n|$)/)?.[1]?.trim(); + button.url = content.match(/url: (.*?)(?:\n|$)/)?.[1]?.trim(); + break; + } + + if (Object.keys(button).length > 1) { + buttonJson.buttons.push(button); + } + } + } + + await instance.buttonMessage(buttonJson); + } else { + await instance.textMessage( + { + number: remoteJid.split('@')[0], + delay: settings?.delayMessage || 1000, + text: formattedText, + }, + false, + ); + } + + sendTelemetry('/message/sendText'); + } + + if (message.type === 'image') { + await instance.mediaMessage( + { + number: remoteJid.split('@')[0], + delay: settings?.delayMessage || 1000, + mediatype: 'image', + media: message.content.url, + }, + null, + false, + ); + + sendTelemetry('/message/sendMedia'); + } + + if (message.type === 'video') { + await instance.mediaMessage( + { + number: remoteJid.split('@')[0], + delay: settings?.delayMessage || 1000, + mediatype: 'video', + media: message.content.url, + }, + null, + false, + ); + + sendTelemetry('/message/sendMedia'); + } + + if (message.type === 'audio') { + await instance.audioWhatsapp( + { + number: remoteJid.split('@')[0], + delay: settings?.delayMessage || 1000, + encoding: true, + audio: message.content.url, + }, + false, + ); + + sendTelemetry('/message/sendWhatsAppAudio'); + } + + const wait = findItemAndGetSecondsToWait(clientSideActions, message.id); + + if (wait) { + await new Promise((resolve) => setTimeout(resolve, wait * 1000)); + } + } + + console.log('input', input); + if (input) { + if (input.type === 'choice input') { + let formattedText = ''; + + const items = input.items; + + for (const item of items) { + formattedText += `▶️ ${item.content}\n`; + } + + formattedText = formattedText.replace(/\n$/, ''); + + if (formattedText.includes('[list]')) { + const listJson = { + number: remoteJid.split('@')[0], + title: '', + description: '', + buttonText: '', + footerText: '', + sections: [], + }; + + const titleMatch = formattedText.match(/\[title\]([\s\S]*?)(?=\[description\])/); + const descriptionMatch = formattedText.match(/\[description\]([\s\S]*?)(?=\[buttonText\])/); + const buttonTextMatch = formattedText.match(/\[buttonText\]([\s\S]*?)(?=\[footerText\])/); + const footerTextMatch = formattedText.match(/\[footerText\]([\s\S]*?)(?=\[menu\])/); + + if (titleMatch) listJson.title = titleMatch[1].trim(); + if (descriptionMatch) listJson.description = descriptionMatch[1].trim(); + if (buttonTextMatch) listJson.buttonText = buttonTextMatch[1].trim(); + if (footerTextMatch) listJson.footerText = footerTextMatch[1].trim(); + + const menuContent = formattedText.match(/\[menu\]([\s\S]*?)\[\/menu\]/)?.[1]; + if (menuContent) { + const sections = menuContent.match(/\[section\]([\s\S]*?)(?=\[section\]|\[\/section\]|\[\/menu\])/g); + if (sections) { + sections.forEach((section) => { + const sectionTitle = section.match(/title: (.*?)(?:\n|$)/)?.[1]?.trim(); + const rows = section.match(/\[row\]([\s\S]*?)(?=\[row\]|\[\/row\]|\[\/section\]|\[\/menu\])/g); + + const sectionData = { + title: sectionTitle, + rows: + rows?.map((row) => ({ + title: row.match(/title: (.*?)(?:\n|$)/)?.[1]?.trim(), + description: row.match(/description: (.*?)(?:\n|$)/)?.[1]?.trim(), + rowId: row.match(/rowId: (.*?)(?:\n|$)/)?.[1]?.trim(), + })) || [], + }; + + listJson.sections.push(sectionData); + }); + } + } + + await instance.listMessage(listJson); + } else if (formattedText.includes('[buttons]')) { + const buttonJson = { + number: remoteJid.split('@')[0], + thumbnailUrl: undefined, + title: '', + description: '', + footer: '', + buttons: [], + }; + + const thumbnailUrlMatch = formattedText.match(/\[thumbnailUrl\]([\s\S]*?)(?=\[title\])/); + const titleMatch = formattedText.match(/\[title\]([\s\S]*?)(?=\[description\])/); + const descriptionMatch = formattedText.match(/\[description\]([\s\S]*?)(?=\[footer\])/); + const footerMatch = formattedText.match(/\[footer\]([\s\S]*?)(?=\[(?:reply|pix|copy|call|url))/); + + if (titleMatch) buttonJson.title = titleMatch[1].trim(); + if (thumbnailUrlMatch) buttonJson.thumbnailUrl = thumbnailUrlMatch[1].trim(); + if (descriptionMatch) buttonJson.description = descriptionMatch[1].trim(); + if (footerMatch) buttonJson.footer = footerMatch[1].trim(); + + const buttonTypes = { + reply: /\[reply\]([\s\S]*?)(?=\[(?:reply|pix|copy|call|url)|$)/g, + pix: /\[pix\]([\s\S]*?)(?=\[(?:reply|pix|copy|call|url)|$)/g, + copy: /\[copy\]([\s\S]*?)(?=\[(?:reply|pix|copy|call|url)|$)/g, + call: /\[call\]([\s\S]*?)(?=\[(?:reply|pix|copy|call|url)|$)/g, + url: /\[url\]([\s\S]*?)(?=\[(?:reply|pix|copy|call|url)|$)/g, + }; + + for (const [type, pattern] of Object.entries(buttonTypes)) { + let match; + while ((match = pattern.exec(formattedText)) !== null) { + const content = match[1].trim(); + const button: any = { type }; + + switch (type) { + case 'pix': + button.currency = content.match(/currency: (.*?)(?:\n|$)/)?.[1]?.trim(); + button.name = content.match(/name: (.*?)(?:\n|$)/)?.[1]?.trim(); + button.keyType = content.match(/keyType: (.*?)(?:\n|$)/)?.[1]?.trim(); + button.key = content.match(/key: (.*?)(?:\n|$)/)?.[1]?.trim(); + break; + + case 'reply': + button.displayText = content.match(/displayText: (.*?)(?:\n|$)/)?.[1]?.trim(); + button.id = content.match(/id: (.*?)(?:\n|$)/)?.[1]?.trim(); + break; + + case 'copy': + button.displayText = content.match(/displayText: (.*?)(?:\n|$)/)?.[1]?.trim(); + button.copyCode = content.match(/copyCode: (.*?)(?:\n|$)/)?.[1]?.trim(); + break; + + case 'call': + button.displayText = content.match(/displayText: (.*?)(?:\n|$)/)?.[1]?.trim(); + button.phoneNumber = content.match(/phone: (.*?)(?:\n|$)/)?.[1]?.trim(); + break; + + case 'url': + button.displayText = content.match(/displayText: (.*?)(?:\n|$)/)?.[1]?.trim(); + button.url = content.match(/url: (.*?)(?:\n|$)/)?.[1]?.trim(); + break; + } + + if (Object.keys(button).length > 1) { + buttonJson.buttons.push(button); + } + } + } + + await instance.buttonMessage(buttonJson); + } else { + await instance.textMessage( + { + number: remoteJid.split('@')[0], + delay: settings?.delayMessage || 1000, + text: formattedText, + }, + false, + ); + } + + sendTelemetry('/message/sendText'); + } + + await prismaRepository.integrationSession.update({ + where: { + id: session.id, + }, + data: { + awaitUser: true, + }, + }); + } else { + if (!settings?.keepOpen) { + await prismaRepository.integrationSession.deleteMany({ + where: { + id: session.id, + }, + }); + } else { + await prismaRepository.integrationSession.update({ + where: { + id: session.id, + }, + data: { + status: 'closed', + }, + }); + } + } + } + } + + public async processTypebot( + instance: Instance, + remoteJid: string, + msg: Message, + session: IntegrationSession, + findTypebot: TypebotModel, + url: string, + expire: number, + typebot: string, + keywordFinish: string, + delayMessage: number, + unknownMessage: string, + listeningFromMe: boolean, + stopBotFromMe: boolean, + keepOpen: boolean, + content: string, + prefilledVariables?: any, + ) { + if (session && expire && expire > 0) { + const now = Date.now(); + + const sessionUpdatedAt = new Date(session.updatedAt).getTime(); + + const diff = now - sessionUpdatedAt; + + const diffInMinutes = Math.floor(diff / 1000 / 60); + + if (diffInMinutes > expire) { + if (keepOpen) { + await this.prismaRepository.integrationSession.update({ + where: { + id: session.id, + }, + data: { + status: 'closed', + }, + }); + } else { + await this.prismaRepository.integrationSession.deleteMany({ + where: { + botId: findTypebot.id, + remoteJid: remoteJid, + }, + }); + } + + const data = await this.createNewSession(instance, { + enabled: findTypebot?.enabled, + url: url, + typebot: typebot, + expire: expire, + keywordFinish: keywordFinish, + delayMessage: delayMessage, + unknownMessage: unknownMessage, + listeningFromMe: listeningFromMe, + remoteJid: remoteJid, + pushName: msg.pushName, + botId: findTypebot.id, + prefilledVariables: prefilledVariables, + }); + + if (data.session) { + session = data.session; + } + + if (data.messages.length === 0) { + const content = getConversationMessage(msg.message); + + if (!content) { + if (unknownMessage) { + this.waMonitor.waInstances[instance.name].textMessage( + { + number: remoteJid.split('@')[0], + delay: delayMessage || 1000, + text: unknownMessage, + }, + false, + ); + + sendTelemetry('/message/sendText'); + } + return; + } + + if (keywordFinish && content.toLowerCase() === keywordFinish.toLowerCase()) { + if (keepOpen) { + await this.prismaRepository.integrationSession.update({ + where: { + id: session.id, + }, + data: { + status: 'closed', + }, + }); + } else { + await this.prismaRepository.integrationSession.deleteMany({ + where: { + botId: findTypebot.id, + remoteJid: remoteJid, + }, + }); + } + return; + } + + try { + const version = this.configService.get('TYPEBOT').API_VERSION; + let urlTypebot: string; + let reqData: {}; + if (version === 'latest') { + urlTypebot = `${url}/api/v1/sessions/${data.sessionId}/continueChat`; + reqData = { + message: content, + }; + } else { + urlTypebot = `${url}/api/v1/sendMessage`; + reqData = { + message: content, + sessionId: data.sessionId, + }; + } + + const request = await axios.post(urlTypebot, reqData); + + await this.sendWAMessage( + instance, + session, + { + expire: expire, + keywordFinish: keywordFinish, + delayMessage: delayMessage, + unknownMessage: unknownMessage, + listeningFromMe: listeningFromMe, + stopBotFromMe: stopBotFromMe, + keepOpen: keepOpen, + }, + remoteJid, + request.data.messages, + request.data.input, + request.data.clientSideActions, + ); + } catch (error) { + this.logger.error(error); + return; + } + } + + await this.sendWAMessage( + instance, + session, + { + expire: expire, + keywordFinish: keywordFinish, + delayMessage: delayMessage, + unknownMessage: unknownMessage, + listeningFromMe: listeningFromMe, + stopBotFromMe: stopBotFromMe, + keepOpen: keepOpen, + }, + remoteJid, + data.messages, + data.input, + data.clientSideActions, + ); + + return; + } + } + + if (session && session.status !== 'opened') { + return; + } + + if (!session) { + const data = await this.createNewSession(instance, { + enabled: findTypebot?.enabled, + url: url, + typebot: typebot, + expire: expire, + keywordFinish: keywordFinish, + delayMessage: delayMessage, + unknownMessage: unknownMessage, + listeningFromMe: listeningFromMe, + remoteJid: remoteJid, + pushName: msg?.pushName, + botId: findTypebot.id, + prefilledVariables: prefilledVariables, + }); + + if (data?.session) { + session = data.session; + } + + await this.sendWAMessage( + instance, + session, + { + expire: expire, + keywordFinish: keywordFinish, + delayMessage: delayMessage, + unknownMessage: unknownMessage, + listeningFromMe: listeningFromMe, + stopBotFromMe: stopBotFromMe, + keepOpen: keepOpen, + }, + remoteJid, + data?.messages, + data?.input, + data?.clientSideActions, + ); + + if (data.messages.length === 0) { + if (!content) { + if (unknownMessage) { + this.waMonitor.waInstances[instance.name].textMessage( + { + number: remoteJid.split('@')[0], + delay: delayMessage || 1000, + text: unknownMessage, + }, + false, + ); + + sendTelemetry('/message/sendText'); + } + return; + } + + if (keywordFinish && content.toLowerCase() === keywordFinish.toLowerCase()) { + if (keepOpen) { + await this.prismaRepository.integrationSession.update({ + where: { + id: session.id, + }, + data: { + status: 'closed', + }, + }); + } else { + await this.prismaRepository.integrationSession.deleteMany({ + where: { + botId: findTypebot.id, + remoteJid: remoteJid, + }, + }); + } + + return; + } + + let request: any; + try { + const version = this.configService.get('TYPEBOT').API_VERSION; + let urlTypebot: string; + let reqData: {}; + if (version === 'latest') { + urlTypebot = `${url}/api/v1/sessions/${data.sessionId}/continueChat`; + reqData = { + message: content, + }; + } else { + urlTypebot = `${url}/api/v1/sendMessage`; + reqData = { + message: content, + sessionId: data.sessionId, + }; + } + request = await axios.post(urlTypebot, reqData); + + await this.sendWAMessage( + instance, + session, + { + expire: expire, + keywordFinish: keywordFinish, + delayMessage: delayMessage, + unknownMessage: unknownMessage, + listeningFromMe: listeningFromMe, + stopBotFromMe: stopBotFromMe, + keepOpen: keepOpen, + }, + remoteJid, + request.data.messages, + request.data.input, + request.data.clientSideActions, + ); + } catch (error) { + this.logger.error(error); + return; + } + } + return; + } + + await this.prismaRepository.integrationSession.update({ + where: { + id: session.id, + }, + data: { + status: 'opened', + awaitUser: false, + }, + }); + + if (!content) { + if (unknownMessage) { + this.waMonitor.waInstances[instance.name].textMessage( + { + number: remoteJid.split('@')[0], + delay: delayMessage || 1000, + text: unknownMessage, + }, + false, + ); + + sendTelemetry('/message/sendText'); + } + return; + } + + if (keywordFinish && content.toLowerCase() === keywordFinish.toLowerCase()) { + if (keepOpen) { + await this.prismaRepository.integrationSession.update({ + where: { + id: session.id, + }, + data: { + status: 'closed', + }, + }); + } else { + await this.prismaRepository.integrationSession.deleteMany({ + where: { + botId: findTypebot.id, + remoteJid: remoteJid, + }, + }); + } + return; + } + + const version = this.configService.get('TYPEBOT').API_VERSION; + let urlTypebot: string; + let reqData: {}; + if (version === 'latest') { + urlTypebot = `${url}/api/v1/sessions/${session.sessionId.split('-')[1]}/continueChat`; + reqData = { + message: content, + }; + } else { + urlTypebot = `${url}/api/v1/sendMessage`; + reqData = { + message: content, + sessionId: session.sessionId.split('-')[1], + }; + } + const request = await axios.post(urlTypebot, reqData); + + await this.sendWAMessage( + instance, + session, + { + expire: expire, + keywordFinish: keywordFinish, + delayMessage: delayMessage, + unknownMessage: unknownMessage, + listeningFromMe: listeningFromMe, + stopBotFromMe: stopBotFromMe, + keepOpen: keepOpen, + }, + remoteJid, + request?.data?.messages, + request?.data?.input, + request?.data?.clientSideActions, + ); + + return; + } +} diff --git a/src/api/integrations/chatbot/typebot/validate/typebot.schema.ts b/src/api/integrations/chatbot/typebot/validate/typebot.schema.ts new file mode 100644 index 00000000..02dc74e8 --- /dev/null +++ b/src/api/integrations/chatbot/typebot/validate/typebot.schema.ts @@ -0,0 +1,97 @@ +import { JSONSchema7 } from 'json-schema'; +import { v4 } from 'uuid'; + +const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => { + const properties = {}; + propertyNames.forEach( + (property) => + (properties[property] = { + minLength: 1, + description: `The "${property}" cannot be empty`, + }), + ); + return { + if: { + propertyNames: { + enum: [...propertyNames], + }, + }, + then: { properties }, + }; +}; + +export const typebotSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + enabled: { type: 'boolean' }, + description: { type: 'string' }, + url: { type: 'string' }, + typebot: { type: 'string' }, + triggerType: { type: 'string', enum: ['all', 'keyword', 'none', 'advanced'] }, + triggerOperator: { type: 'string', enum: ['equals', 'contains', 'startsWith', 'endsWith', 'regex'] }, + triggerValue: { type: 'string' }, + expire: { type: 'integer' }, + keywordFinish: { type: 'string' }, + delayMessage: { type: 'integer' }, + unknownMessage: { type: 'string' }, + listeningFromMe: { type: 'boolean' }, + stopBotFromMe: { type: 'boolean' }, + ignoreJids: { type: 'array', items: { type: 'string' } }, + }, + required: ['enabled', 'url', 'typebot', 'triggerType'], + ...isNotEmpty('enabled', 'url', 'typebot', 'triggerType'), +}; + +export const typebotStatusSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + remoteJid: { type: 'string' }, + status: { type: 'string', enum: ['opened', 'closed', 'paused', 'delete'] }, + }, + required: ['remoteJid', 'status'], + ...isNotEmpty('remoteJid', 'status'), +}; + +export const typebotStartSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + remoteJid: { type: 'string' }, + url: { type: 'string' }, + typebot: { type: 'string' }, + }, + required: ['remoteJid', 'url', 'typebot'], + ...isNotEmpty('remoteJid', 'url', 'typebot'), +}; + +export const typebotSettingSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + expire: { type: 'integer' }, + keywordFinish: { type: 'string' }, + delayMessage: { type: 'integer' }, + unknownMessage: { type: 'string' }, + listeningFromMe: { type: 'boolean' }, + stopBotFromMe: { type: 'boolean' }, + keepOpen: { type: 'boolean' }, + debounceTime: { type: 'integer' }, + typebotIdFallback: { type: 'string' }, + ignoreJids: { type: 'array', items: { type: 'string' } }, + }, + required: ['expire', 'keywordFinish', 'delayMessage', 'unknownMessage', 'listeningFromMe', 'stopBotFromMe'], + ...isNotEmpty('expire', 'keywordFinish', 'delayMessage', 'unknownMessage', 'listeningFromMe', 'stopBotFromMe'), +}; + +export const typebotIgnoreJidSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + remoteJid: { type: 'string' }, + action: { type: 'string', enum: ['add', 'remove'] }, + }, + required: ['remoteJid', 'action'], + ...isNotEmpty('remoteJid', 'action'), +}; diff --git a/src/api/integrations/chatwoot/controllers/chatwoot.controller.ts b/src/api/integrations/chatwoot/controllers/chatwoot.controller.ts deleted file mode 100644 index c6799ea5..00000000 --- a/src/api/integrations/chatwoot/controllers/chatwoot.controller.ts +++ /dev/null @@ -1,112 +0,0 @@ -import { isURL } from 'class-validator'; - -import { CacheEngine } from '../../../../cache/cacheengine'; -import { ConfigService, HttpServer } from '../../../../config/env.config'; -import { Logger } from '../../../../config/logger.config'; -import { BadRequestException } from '../../../../exceptions'; -import { InstanceDto } from '../../../dto/instance.dto'; -import { RepositoryBroker } from '../../../repository/repository.manager'; -import { waMonitor } from '../../../server.module'; -import { CacheService } from '../../../services/cache.service'; -import { ChatwootDto } from '../dto/chatwoot.dto'; -import { ChatwootService } from '../services/chatwoot.service'; - -const logger = new Logger('ChatwootController'); - -export class ChatwootController { - constructor( - private readonly chatwootService: ChatwootService, - private readonly configService: ConfigService, - private readonly repository: RepositoryBroker, - ) {} - - public async createChatwoot(instance: InstanceDto, data: ChatwootDto) { - logger.verbose('requested createChatwoot from ' + instance.instanceName + ' instance'); - - if (data.enabled) { - if (!isURL(data.url, { require_tld: false })) { - throw new BadRequestException('url is not valid'); - } - - if (!data.account_id) { - throw new BadRequestException('account_id is required'); - } - - if (!data.token) { - throw new BadRequestException('token is required'); - } - - if (data.sign_msg !== true && data.sign_msg !== false) { - throw new BadRequestException('sign_msg is required'); - } - if (data.sign_msg === false) data.sign_delimiter = null; - } - - if (!data.enabled) { - logger.verbose('chatwoot disabled'); - data.account_id = ''; - data.token = ''; - data.url = ''; - data.sign_msg = false; - data.sign_delimiter = null; - data.reopen_conversation = false; - data.conversation_pending = false; - data.import_contacts = false; - data.import_messages = false; - data.merge_brazil_contacts = false; - data.days_limit_import_messages = 0; - data.auto_create = false; - data.name_inbox = ''; - } - - if (!data.name_inbox || data.name_inbox === '') { - data.name_inbox = instance.instanceName; - } - - const result = await this.chatwootService.create(instance, data); - - const urlServer = this.configService.get('SERVER').URL; - - const response = { - ...result, - webhook_url: `${urlServer}/chatwoot/webhook/${encodeURIComponent(instance.instanceName)}`, - }; - - return response; - } - - public async findChatwoot(instance: InstanceDto) { - logger.verbose('requested findChatwoot from ' + instance.instanceName + ' instance'); - const result = await this.chatwootService.find(instance); - - const urlServer = this.configService.get('SERVER').URL; - - if (Object.keys(result || {}).length === 0) { - return { - enabled: false, - url: '', - account_id: '', - token: '', - sign_msg: false, - name_inbox: '', - webhook_url: '', - }; - } - - const response = { - ...result, - webhook_url: `${urlServer}/chatwoot/webhook/${encodeURIComponent(instance.instanceName)}`, - }; - - return response; - } - - public async receiveWebhook(instance: InstanceDto, data: any) { - logger.verbose('requested receiveWebhook from ' + instance.instanceName + ' instance'); - - const chatwootCache = new CacheService(new CacheEngine(this.configService, ChatwootService.name).getEngine()); - const chatwootService = new ChatwootService(waMonitor, this.configService, this.repository, chatwootCache); - - return chatwootService.receiveWebhook(instance, data); - } -} diff --git a/src/api/integrations/chatwoot/dto/chatwoot.dto.ts b/src/api/integrations/chatwoot/dto/chatwoot.dto.ts deleted file mode 100644 index a6786db2..00000000 --- a/src/api/integrations/chatwoot/dto/chatwoot.dto.ts +++ /dev/null @@ -1,17 +0,0 @@ -export class ChatwootDto { - enabled?: boolean; - account_id?: string; - token?: string; - url?: string; - name_inbox?: string; - sign_msg?: boolean; - sign_delimiter?: string; - number?: string; - reopen_conversation?: boolean; - conversation_pending?: boolean; - merge_brazil_contacts?: boolean; - import_contacts?: boolean; - import_messages?: boolean; - days_limit_import_messages?: number; - auto_create?: boolean; -} diff --git a/src/api/integrations/chatwoot/models/chatwoot.model.ts b/src/api/integrations/chatwoot/models/chatwoot.model.ts deleted file mode 100644 index 423fbb10..00000000 --- a/src/api/integrations/chatwoot/models/chatwoot.model.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { Schema } from 'mongoose'; - -import { dbserver } from '../../../../libs/db.connect'; - -export class ChatwootRaw { - _id?: string; - enabled?: boolean; - account_id?: string; - token?: string; - url?: string; - name_inbox?: string; - sign_msg?: boolean; - sign_delimiter?: string; - number?: string; - reopen_conversation?: boolean; - conversation_pending?: boolean; - merge_brazil_contacts?: boolean; - import_contacts?: boolean; - import_messages?: boolean; - days_limit_import_messages?: number; -} - -const chatwootSchema = new Schema({ - _id: { type: String, _id: true }, - enabled: { type: Boolean, required: true }, - account_id: { type: String, required: true }, - token: { type: String, required: true }, - url: { type: String, required: true }, - name_inbox: { type: String, required: true }, - sign_msg: { type: Boolean, required: true }, - sign_delimiter: { type: String, required: false }, - number: { type: String, required: true }, - reopen_conversation: { type: Boolean, required: true }, - conversation_pending: { type: Boolean, required: true }, - merge_brazil_contacts: { type: Boolean, required: true }, - import_contacts: { type: Boolean, required: true }, - import_messages: { type: Boolean, required: true }, - days_limit_import_messages: { type: Number, required: true }, -}); - -export const ChatwootModel = dbserver?.model(ChatwootRaw.name, chatwootSchema, 'chatwoot'); -export type IChatwootModel = typeof ChatwootModel; diff --git a/src/api/integrations/chatwoot/repository/chatwoot.repository.ts b/src/api/integrations/chatwoot/repository/chatwoot.repository.ts deleted file mode 100644 index 820f54af..00000000 --- a/src/api/integrations/chatwoot/repository/chatwoot.repository.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { readFileSync } from 'fs'; -import { join } from 'path'; - -import { ConfigService } from '../../../../config/env.config'; -import { Logger } from '../../../../config/logger.config'; -import { IInsert, Repository } from '../../../abstract/abstract.repository'; -import { ChatwootRaw, IChatwootModel } from '../../../models'; - -export class ChatwootRepository extends Repository { - constructor(private readonly chatwootModel: IChatwootModel, private readonly configService: ConfigService) { - super(configService); - } - - private readonly logger = new Logger('ChatwootRepository'); - - public async create(data: ChatwootRaw, instance: string): Promise { - try { - this.logger.verbose('creating chatwoot'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('saving chatwoot to db'); - const insert = await this.chatwootModel.replaceOne({ _id: instance }, { ...data }, { upsert: true }); - - this.logger.verbose('chatwoot saved to db: ' + insert.modifiedCount + ' chatwoot'); - return { insertCount: insert.modifiedCount }; - } - - this.logger.verbose('saving chatwoot to store'); - - this.writeStore({ - path: join(this.storePath, 'chatwoot'), - fileName: instance, - data, - }); - - this.logger.verbose('chatwoot saved to store in path: ' + join(this.storePath, 'chatwoot') + '/' + instance); - - this.logger.verbose('chatwoot created'); - return { insertCount: 1 }; - } catch (error) { - return error; - } - } - - public async find(instance: string): Promise { - try { - this.logger.verbose('finding chatwoot'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding chatwoot in db'); - return await this.chatwootModel.findOne({ _id: instance }); - } - - this.logger.verbose('finding chatwoot in store'); - return JSON.parse( - readFileSync(join(this.storePath, 'chatwoot', instance + '.json'), { - encoding: 'utf-8', - }), - ) as ChatwootRaw; - } catch (error) { - return {}; - } - } -} diff --git a/src/api/integrations/chatwoot/validate/chatwoot.schema.ts b/src/api/integrations/chatwoot/validate/chatwoot.schema.ts deleted file mode 100644 index 05995a2c..00000000 --- a/src/api/integrations/chatwoot/validate/chatwoot.schema.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { JSONSchema7 } from 'json-schema'; -import { v4 } from 'uuid'; - -const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => { - const properties = {}; - propertyNames.forEach( - (property) => - (properties[property] = { - minLength: 1, - description: `The "${property}" cannot be empty`, - }), - ); - return { - if: { - propertyNames: { - enum: [...propertyNames], - }, - }, - then: { properties }, - }; -}; - -export const chatwootSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - enabled: { type: 'boolean', enum: [true, false] }, - account_id: { type: 'string' }, - token: { type: 'string' }, - url: { type: 'string' }, - sign_msg: { type: 'boolean', enum: [true, false] }, - sign_delimiter: { type: ['string', 'null'] }, - name_inbox: { type: ['string', 'null'] }, - reopen_conversation: { type: 'boolean', enum: [true, false] }, - conversation_pending: { type: 'boolean', enum: [true, false] }, - auto_create: { type: 'boolean', enum: [true, false] }, - import_contacts: { type: 'boolean', enum: [true, false] }, - merge_brazil_contacts: { type: 'boolean', enum: [true, false] }, - import_messages: { type: 'boolean', enum: [true, false] }, - days_limit_import_messages: { type: 'number' }, - }, - required: ['enabled', 'account_id', 'token', 'url', 'sign_msg', 'reopen_conversation', 'conversation_pending'], - ...isNotEmpty('account_id', 'token', 'url', 'sign_msg', 'reopen_conversation', 'conversation_pending'), -}; diff --git a/src/api/integrations/event/event.controller.ts b/src/api/integrations/event/event.controller.ts new file mode 100644 index 00000000..2e6a2330 --- /dev/null +++ b/src/api/integrations/event/event.controller.ts @@ -0,0 +1,155 @@ +import { EventDto } from '@api/integrations/event/event.dto'; +import { PrismaRepository } from '@api/repository/repository.service'; +import { WAMonitoringService } from '@api/services/monitor.service'; +import { wa } from '@api/types/wa.types'; + +export type EmitData = { + instanceName: string; + origin: string; + event: string; + data: any; + serverUrl: string; + dateTime: string; + sender: string; + apiKey?: string; + local?: boolean; + integration?: string[]; +}; + +export interface EventControllerInterface { + set(instanceName: string, data: any): Promise; + get(instanceName: string): Promise; + emit({ instanceName, origin, event, data, serverUrl, dateTime, sender, apiKey, local }: EmitData): Promise; +} + +export class EventController { + public prismaRepository: PrismaRepository; + protected waMonitor: WAMonitoringService; + private integrationStatus: boolean; + private integrationName: string; + + constructor( + prismaRepository: PrismaRepository, + waMonitor: WAMonitoringService, + integrationStatus: boolean, + integrationName: string, + ) { + this.prisma = prismaRepository; + this.monitor = waMonitor; + this.status = integrationStatus; + this.name = integrationName; + } + + public set prisma(prisma: PrismaRepository) { + this.prismaRepository = prisma; + } + + public get prisma() { + return this.prismaRepository; + } + + public set monitor(waMonitor: WAMonitoringService) { + this.waMonitor = waMonitor; + } + + public get monitor() { + return this.waMonitor; + } + + public set name(name: string) { + this.integrationName = name; + } + + public get name() { + return this.integrationName; + } + + public set status(status: boolean) { + this.integrationStatus = status; + } + + public get status() { + return this.integrationStatus; + } + + public async set(instanceName: string, data: EventDto): Promise { + if (!this.status) { + return; + } + + if (!data[this.name]?.enabled) { + data[this.name].events = []; + } else { + if (0 === data[this.name].events.length) { + data[this.name].events = EventController.events; + } + } + + return this.prisma[this.name].upsert({ + where: { + instanceId: this.monitor.waInstances[instanceName].instanceId, + }, + update: { + enabled: data[this.name]?.enabled, + events: data[this.name].events, + }, + create: { + enabled: data[this.name]?.enabled, + events: data[this.name].events, + instanceId: this.monitor.waInstances[instanceName].instanceId, + }, + }); + } + + public async get(instanceName: string): Promise { + if (!this.status) { + return; + } + + if (undefined === this.monitor.waInstances[instanceName]) { + return null; + } + + const data = await this.prisma[this.name].findUnique({ + where: { + instanceId: this.monitor.waInstances[instanceName].instanceId, + }, + }); + + if (!data) { + return null; + } + + return data; + } + + public static readonly events = [ + 'APPLICATION_STARTUP', + 'QRCODE_UPDATED', + 'MESSAGES_SET', + 'MESSAGES_UPSERT', + 'MESSAGES_EDITED', + 'MESSAGES_UPDATE', + 'MESSAGES_DELETE', + 'SEND_MESSAGE', + 'CONTACTS_SET', + 'CONTACTS_UPSERT', + 'CONTACTS_UPDATE', + 'PRESENCE_UPDATE', + 'CHATS_SET', + 'CHATS_UPSERT', + 'CHATS_UPDATE', + 'CHATS_DELETE', + 'GROUPS_UPSERT', + 'GROUP_UPDATE', + 'GROUP_PARTICIPANTS_UPDATE', + 'CONNECTION_UPDATE', + 'LABELS_EDIT', + 'LABELS_ASSOCIATION', + 'CALL', + 'TYPEBOT_START', + 'TYPEBOT_CHANGE_STATUS', + 'REMOVE_INSTANCE', + 'LOGOUT_INSTANCE', + ]; +} diff --git a/src/api/integrations/event/event.dto.ts b/src/api/integrations/event/event.dto.ts new file mode 100644 index 00000000..eaa7cc40 --- /dev/null +++ b/src/api/integrations/event/event.dto.ts @@ -0,0 +1,76 @@ +import { Constructor } from '@api/integrations/integration.dto'; +import { JsonValue } from '@prisma/client/runtime/library'; + +export class EventDto { + webhook?: { + enabled?: boolean; + events?: string[]; + url?: string; + headers?: JsonValue; + byEvents?: boolean; + base64?: boolean; + }; + + websocket?: { + enabled?: boolean; + events?: string[]; + }; + + sqs?: { + enabled?: boolean; + events?: string[]; + }; + + rabbitmq?: { + enabled?: boolean; + events?: string[]; + }; + + pusher?: { + enabled?: boolean; + appId?: string; + key?: string; + secret?: string; + cluster?: string; + useTLS?: boolean; + events?: string[]; + }; +} + +export function EventInstanceMixin(Base: TBase) { + return class extends Base { + webhook?: { + enabled?: boolean; + events?: string[]; + headers?: JsonValue; + url?: string; + byEvents?: boolean; + base64?: boolean; + }; + + websocket?: { + enabled?: boolean; + events?: string[]; + }; + + sqs?: { + enabled?: boolean; + events?: string[]; + }; + + rabbitmq?: { + enabled?: boolean; + events?: string[]; + }; + + pusher?: { + enabled?: boolean; + appId?: string; + key?: string; + secret?: string; + cluster?: string; + useTLS?: boolean; + events?: string[]; + }; + }; +} diff --git a/src/api/integrations/event/event.manager.ts b/src/api/integrations/event/event.manager.ts new file mode 100644 index 00000000..9df96f9f --- /dev/null +++ b/src/api/integrations/event/event.manager.ts @@ -0,0 +1,161 @@ +import { PusherController } from '@api/integrations/event/pusher/pusher.controller'; +import { RabbitmqController } from '@api/integrations/event/rabbitmq/rabbitmq.controller'; +import { SqsController } from '@api/integrations/event/sqs/sqs.controller'; +import { WebhookController } from '@api/integrations/event/webhook/webhook.controller'; +import { WebsocketController } from '@api/integrations/event/websocket/websocket.controller'; +import { PrismaRepository } from '@api/repository/repository.service'; +import { WAMonitoringService } from '@api/services/monitor.service'; +import { Server } from 'http'; + +export class EventManager { + private prismaRepository: PrismaRepository; + private waMonitor: WAMonitoringService; + private websocketController: WebsocketController; + private webhookController: WebhookController; + private rabbitmqController: RabbitmqController; + private sqsController: SqsController; + private pusherController: PusherController; + + constructor(prismaRepository: PrismaRepository, waMonitor: WAMonitoringService) { + this.prisma = prismaRepository; + this.monitor = waMonitor; + + this.websocket = new WebsocketController(prismaRepository, waMonitor); + this.webhook = new WebhookController(prismaRepository, waMonitor); + this.rabbitmq = new RabbitmqController(prismaRepository, waMonitor); + this.sqs = new SqsController(prismaRepository, waMonitor); + this.pusher = new PusherController(prismaRepository, waMonitor); + } + + public set prisma(prisma: PrismaRepository) { + this.prismaRepository = prisma; + } + + public get prisma() { + return this.prismaRepository; + } + + public set monitor(waMonitor: WAMonitoringService) { + this.waMonitor = waMonitor; + } + + public get monitor() { + return this.waMonitor; + } + + public set websocket(websocket: WebsocketController) { + this.websocketController = websocket; + } + + public get websocket() { + return this.websocketController; + } + + public set webhook(webhook: WebhookController) { + this.webhookController = webhook; + } + + public get webhook() { + return this.webhookController; + } + + public set rabbitmq(rabbitmq: RabbitmqController) { + this.rabbitmqController = rabbitmq; + } + + public get rabbitmq() { + return this.rabbitmqController; + } + + public set sqs(sqs: SqsController) { + this.sqsController = sqs; + } + + public get sqs() { + return this.sqsController; + } + + public set pusher(pusher: PusherController) { + this.pusherController = pusher; + } + public get pusher() { + return this.pusherController; + } + + public init(httpServer: Server): void { + this.websocket.init(httpServer); + this.rabbitmq.init(); + this.sqs.init(); + this.pusher.init(); + } + + public async emit(eventData: { + instanceName: string; + origin: string; + event: string; + data: Object; + serverUrl: string; + dateTime: string; + sender: string; + apiKey?: string; + local?: boolean; + integration?: string[]; + }): Promise { + await this.websocket.emit(eventData); + await this.rabbitmq.emit(eventData); + await this.sqs.emit(eventData); + await this.webhook.emit(eventData); + await this.pusher.emit(eventData); + } + + public async setInstance(instanceName: string, data: any): Promise { + if (data.websocket) + await this.websocket.set(instanceName, { + websocket: { + enabled: true, + events: data.websocket?.events, + }, + }); + + if (data.rabbitmq) + await this.rabbitmq.set(instanceName, { + rabbitmq: { + enabled: true, + events: data.rabbitmq?.events, + }, + }); + + if (data.sqs) + await this.sqs.set(instanceName, { + sqs: { + enabled: true, + events: data.sqs?.events, + }, + }); + + if (data.webhook) + await this.webhook.set(instanceName, { + webhook: { + enabled: true, + events: data.webhook?.events, + url: data.webhook?.url, + headers: data.webhook?.headers, + base64: data.webhook?.base64, + byEvents: data.webhook?.byEvents, + }, + }); + + if (data.pusher) + await this.pusher.set(instanceName, { + pusher: { + enabled: true, + events: data.pusher?.events, + appId: data.pusher?.appId, + key: data.pusher?.key, + secret: data.pusher?.secret, + cluster: data.pusher?.cluster, + useTLS: data.pusher?.useTLS, + }, + }); + } +} diff --git a/src/api/integrations/event/event.router.ts b/src/api/integrations/event/event.router.ts new file mode 100644 index 00000000..580b0324 --- /dev/null +++ b/src/api/integrations/event/event.router.ts @@ -0,0 +1,20 @@ +import { PusherRouter } from '@api/integrations/event/pusher/pusher.router'; +import { RabbitmqRouter } from '@api/integrations/event/rabbitmq/rabbitmq.router'; +import { SqsRouter } from '@api/integrations/event/sqs/sqs.router'; +import { WebhookRouter } from '@api/integrations/event/webhook/webhook.router'; +import { WebsocketRouter } from '@api/integrations/event/websocket/websocket.router'; +import { Router } from 'express'; + +export class EventRouter { + public readonly router: Router; + + constructor(configService: any, ...guards: any[]) { + this.router = Router(); + + this.router.use('/webhook', new WebhookRouter(configService, ...guards).router); + this.router.use('/websocket', new WebsocketRouter(...guards).router); + this.router.use('/rabbitmq', new RabbitmqRouter(...guards).router); + this.router.use('/pusher', new PusherRouter(...guards).router); + this.router.use('/sqs', new SqsRouter(...guards).router); + } +} diff --git a/src/api/integrations/event/event.schema.ts b/src/api/integrations/event/event.schema.ts new file mode 100644 index 00000000..5ec8866f --- /dev/null +++ b/src/api/integrations/event/event.schema.ts @@ -0,0 +1,40 @@ +import { JSONSchema7 } from 'json-schema'; +import { v4 } from 'uuid'; + +import { EventController } from './event.controller'; + +export * from '@api/integrations/event/pusher/pusher.schema'; +export * from '@api/integrations/event/webhook/webhook.schema'; + +export const eventSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + websocket: { + $ref: '#/$defs/event', + }, + rabbitmq: { + $ref: '#/$defs/event', + }, + sqs: { + $ref: '#/$defs/event', + }, + }, + $defs: { + event: { + type: 'object', + properties: { + enabled: { type: 'boolean', enum: [true, false] }, + events: { + type: 'array', + minItems: 0, + items: { + type: 'string', + enum: EventController.events, + }, + }, + }, + required: ['enabled'], + }, + }, +}; diff --git a/src/api/integrations/event/pusher/pusher.controller.ts b/src/api/integrations/event/pusher/pusher.controller.ts new file mode 100644 index 00000000..eef244b2 --- /dev/null +++ b/src/api/integrations/event/pusher/pusher.controller.ts @@ -0,0 +1,213 @@ +import { EventDto } from '@api/integrations/event/event.dto'; +import { PrismaRepository } from '@api/repository/repository.service'; +import { WAMonitoringService } from '@api/services/monitor.service'; +import { wa } from '@api/types/wa.types'; +import { configService, Log, Pusher as ConfigPusher } from '@config/env.config'; +import { Logger } from '@config/logger.config'; +import Pusher from 'pusher'; + +import { EmitData, EventController, EventControllerInterface } from '../event.controller'; +export class PusherController extends EventController implements EventControllerInterface { + private readonly logger = new Logger('PusherController'); + private pusherClients: { [instanceName: string]: Pusher } = {}; + private globalPusherClient: Pusher | null = null; + private pusherConfig: ConfigPusher = configService.get('PUSHER'); + constructor(prismaRepository: PrismaRepository, waMonitor: WAMonitoringService) { + super(prismaRepository, waMonitor, configService.get('PUSHER')?.ENABLED, 'pusher'); + this.init(); + } + public async init(): Promise { + if (!this.status) { + return; + } + if (this.pusherConfig.GLOBAL?.ENABLED) { + const { APP_ID, KEY, SECRET, CLUSTER, USE_TLS } = this.pusherConfig.GLOBAL; + if (APP_ID && KEY && SECRET && CLUSTER) { + this.globalPusherClient = new Pusher({ + appId: APP_ID, + key: KEY, + secret: SECRET, + cluster: CLUSTER, + useTLS: USE_TLS, + }); + this.logger.info('Pusher global client initialized'); + } + } + const instances = await this.prismaRepository.instance.findMany({ + where: { + Pusher: { + isNot: null, + }, + }, + include: { + Pusher: true, + }, + }); + instances.forEach((instance) => { + if ( + instance.Pusher.enabled && + instance.Pusher.appId && + instance.Pusher.key && + instance.Pusher.secret && + instance.Pusher.cluster + ) { + this.pusherClients[instance.name] = new Pusher({ + appId: instance.Pusher.appId, + key: instance.Pusher.key, + secret: instance.Pusher.secret, + cluster: instance.Pusher.cluster, + useTLS: instance.Pusher.useTLS, + }); + this.logger.info(`Pusher client initialized for instance ${instance.name}`); + } else { + delete this.pusherClients[instance.name]; + this.logger.warn(`Pusher client disabled or misconfigured for instance ${instance.name}`); + } + }); + } + override async set(instanceName: string, data: EventDto): Promise { + if (!data.pusher?.enabled) { + data.pusher.events = []; + } else if (data.pusher.events.length === 0) { + data.pusher.events = EventController.events; + } + const instance = await this.prisma.pusher.upsert({ + where: { + instanceId: this.monitor.waInstances[instanceName].instanceId, + }, + update: { + enabled: data.pusher.enabled, + events: data.pusher.events, + appId: data.pusher.appId, + key: data.pusher.key, + secret: data.pusher.secret, + cluster: data.pusher.cluster, + useTLS: data.pusher.useTLS, + }, + create: { + enabled: data.pusher.enabled, + events: data.pusher.events, + instanceId: this.monitor.waInstances[instanceName].instanceId, + appId: data.pusher.appId, + key: data.pusher.key, + secret: data.pusher.secret, + cluster: data.pusher.cluster, + useTLS: data.pusher.useTLS, + }, + }); + if (instance.enabled && instance.appId && instance.key && instance.secret && instance.cluster) { + this.pusherClients[instanceName] = new Pusher({ + appId: instance.appId, + key: instance.key, + secret: instance.secret, + cluster: instance.cluster, + useTLS: instance.useTLS, + }); + this.logger.info(`Pusher client initialized for instance ${instanceName}`); + } else { + delete this.pusherClients[instanceName]; + this.logger.warn(`Pusher client disabled or misconfigured for instance ${instanceName}`); + } + return instance; + } + public async emit({ + instanceName, + origin, + event, + data, + serverUrl, + dateTime, + sender, + apiKey, + local, + integration, + }: EmitData): Promise { + if (integration && !integration.includes('pusher')) { + return; + } + if (!this.status) { + return; + } + const instance = (await this.get(instanceName)) as wa.LocalPusher; + const we = event.replace(/[.-]/gm, '_').toUpperCase(); + const enabledLog = configService.get('LOG').LEVEL.includes('WEBHOOKS'); + const eventName = event.replace(/_/g, '.').toLowerCase(); + const pusherData = { + event, + instance: instanceName, + data, + destination: instance?.appId || this.pusherConfig.GLOBAL?.APP_ID, + date_time: dateTime, + sender, + server_url: serverUrl, + apikey: apiKey, + }; + if (event == 'qrcode.updated') { + delete pusherData.data.qrcode.base64; + } + const payload = JSON.stringify(pusherData); + const payloadSize = Buffer.byteLength(payload, 'utf8'); + const MAX_SIZE = 10240; + if (payloadSize > MAX_SIZE) { + this.logger.error({ + local: `${origin}.sendData-Pusher`, + message: 'Payload size exceeds Pusher limit', + event, + instanceName, + payloadSize, + }); + return; + } + if (local && instance && instance.enabled) { + const pusherLocalEvents = instance.events; + if (Array.isArray(pusherLocalEvents) && pusherLocalEvents.includes(we)) { + if (enabledLog) { + this.logger.log({ + local: `${origin}.sendData-Pusher`, + appId: instance.appId, + ...pusherData, + }); + } + try { + const pusher = this.pusherClients[instanceName]; + if (pusher) { + pusher.trigger(instanceName, eventName, pusherData); + } else { + this.logger.error(`Pusher client not found for instance ${instanceName}`); + } + } catch (error) { + this.logger.error({ + local: `${origin}.sendData-Pusher`, + message: error?.message, + error, + }); + } + } + } + if (this.pusherConfig.GLOBAL?.ENABLED) { + const globalEvents = this.pusherConfig.EVENTS; + if (globalEvents[we]) { + if (enabledLog) { + this.logger.log({ + local: `${origin}.sendData-Pusher-Global`, + appId: this.pusherConfig.GLOBAL?.APP_ID, + ...pusherData, + }); + } + try { + if (this.globalPusherClient) { + this.globalPusherClient.trigger(instanceName, eventName, pusherData); + } else { + this.logger.error('Global Pusher client not initialized'); + } + } catch (error) { + this.logger.error({ + local: `${origin}.sendData-Pusher-Global`, + message: error?.message, + error, + }); + } + } + } + } +} diff --git a/src/api/integrations/event/pusher/pusher.router.ts b/src/api/integrations/event/pusher/pusher.router.ts new file mode 100644 index 00000000..8e3c534f --- /dev/null +++ b/src/api/integrations/event/pusher/pusher.router.ts @@ -0,0 +1,32 @@ +import { RouterBroker } from '@api/abstract/abstract.router'; +import { InstanceDto } from '@api/dto/instance.dto'; +import { EventDto } from '@api/integrations/event/event.dto'; +import { HttpStatus } from '@api/routes/index.router'; +import { eventManager } from '@api/server.module'; +import { instanceSchema, pusherSchema } from '@validate/validate.schema'; +import { RequestHandler, Router } from 'express'; +export class PusherRouter extends RouterBroker { + constructor(...guards: RequestHandler[]) { + super(); + this.router + .post(this.routerPath('set'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: pusherSchema, + ClassRef: EventDto, + execute: (instance, data) => eventManager.pusher.set(instance.instanceName, data), + }); + res.status(HttpStatus.CREATED).json(response); + }) + .get(this.routerPath('find'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => eventManager.pusher.get(instance.instanceName), + }); + res.status(HttpStatus.OK).json(response); + }); + } + public readonly router: Router = Router(); +} diff --git a/src/api/integrations/event/pusher/pusher.schema.ts b/src/api/integrations/event/pusher/pusher.schema.ts new file mode 100644 index 00000000..c04756ea --- /dev/null +++ b/src/api/integrations/event/pusher/pusher.schema.ts @@ -0,0 +1,50 @@ +import { JSONSchema7 } from 'json-schema'; +import { v4 } from 'uuid'; + +import { EventController } from '../event.controller'; +const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => { + const properties = {}; + propertyNames.forEach( + (property) => + (properties[property] = { + minLength: 1, + description: `The "${property}" cannot be empty`, + }), + ); + return { + if: { + propertyNames: { + enum: [...propertyNames], + }, + }, + then: { properties }, + }; +}; +export const pusherSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + pusher: { + type: 'object', + properties: { + enabled: { type: 'boolean' }, + appId: { type: 'string' }, + key: { type: 'string' }, + secret: { type: 'string' }, + cluster: { type: 'string' }, + useTLS: { type: 'boolean' }, + events: { + type: 'array', + minItems: 0, + items: { + type: 'string', + enum: EventController.events, + }, + }, + }, + required: ['enabled', 'appId', 'key', 'secret', 'cluster', 'useTLS'], + ...isNotEmpty('enabled', 'appId', 'key', 'secret', 'cluster', 'useTLS'), + }, + }, + required: ['pusher'], +}; diff --git a/src/api/integrations/event/rabbitmq/rabbitmq.controller.ts b/src/api/integrations/event/rabbitmq/rabbitmq.controller.ts new file mode 100644 index 00000000..22defde5 --- /dev/null +++ b/src/api/integrations/event/rabbitmq/rabbitmq.controller.ts @@ -0,0 +1,236 @@ +import { PrismaRepository } from '@api/repository/repository.service'; +import { WAMonitoringService } from '@api/services/monitor.service'; +import { configService, Log, Rabbitmq } from '@config/env.config'; +import { Logger } from '@config/logger.config'; +import * as amqp from 'amqplib/callback_api'; + +import { EmitData, EventController, EventControllerInterface } from '../event.controller'; + +export class RabbitmqController extends EventController implements EventControllerInterface { + public amqpChannel: amqp.Channel | null = null; + private readonly logger = new Logger('RabbitmqController'); + + constructor(prismaRepository: PrismaRepository, waMonitor: WAMonitoringService) { + super(prismaRepository, waMonitor, configService.get('RABBITMQ')?.ENABLED, 'rabbitmq'); + } + + public async init(): Promise { + if (!this.status) { + return; + } + + await new Promise((resolve, reject) => { + const uri = configService.get('RABBITMQ').URI; + const rabbitmqExchangeName = configService.get('RABBITMQ').EXCHANGE_NAME; + + amqp.connect(uri, (error, connection) => { + if (error) { + reject(error); + + return; + } + + connection.createChannel((channelError, channel) => { + if (channelError) { + reject(channelError); + + return; + } + + const exchangeName = rabbitmqExchangeName; + + channel.assertExchange(exchangeName, 'topic', { + durable: true, + autoDelete: false, + }); + + this.amqpChannel = channel; + + this.logger.info('AMQP initialized'); + + resolve(); + }); + }); + }).then(() => { + if (configService.get('RABBITMQ')?.GLOBAL_ENABLED) this.initGlobalQueues(); + }); + } + + private set channel(channel: amqp.Channel) { + this.amqpChannel = channel; + } + + public get channel(): amqp.Channel { + return this.amqpChannel; + } + + public async emit({ + instanceName, + origin, + event, + data, + serverUrl, + dateTime, + sender, + apiKey, + integration, + }: EmitData): Promise { + if (integration && !integration.includes('rabbitmq')) { + return; + } + + if (!this.status) { + return; + } + + const instanceRabbitmq = await this.get(instanceName); + const rabbitmqLocal = instanceRabbitmq?.events; + const rabbitmqGlobal = configService.get('RABBITMQ').GLOBAL_ENABLED; + const rabbitmqEvents = configService.get('RABBITMQ').EVENTS; + const prefixKey = configService.get('RABBITMQ').PREFIX_KEY; + const rabbitmqExchangeName = configService.get('RABBITMQ').EXCHANGE_NAME; + const we = event.replace(/[.-]/gm, '_').toUpperCase(); + const logEnabled = configService.get('LOG').LEVEL.includes('WEBHOOKS'); + + const message = { + event, + instance: instanceName, + data, + server_url: serverUrl, + date_time: dateTime, + sender, + apikey: apiKey, + }; + + if (instanceRabbitmq?.enabled && this.amqpChannel) { + if (Array.isArray(rabbitmqLocal) && rabbitmqLocal.includes(we)) { + const exchangeName = instanceName ?? rabbitmqExchangeName; + + let retry = 0; + + while (retry < 3) { + try { + await this.amqpChannel.assertExchange(exchangeName, 'topic', { + durable: true, + autoDelete: false, + }); + + const eventName = event.replace(/_/g, '.').toLowerCase(); + + const queueName = `${instanceName}.${eventName}`; + + await this.amqpChannel.assertQueue(queueName, { + durable: true, + autoDelete: false, + arguments: { + 'x-queue-type': 'quorum', + }, + }); + + await this.amqpChannel.bindQueue(queueName, exchangeName, eventName); + + await this.amqpChannel.publish(exchangeName, event, Buffer.from(JSON.stringify(message))); + + if (logEnabled) { + const logData = { + local: `${origin}.sendData-RabbitMQ`, + ...message, + }; + + this.logger.log(logData); + } + + break; + } catch (error) { + retry++; + } + } + } + } + + if (rabbitmqGlobal && rabbitmqEvents[we] && this.amqpChannel) { + const exchangeName = rabbitmqExchangeName; + + let retry = 0; + + while (retry < 3) { + try { + await this.amqpChannel.assertExchange(exchangeName, 'topic', { + durable: true, + autoDelete: false, + }); + + const queueName = prefixKey + ? `${prefixKey}.${event.replace(/_/g, '.').toLowerCase()}` + : event.replace(/_/g, '.').toLowerCase(); + + await this.amqpChannel.assertQueue(queueName, { + durable: true, + autoDelete: false, + arguments: { + 'x-queue-type': 'quorum', + }, + }); + + await this.amqpChannel.bindQueue(queueName, exchangeName, event); + + await this.amqpChannel.publish(exchangeName, event, Buffer.from(JSON.stringify(message))); + + if (logEnabled) { + const logData = { + local: `${origin}.sendData-RabbitMQ-Global`, + ...message, + }; + + this.logger.log(logData); + } + + break; + } catch (error) { + retry++; + } + } + } + } + + private async initGlobalQueues(): Promise { + this.logger.info('Initializing global queues'); + + const rabbitmqExchangeName = configService.get('RABBITMQ').EXCHANGE_NAME; + const events = configService.get('RABBITMQ').EVENTS; + const prefixKey = configService.get('RABBITMQ').PREFIX_KEY; + + if (!events) { + this.logger.warn('No events to initialize on AMQP'); + + return; + } + + const eventKeys = Object.keys(events); + + eventKeys.forEach((event) => { + if (events[event] === false) return; + + const queueName = + prefixKey !== '' + ? `${prefixKey}.${event.replace(/_/g, '.').toLowerCase()}` + : `${event.replace(/_/g, '.').toLowerCase()}`; + const exchangeName = rabbitmqExchangeName; + + this.amqpChannel.assertExchange(exchangeName, 'topic', { + durable: true, + autoDelete: false, + }); + + this.amqpChannel.assertQueue(queueName, { + durable: true, + autoDelete: false, + arguments: { + 'x-queue-type': 'quorum', + }, + }); + + this.amqpChannel.bindQueue(queueName, exchangeName, event); + }); + } +} diff --git a/src/api/integrations/event/rabbitmq/rabbitmq.router.ts b/src/api/integrations/event/rabbitmq/rabbitmq.router.ts new file mode 100644 index 00000000..997e1ca2 --- /dev/null +++ b/src/api/integrations/event/rabbitmq/rabbitmq.router.ts @@ -0,0 +1,36 @@ +import { RouterBroker } from '@api/abstract/abstract.router'; +import { InstanceDto } from '@api/dto/instance.dto'; +import { EventDto } from '@api/integrations/event/event.dto'; +import { HttpStatus } from '@api/routes/index.router'; +import { eventManager } from '@api/server.module'; +import { eventSchema, instanceSchema } from '@validate/validate.schema'; +import { RequestHandler, Router } from 'express'; + +export class RabbitmqRouter extends RouterBroker { + constructor(...guards: RequestHandler[]) { + super(); + this.router + .post(this.routerPath('set'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: eventSchema, + ClassRef: EventDto, + execute: (instance, data) => eventManager.rabbitmq.set(instance.instanceName, data), + }); + + res.status(HttpStatus.CREATED).json(response); + }) + .get(this.routerPath('find'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => eventManager.rabbitmq.get(instance.instanceName), + }); + + res.status(HttpStatus.OK).json(response); + }); + } + + public readonly router: Router = Router(); +} diff --git a/src/api/integrations/event/sqs/sqs.controller.ts b/src/api/integrations/event/sqs/sqs.controller.ts new file mode 100644 index 00000000..1d60fb7b --- /dev/null +++ b/src/api/integrations/event/sqs/sqs.controller.ts @@ -0,0 +1,190 @@ +import { PrismaRepository } from '@api/repository/repository.service'; +import { WAMonitoringService } from '@api/services/monitor.service'; +import { SQS } from '@aws-sdk/client-sqs'; +import { configService, Log, Sqs } from '@config/env.config'; +import { Logger } from '@config/logger.config'; + +import { EmitData, EventController, EventControllerInterface } from '../event.controller'; + +export class SqsController extends EventController implements EventControllerInterface { + private sqs: SQS; + private readonly logger = new Logger('SqsController'); + + constructor(prismaRepository: PrismaRepository, waMonitor: WAMonitoringService) { + super(prismaRepository, waMonitor, configService.get('SQS')?.ENABLED, 'sqs'); + } + + public init(): void { + if (!this.status) { + return; + } + + new Promise((resolve) => { + const awsConfig = configService.get('SQS'); + + this.sqs = new SQS({ + credentials: { + accessKeyId: awsConfig.ACCESS_KEY_ID, + secretAccessKey: awsConfig.SECRET_ACCESS_KEY, + }, + + region: awsConfig.REGION, + }); + + this.logger.info('SQS initialized'); + + resolve(); + }); + } + + private set channel(sqs: SQS) { + this.sqs = sqs; + } + + public get channel(): SQS { + return this.sqs; + } + + public async emit({ + instanceName, + origin, + event, + data, + serverUrl, + dateTime, + sender, + apiKey, + integration, + }: EmitData): Promise { + if (integration && !integration.includes('sqs')) { + return; + } + + if (!this.status) { + return; + } + + const instanceSqs = await this.get(instanceName); + const sqsLocal = instanceSqs?.events; + const we = event.replace(/[.-]/gm, '_').toUpperCase(); + + if (instanceSqs?.enabled) { + if (this.sqs) { + if (Array.isArray(sqsLocal) && sqsLocal.includes(we)) { + const eventFormatted = `${event.replace('.', '_').toLowerCase()}`; + const queueName = `${instanceName}_${eventFormatted}.fifo`; + const sqsConfig = configService.get('SQS'); + const sqsUrl = `https://sqs.${sqsConfig.REGION}.amazonaws.com/${sqsConfig.ACCOUNT_ID}/${queueName}`; + + const message = { + event, + instance: instanceName, + data, + server_url: serverUrl, + date_time: dateTime, + sender, + apikey: apiKey, + }; + + const params = { + MessageBody: JSON.stringify(message), + MessageGroupId: 'evolution', + MessageDeduplicationId: `${instanceName}_${eventFormatted}_${Date.now()}`, + QueueUrl: sqsUrl, + }; + + this.sqs.sendMessage(params, (err) => { + if (err) { + this.logger.error({ + local: `${origin}.sendData-SQS`, + message: err?.message, + hostName: err?.hostname, + code: err?.code, + stack: err?.stack, + name: err?.name, + url: queueName, + server_url: serverUrl, + }); + } else { + if (configService.get('LOG').LEVEL.includes('WEBHOOKS')) { + const logData = { + local: `${origin}.sendData-SQS`, + ...message, + }; + + this.logger.log(logData); + } + } + }); + } + } + } + } + + public async initQueues(instanceName: string, events: string[]) { + if (!events || !events.length) return; + + const queues = events.map((event) => { + return `${event.replace(/_/g, '_').toLowerCase()}`; + }); + + queues.forEach((event) => { + const queueName = `${instanceName}_${event}.fifo`; + + this.sqs.createQueue( + { + QueueName: queueName, + Attributes: { + FifoQueue: 'true', + }, + }, + (err, data) => { + if (err) { + this.logger.error(`Error creating queue ${queueName}: ${err.message}`); + } else { + this.logger.info(`Queue ${queueName} created: ${data.QueueUrl}`); + } + }, + ); + }); + } + + public async removeQueues(instanceName: string, events: any) { + const eventsArray = Array.isArray(events) ? events.map((event) => String(event)) : []; + if (!events || !eventsArray.length) return; + + const queues = eventsArray.map((event) => { + return `${event.replace(/_/g, '_').toLowerCase()}`; + }); + + queues.forEach((event) => { + const queueName = `${instanceName}_${event}.fifo`; + + this.sqs.getQueueUrl( + { + QueueName: queueName, + }, + (err, data) => { + if (err) { + this.logger.error(`Error getting queue URL for ${queueName}: ${err.message}`); + } else { + const queueUrl = data.QueueUrl; + + this.sqs.deleteQueue( + { + QueueUrl: queueUrl, + }, + (deleteErr) => { + if (deleteErr) { + this.logger.error(`Error deleting queue ${queueName}: ${deleteErr.message}`); + } else { + this.logger.info(`Queue ${queueName} deleted`); + } + }, + ); + } + }, + ); + }); + } +} diff --git a/src/api/integrations/event/sqs/sqs.router.ts b/src/api/integrations/event/sqs/sqs.router.ts new file mode 100644 index 00000000..23f63f85 --- /dev/null +++ b/src/api/integrations/event/sqs/sqs.router.ts @@ -0,0 +1,36 @@ +import { RouterBroker } from '@api/abstract/abstract.router'; +import { InstanceDto } from '@api/dto/instance.dto'; +import { EventDto } from '@api/integrations/event/event.dto'; +import { HttpStatus } from '@api/routes/index.router'; +import { eventManager } from '@api/server.module'; +import { eventSchema, instanceSchema } from '@validate/validate.schema'; +import { RequestHandler, Router } from 'express'; + +export class SqsRouter extends RouterBroker { + constructor(...guards: RequestHandler[]) { + super(); + this.router + .post(this.routerPath('set'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: eventSchema, + ClassRef: EventDto, + execute: (instance, data) => eventManager.sqs.set(instance.instanceName, data), + }); + + res.status(HttpStatus.CREATED).json(response); + }) + .get(this.routerPath('find'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => eventManager.sqs.get(instance.instanceName), + }); + + res.status(HttpStatus.OK).json(response); + }); + } + + public readonly router: Router = Router(); +} diff --git a/src/api/integrations/event/webhook/webhook.controller.ts b/src/api/integrations/event/webhook/webhook.controller.ts new file mode 100644 index 00000000..ce709c3d --- /dev/null +++ b/src/api/integrations/event/webhook/webhook.controller.ts @@ -0,0 +1,233 @@ +import { EventDto } from '@api/integrations/event/event.dto'; +import { PrismaRepository } from '@api/repository/repository.service'; +import { WAMonitoringService } from '@api/services/monitor.service'; +import { wa } from '@api/types/wa.types'; +import { configService, Log, Webhook } from '@config/env.config'; +import { Logger } from '@config/logger.config'; +import { BadRequestException } from '@exceptions'; +import axios, { AxiosInstance } from 'axios'; +import { isURL } from 'class-validator'; + +import { EmitData, EventController, EventControllerInterface } from '../event.controller'; + +export class WebhookController extends EventController implements EventControllerInterface { + private readonly logger = new Logger('WebhookController'); + + constructor(prismaRepository: PrismaRepository, waMonitor: WAMonitoringService) { + super(prismaRepository, waMonitor, true, 'webhook'); + } + + override async set(instanceName: string, data: EventDto): Promise { + if (!isURL(data.webhook.url, { require_tld: false })) { + throw new BadRequestException('Invalid "url" property'); + } + + if (!data.webhook?.enabled) { + data.webhook.events = []; + } else { + if (0 === data.webhook.events.length) { + data.webhook.events = EventController.events; + } + } + + return this.prisma.webhook.upsert({ + where: { + instanceId: this.monitor.waInstances[instanceName].instanceId, + }, + update: { + enabled: data.webhook?.enabled, + events: data.webhook?.events, + url: data.webhook?.url, + headers: data.webhook?.headers, + webhookBase64: data.webhook.base64, + webhookByEvents: data.webhook.byEvents, + }, + create: { + enabled: data.webhook?.enabled, + events: data.webhook?.events, + instanceId: this.monitor.waInstances[instanceName].instanceId, + url: data.webhook?.url, + headers: data.webhook?.headers, + webhookBase64: data.webhook.base64, + webhookByEvents: data.webhook.byEvents, + }, + }); + } + + public async emit({ + instanceName, + origin, + event, + data, + serverUrl, + dateTime, + sender, + apiKey, + local, + integration, + }: EmitData): Promise { + if (integration && !integration.includes('webhook')) { + return; + } + + const instance = (await this.get(instanceName)) as wa.LocalWebHook; + + const webhookConfig = configService.get('WEBHOOK'); + const webhookLocal = instance?.events; + const webhookHeaders = instance?.headers; + const we = event.replace(/[.-]/gm, '_').toUpperCase(); + const transformedWe = we.replace(/_/gm, '-').toLowerCase(); + const enabledLog = configService.get('LOG').LEVEL.includes('WEBHOOKS'); + + const webhookData = { + event, + instance: instanceName, + data, + destination: instance?.url || `${webhookConfig.GLOBAL.URL}/${transformedWe}`, + date_time: dateTime, + sender, + server_url: serverUrl, + apikey: apiKey, + }; + + if (local && instance?.enabled) { + if (Array.isArray(webhookLocal) && webhookLocal.includes(we)) { + let baseURL: string; + + if (instance?.webhookByEvents) { + baseURL = `${instance?.url}/${transformedWe}`; + } else { + baseURL = instance?.url; + } + + if (enabledLog) { + const logData = { + local: `${origin}.sendData-Webhook`, + url: baseURL, + ...webhookData, + }; + + this.logger.log(logData); + } + + try { + if (instance?.enabled && isURL(instance.url, { require_tld: false })) { + const httpService = axios.create({ + baseURL, + headers: webhookHeaders as Record | undefined, + }); + + await this.retryWebhookRequest(httpService, webhookData, `${origin}.sendData-Webhook`, baseURL, serverUrl); + } + } catch (error) { + this.logger.error({ + local: `${origin}.sendData-Webhook`, + message: `Todas as tentativas falharam: ${error?.message}`, + hostName: error?.hostname, + syscall: error?.syscall, + code: error?.code, + error: error?.errno, + stack: error?.stack, + name: error?.name, + url: baseURL, + server_url: serverUrl, + }); + } + } + } + + if (webhookConfig.GLOBAL?.ENABLED) { + if (webhookConfig.EVENTS[we]) { + let globalURL = webhookConfig.GLOBAL.URL; + + if (webhookConfig.GLOBAL.WEBHOOK_BY_EVENTS) { + globalURL = `${globalURL}/${transformedWe}`; + } + + if (enabledLog) { + const logData = { + local: `${origin}.sendData-Webhook-Global`, + url: globalURL, + ...webhookData, + }; + + this.logger.log(logData); + } + + try { + if (isURL(globalURL)) { + const httpService = axios.create({ baseURL: globalURL }); + + await this.retryWebhookRequest( + httpService, + webhookData, + `${origin}.sendData-Webhook-Global`, + globalURL, + serverUrl, + ); + } + } catch (error) { + this.logger.error({ + local: `${origin}.sendData-Webhook-Global`, + message: `Todas as tentativas falharam: ${error?.message}`, + hostName: error?.hostname, + syscall: error?.syscall, + code: error?.code, + error: error?.errno, + stack: error?.stack, + name: error?.name, + url: globalURL, + server_url: serverUrl, + }); + } + } + } + } + + private async retryWebhookRequest( + httpService: AxiosInstance, + webhookData: any, + origin: string, + baseURL: string, + serverUrl: string, + maxRetries = 10, + delaySeconds = 30, + ): Promise { + let attempts = 0; + + while (attempts < maxRetries) { + try { + await httpService.post('', webhookData); + if (attempts > 0) { + this.logger.log({ + local: `${origin}`, + message: `Sucesso no envio após ${attempts + 1} tentativas`, + url: baseURL, + }); + } + return; + } catch (error) { + attempts++; + + this.logger.error({ + local: `${origin}`, + message: `Tentativa ${attempts}/${maxRetries} falhou: ${error?.message}`, + hostName: error?.hostname, + syscall: error?.syscall, + code: error?.code, + error: error?.errno, + stack: error?.stack, + name: error?.name, + url: baseURL, + server_url: serverUrl, + }); + + if (attempts === maxRetries) { + throw error; + } + + await new Promise((resolve) => setTimeout(resolve, delaySeconds * 1000)); + } + } + } +} diff --git a/src/api/integrations/event/webhook/webhook.router.ts b/src/api/integrations/event/webhook/webhook.router.ts new file mode 100644 index 00000000..149f940b --- /dev/null +++ b/src/api/integrations/event/webhook/webhook.router.ts @@ -0,0 +1,40 @@ +import { RouterBroker } from '@api/abstract/abstract.router'; +import { InstanceDto } from '@api/dto/instance.dto'; +import { EventDto } from '@api/integrations/event/event.dto'; +import { HttpStatus } from '@api/routes/index.router'; +import { eventManager } from '@api/server.module'; +import { ConfigService } from '@config/env.config'; +import { instanceSchema, webhookSchema } from '@validate/validate.schema'; +import { RequestHandler, Router } from 'express'; + +export class WebhookRouter extends RouterBroker { + constructor( + readonly configService: ConfigService, + ...guards: RequestHandler[] + ) { + super(); + this.router + .post(this.routerPath('set'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: webhookSchema, + ClassRef: EventDto, + execute: (instance, data) => eventManager.webhook.set(instance.instanceName, data), + }); + + res.status(HttpStatus.CREATED).json(response); + }) + .get(this.routerPath('find'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => eventManager.webhook.get(instance.instanceName), + }); + + res.status(HttpStatus.OK).json(response); + }); + } + + public readonly router: Router = Router(); +} diff --git a/src/api/integrations/event/webhook/webhook.schema.ts b/src/api/integrations/event/webhook/webhook.schema.ts new file mode 100644 index 00000000..5d0f3724 --- /dev/null +++ b/src/api/integrations/event/webhook/webhook.schema.ts @@ -0,0 +1,51 @@ +import { JSONSchema7 } from 'json-schema'; +import { v4 } from 'uuid'; + +import { EventController } from '../event.controller'; + +const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => { + const properties = {}; + propertyNames.forEach( + (property) => + (properties[property] = { + minLength: 1, + description: `The "${property}" cannot be empty`, + }), + ); + return { + if: { + propertyNames: { + enum: [...propertyNames], + }, + }, + then: { properties }, + }; +}; + +export const webhookSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + webhook: { + type: 'object', + properties: { + enabled: { type: 'boolean' }, + url: { type: 'string' }, + headers: { type: 'object' }, + byEvents: { type: 'boolean' }, + base64: { type: 'boolean' }, + events: { + type: 'array', + minItems: 0, + items: { + type: 'string', + enum: EventController.events, + }, + }, + }, + required: ['enabled', 'url'], + ...isNotEmpty('enabled', 'url'), + }, + }, + required: ['webhook'], +}; diff --git a/src/api/integrations/event/websocket/websocket.controller.ts b/src/api/integrations/event/websocket/websocket.controller.ts new file mode 100644 index 00000000..f6d152ff --- /dev/null +++ b/src/api/integrations/event/websocket/websocket.controller.ts @@ -0,0 +1,134 @@ +import { PrismaRepository } from '@api/repository/repository.service'; +import { WAMonitoringService } from '@api/services/monitor.service'; +import { configService, Cors, Log, Websocket } from '@config/env.config'; +import { Logger } from '@config/logger.config'; +import { Server } from 'http'; +import { Server as SocketIO } from 'socket.io'; + +import { EmitData, EventController, EventControllerInterface } from '../event.controller'; + +export class WebsocketController extends EventController implements EventControllerInterface { + private io: SocketIO; + private corsConfig: Array; + private readonly logger = new Logger('WebsocketController'); + + constructor(prismaRepository: PrismaRepository, waMonitor: WAMonitoringService) { + super(prismaRepository, waMonitor, configService.get('WEBSOCKET')?.ENABLED, 'websocket'); + + this.cors = configService.get('CORS').ORIGIN; + } + + public init(httpServer: Server): void { + if (!this.status) { + return; + } + + this.socket = new SocketIO(httpServer, { + cors: { + origin: this.cors, + }, + }); + + this.socket.on('connection', (socket) => { + this.logger.info('User connected'); + + socket.on('disconnect', () => { + this.logger.info('User disconnected'); + }); + + socket.on('sendNode', async (data) => { + try { + await this.waMonitor.waInstances[data.instanceId].baileysSendNode(data.stanza); + this.logger.info('Node sent successfully'); + } catch (error) { + this.logger.error('Error sending node:'); + this.logger.error(error); + } + }); + }); + + this.logger.info('Socket.io initialized'); + } + + private set cors(cors: Array) { + this.corsConfig = cors; + } + + private get cors(): string | Array { + return this.corsConfig?.includes('*') ? '*' : this.corsConfig; + } + + private set socket(socket: SocketIO) { + this.io = socket; + } + + public get socket(): SocketIO { + return this.io; + } + + public async emit({ + instanceName, + origin, + event, + data, + serverUrl, + dateTime, + sender, + apiKey, + integration, + }: EmitData): Promise { + if (integration && !integration.includes('websocket')) { + return; + } + + if (!this.status) { + return; + } + + const configEv = event.replace(/[.-]/gm, '_').toUpperCase(); + const logEnabled = configService.get('LOG').LEVEL.includes('WEBSOCKET'); + const message = { + event, + instance: instanceName, + data, + server_url: serverUrl, + date_time: dateTime, + sender, + apikey: apiKey, + }; + + if (configService.get('WEBSOCKET')?.GLOBAL_EVENTS) { + this.socket.emit(event, message); + + if (logEnabled) { + this.logger.log({ + local: `${origin}.sendData-WebsocketGlobal`, + ...message, + }); + } + } + + try { + const instance = await this.get(instanceName); + + if (!instance?.enabled) { + return; + } + + if (Array.isArray(instance?.events) && instance?.events.includes(configEv)) { + this.socket.of(`/${instanceName}`).emit(event, message); + + if (logEnabled) { + this.logger.log({ + local: `${origin}.sendData-Websocket`, + ...message, + }); + } + } + } catch (err) { + if (logEnabled) { + this.logger.log(err); + } + } + } +} diff --git a/src/api/integrations/event/websocket/websocket.router.ts b/src/api/integrations/event/websocket/websocket.router.ts new file mode 100644 index 00000000..4271245f --- /dev/null +++ b/src/api/integrations/event/websocket/websocket.router.ts @@ -0,0 +1,36 @@ +import { RouterBroker } from '@api/abstract/abstract.router'; +import { InstanceDto } from '@api/dto/instance.dto'; +import { EventDto } from '@api/integrations/event/event.dto'; +import { HttpStatus } from '@api/routes/index.router'; +import { eventManager } from '@api/server.module'; +import { eventSchema, instanceSchema } from '@validate/validate.schema'; +import { RequestHandler, Router } from 'express'; + +export class WebsocketRouter extends RouterBroker { + constructor(...guards: RequestHandler[]) { + super(); + this.router + .post(this.routerPath('set'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: eventSchema, + ClassRef: EventDto, + execute: (instance, data) => eventManager.websocket.set(instance.instanceName, data), + }); + + res.status(HttpStatus.CREATED).json(response); + }) + .get(this.routerPath('find'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => eventManager.websocket.get(instance.instanceName), + }); + + res.status(HttpStatus.OK).json(response); + }); + } + + public readonly router: Router = Router(); +} diff --git a/src/api/integrations/integration.dto.ts b/src/api/integrations/integration.dto.ts new file mode 100644 index 00000000..743364c5 --- /dev/null +++ b/src/api/integrations/integration.dto.ts @@ -0,0 +1,6 @@ +import { ChatwootInstanceMixin } from '@api/integrations/chatbot/chatwoot/dto/chatwoot.dto'; +import { EventInstanceMixin } from '@api/integrations/event/event.dto'; + +export type Constructor = new (...args: any[]) => T; + +export class IntegrationDto extends EventInstanceMixin(ChatwootInstanceMixin(class {})) {} diff --git a/src/api/integrations/rabbitmq/controllers/rabbitmq.controller.ts b/src/api/integrations/rabbitmq/controllers/rabbitmq.controller.ts deleted file mode 100644 index 0b10e954..00000000 --- a/src/api/integrations/rabbitmq/controllers/rabbitmq.controller.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { Logger } from '../../../../config/logger.config'; -import { InstanceDto } from '../../../dto/instance.dto'; -import { RabbitmqDto } from '../dto/rabbitmq.dto'; -import { RabbitmqService } from '../services/rabbitmq.service'; - -const logger = new Logger('RabbitmqController'); - -export class RabbitmqController { - constructor(private readonly rabbitmqService: RabbitmqService) {} - - public async createRabbitmq(instance: InstanceDto, data: RabbitmqDto) { - logger.verbose('requested createRabbitmq from ' + instance.instanceName + ' instance'); - - if (!data.enabled) { - logger.verbose('rabbitmq disabled'); - data.events = []; - } - - if (data.events.length === 0) { - logger.verbose('rabbitmq events empty'); - data.events = [ - 'APPLICATION_STARTUP', - 'QRCODE_UPDATED', - 'MESSAGES_SET', - 'MESSAGES_UPSERT', - 'MESSAGES_UPDATE', - 'MESSAGES_DELETE', - 'SEND_MESSAGE', - 'CONTACTS_SET', - 'CONTACTS_UPSERT', - 'CONTACTS_UPDATE', - 'PRESENCE_UPDATE', - 'CHATS_SET', - 'CHATS_UPSERT', - 'CHATS_UPDATE', - 'CHATS_DELETE', - 'GROUPS_UPSERT', - 'GROUP_UPDATE', - 'GROUP_PARTICIPANTS_UPDATE', - 'CONNECTION_UPDATE', - 'LABELS_EDIT', - 'LABELS_ASSOCIATION', - 'CALL', - 'NEW_JWT_TOKEN', - 'TYPEBOT_START', - 'TYPEBOT_CHANGE_STATUS', - 'CHAMA_AI_ACTION', - ]; - } - - return this.rabbitmqService.create(instance, data); - } - - public async findRabbitmq(instance: InstanceDto) { - logger.verbose('requested findRabbitmq from ' + instance.instanceName + ' instance'); - return this.rabbitmqService.find(instance); - } -} diff --git a/src/api/integrations/rabbitmq/dto/rabbitmq.dto.ts b/src/api/integrations/rabbitmq/dto/rabbitmq.dto.ts deleted file mode 100644 index 9bfd5b42..00000000 --- a/src/api/integrations/rabbitmq/dto/rabbitmq.dto.ts +++ /dev/null @@ -1,4 +0,0 @@ -export class RabbitmqDto { - enabled: boolean; - events?: string[]; -} diff --git a/src/api/integrations/rabbitmq/libs/amqp.server.ts b/src/api/integrations/rabbitmq/libs/amqp.server.ts deleted file mode 100644 index 99c10f66..00000000 --- a/src/api/integrations/rabbitmq/libs/amqp.server.ts +++ /dev/null @@ -1,135 +0,0 @@ -import * as amqp from 'amqplib/callback_api'; - -import { configService, Rabbitmq } from '../../../../config/env.config'; -import { Logger } from '../../../../config/logger.config'; - -const logger = new Logger('AMQP'); - -let amqpChannel: amqp.Channel | null = null; - -export const initAMQP = () => { - return new Promise((resolve, reject) => { - const uri = configService.get('RABBITMQ').URI; - amqp.connect(uri, (error, connection) => { - if (error) { - reject(error); - return; - } - - connection.createChannel((channelError, channel) => { - if (channelError) { - reject(channelError); - return; - } - - const exchangeName = 'evolution_exchange'; - - channel.assertExchange(exchangeName, 'topic', { - durable: true, - autoDelete: false, - }); - - amqpChannel = channel; - - logger.info('AMQP initialized'); - resolve(); - }); - }); - }); -}; - -export const getAMQP = (): amqp.Channel | null => { - return amqpChannel; -}; - -export const initGlobalQueues = () => { - logger.info('Initializing global queues'); - const events = configService.get('RABBITMQ').EVENTS; - - if (!events) { - logger.warn('No events to initialize on AMQP'); - return; - } - - const eventKeys = Object.keys(events); - - eventKeys.forEach((event) => { - if (events[event] === false) return; - - const queueName = `${event.replace(/_/g, '.').toLowerCase()}`; - const amqp = getAMQP(); - const exchangeName = 'evolution_exchange'; - - amqp.assertExchange(exchangeName, 'topic', { - durable: true, - autoDelete: false, - }); - - amqp.assertQueue(queueName, { - durable: true, - autoDelete: false, - arguments: { - 'x-queue-type': 'quorum', - }, - }); - - amqp.bindQueue(queueName, exchangeName, event); - }); -}; - -export const initQueues = (instanceName: string, events: string[]) => { - if (!events || !events.length) return; - - const queues = events.map((event) => { - return `${event.replace(/_/g, '.').toLowerCase()}`; - }); - - queues.forEach((event) => { - const amqp = getAMQP(); - const exchangeName = instanceName ?? 'evolution_exchange'; - - amqp.assertExchange(exchangeName, 'topic', { - durable: true, - autoDelete: false, - }); - - const queueName = `${instanceName}.${event}`; - - amqp.assertQueue(queueName, { - durable: true, - autoDelete: false, - arguments: { - 'x-queue-type': 'quorum', - }, - }); - - amqp.bindQueue(queueName, exchangeName, event); - }); -}; - -export const removeQueues = (instanceName: string, events: string[]) => { - if (!events || !events.length) return; - - const channel = getAMQP(); - - const queues = events.map((event) => { - return `${event.replace(/_/g, '.').toLowerCase()}`; - }); - - const exchangeName = instanceName ?? 'evolution_exchange'; - - queues.forEach((event) => { - const amqp = getAMQP(); - - amqp.assertExchange(exchangeName, 'topic', { - durable: true, - autoDelete: false, - }); - - const queueName = `${instanceName}.${event}`; - - amqp.deleteQueue(queueName); - }); - - channel.deleteExchange(exchangeName); -}; diff --git a/src/api/integrations/rabbitmq/models/rabbitmq.model.ts b/src/api/integrations/rabbitmq/models/rabbitmq.model.ts deleted file mode 100644 index ba0ac1af..00000000 --- a/src/api/integrations/rabbitmq/models/rabbitmq.model.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Schema } from 'mongoose'; - -import { dbserver } from '../../../../libs/db.connect'; - -export class RabbitmqRaw { - _id?: string; - enabled?: boolean; - events?: string[]; -} - -const rabbitmqSchema = new Schema({ - _id: { type: String, _id: true }, - enabled: { type: Boolean, required: true }, - events: { type: [String], required: true }, -}); - -export const RabbitmqModel = dbserver?.model(RabbitmqRaw.name, rabbitmqSchema, 'rabbitmq'); -export type IRabbitmqModel = typeof RabbitmqModel; diff --git a/src/api/integrations/rabbitmq/repository/rabbitmq.repository.ts b/src/api/integrations/rabbitmq/repository/rabbitmq.repository.ts deleted file mode 100644 index cb30c7c3..00000000 --- a/src/api/integrations/rabbitmq/repository/rabbitmq.repository.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { readFileSync } from 'fs'; -import { join } from 'path'; - -import { ConfigService } from '../../../../config/env.config'; -import { Logger } from '../../../../config/logger.config'; -import { IInsert, Repository } from '../../../abstract/abstract.repository'; -import { IRabbitmqModel, RabbitmqRaw } from '../../../models'; - -export class RabbitmqRepository extends Repository { - constructor(private readonly rabbitmqModel: IRabbitmqModel, private readonly configService: ConfigService) { - super(configService); - } - - private readonly logger = new Logger('RabbitmqRepository'); - - public async create(data: RabbitmqRaw, instance: string): Promise { - try { - this.logger.verbose('creating rabbitmq'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('saving rabbitmq to db'); - const insert = await this.rabbitmqModel.replaceOne({ _id: instance }, { ...data }, { upsert: true }); - - this.logger.verbose('rabbitmq saved to db: ' + insert.modifiedCount + ' rabbitmq'); - return { insertCount: insert.modifiedCount }; - } - - this.logger.verbose('saving rabbitmq to store'); - - this.writeStore({ - path: join(this.storePath, 'rabbitmq'), - fileName: instance, - data, - }); - - this.logger.verbose('rabbitmq saved to store in path: ' + join(this.storePath, 'rabbitmq') + '/' + instance); - - this.logger.verbose('rabbitmq created'); - return { insertCount: 1 }; - } catch (error) { - return error; - } - } - - public async find(instance: string): Promise { - try { - this.logger.verbose('finding rabbitmq'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding rabbitmq in db'); - return await this.rabbitmqModel.findOne({ _id: instance }); - } - - this.logger.verbose('finding rabbitmq in store'); - return JSON.parse( - readFileSync(join(this.storePath, 'rabbitmq', instance + '.json'), { - encoding: 'utf-8', - }), - ) as RabbitmqRaw; - } catch (error) { - return {}; - } - } -} diff --git a/src/api/integrations/rabbitmq/routes/rabbitmq.router.ts b/src/api/integrations/rabbitmq/routes/rabbitmq.router.ts deleted file mode 100644 index a477a5ba..00000000 --- a/src/api/integrations/rabbitmq/routes/rabbitmq.router.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { RequestHandler, Router } from 'express'; - -import { Logger } from '../../../../config/logger.config'; -import { instanceNameSchema, rabbitmqSchema } from '../../../../validate/validate.schema'; -import { RouterBroker } from '../../../abstract/abstract.router'; -import { InstanceDto } from '../../../dto/instance.dto'; -import { HttpStatus } from '../../../routes/index.router'; -import { rabbitmqController } from '../../../server.module'; -import { RabbitmqDto } from '../dto/rabbitmq.dto'; - -const logger = new Logger('RabbitmqRouter'); - -export class RabbitmqRouter extends RouterBroker { - constructor(...guards: RequestHandler[]) { - super(); - this.router - .post(this.routerPath('set'), ...guards, async (req, res) => { - logger.verbose('request received in setRabbitmq'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - const response = await this.dataValidate({ - request: req, - schema: rabbitmqSchema, - ClassRef: RabbitmqDto, - execute: (instance, data) => rabbitmqController.createRabbitmq(instance, data), - }); - - res.status(HttpStatus.CREATED).json(response); - }) - .get(this.routerPath('find'), ...guards, async (req, res) => { - logger.verbose('request received in findRabbitmq'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - const response = await this.dataValidate({ - request: req, - schema: instanceNameSchema, - ClassRef: InstanceDto, - execute: (instance) => rabbitmqController.findRabbitmq(instance), - }); - - res.status(HttpStatus.OK).json(response); - }); - } - - public readonly router = Router(); -} diff --git a/src/api/integrations/rabbitmq/services/rabbitmq.service.ts b/src/api/integrations/rabbitmq/services/rabbitmq.service.ts deleted file mode 100644 index efb822fd..00000000 --- a/src/api/integrations/rabbitmq/services/rabbitmq.service.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { Logger } from '../../../../config/logger.config'; -import { InstanceDto } from '../../../dto/instance.dto'; -import { RabbitmqRaw } from '../../../models'; -import { WAMonitoringService } from '../../../services/monitor.service'; -import { RabbitmqDto } from '../dto/rabbitmq.dto'; -import { initQueues } from '../libs/amqp.server'; - -export class RabbitmqService { - constructor(private readonly waMonitor: WAMonitoringService) {} - - private readonly logger = new Logger(RabbitmqService.name); - - public create(instance: InstanceDto, data: RabbitmqDto) { - this.logger.verbose('create rabbitmq: ' + instance.instanceName); - this.waMonitor.waInstances[instance.instanceName].setRabbitmq(data); - - initQueues(instance.instanceName, data.events); - return { rabbitmq: { ...instance, rabbitmq: data } }; - } - - public async find(instance: InstanceDto): Promise { - try { - this.logger.verbose('find rabbitmq: ' + instance.instanceName); - const result = await this.waMonitor.waInstances[instance.instanceName].findRabbitmq(); - - if (Object.keys(result).length === 0) { - throw new Error('Rabbitmq not found'); - } - - return result; - } catch (error) { - return { enabled: false, events: [] }; - } - } -} diff --git a/src/api/integrations/rabbitmq/validate/rabbitmq.schema.ts b/src/api/integrations/rabbitmq/validate/rabbitmq.schema.ts deleted file mode 100644 index 7a786bb4..00000000 --- a/src/api/integrations/rabbitmq/validate/rabbitmq.schema.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { JSONSchema7 } from 'json-schema'; -import { v4 } from 'uuid'; - -const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => { - const properties = {}; - propertyNames.forEach( - (property) => - (properties[property] = { - minLength: 1, - description: `The "${property}" cannot be empty`, - }), - ); - return { - if: { - propertyNames: { - enum: [...propertyNames], - }, - }, - then: { properties }, - }; -}; - -export const rabbitmqSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - enabled: { type: 'boolean', enum: [true, false] }, - events: { - type: 'array', - minItems: 0, - items: { - type: 'string', - enum: [ - 'APPLICATION_STARTUP', - 'QRCODE_UPDATED', - 'MESSAGES_SET', - 'MESSAGES_UPSERT', - 'MESSAGES_UPDATE', - 'MESSAGES_DELETE', - 'SEND_MESSAGE', - 'CONTACTS_SET', - 'CONTACTS_UPSERT', - 'CONTACTS_UPDATE', - 'PRESENCE_UPDATE', - 'CHATS_SET', - 'CHATS_UPSERT', - 'CHATS_UPDATE', - 'CHATS_DELETE', - 'GROUPS_UPSERT', - 'GROUP_UPDATE', - 'GROUP_PARTICIPANTS_UPDATE', - 'CONNECTION_UPDATE', - 'LABELS_EDIT', - 'LABELS_ASSOCIATION', - 'CALL', - 'NEW_JWT_TOKEN', - 'TYPEBOT_START', - 'TYPEBOT_CHANGE_STATUS', - 'CHAMA_AI_ACTION', - ], - }, - }, - }, - required: ['enabled'], - ...isNotEmpty('enabled'), -}; diff --git a/src/api/integrations/sqs/controllers/sqs.controller.ts b/src/api/integrations/sqs/controllers/sqs.controller.ts deleted file mode 100644 index d6dd346b..00000000 --- a/src/api/integrations/sqs/controllers/sqs.controller.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { Logger } from '../../../../config/logger.config'; -import { InstanceDto } from '../../../dto/instance.dto'; -import { SqsDto } from '../dto/sqs.dto'; -import { SqsService } from '../services/sqs.service'; - -const logger = new Logger('SqsController'); - -export class SqsController { - constructor(private readonly sqsService: SqsService) {} - - public async createSqs(instance: InstanceDto, data: SqsDto) { - logger.verbose('requested createSqs from ' + instance.instanceName + ' instance'); - - if (!data.enabled) { - logger.verbose('sqs disabled'); - data.events = []; - } - - if (data.events.length === 0) { - logger.verbose('sqs events empty'); - data.events = [ - 'APPLICATION_STARTUP', - 'QRCODE_UPDATED', - 'MESSAGES_SET', - 'MESSAGES_UPSERT', - 'MESSAGES_UPDATE', - 'MESSAGES_DELETE', - 'SEND_MESSAGE', - 'CONTACTS_SET', - 'CONTACTS_UPSERT', - 'CONTACTS_UPDATE', - 'PRESENCE_UPDATE', - 'CHATS_SET', - 'CHATS_UPSERT', - 'CHATS_UPDATE', - 'CHATS_DELETE', - 'GROUPS_UPSERT', - 'GROUP_UPDATE', - 'GROUP_PARTICIPANTS_UPDATE', - 'CONNECTION_UPDATE', - 'LABELS_EDIT', - 'LABELS_ASSOCIATION', - 'CALL', - 'NEW_JWT_TOKEN', - 'TYPEBOT_START', - 'TYPEBOT_CHANGE_STATUS', - 'CHAMA_AI_ACTION', - ]; - } - - return this.sqsService.create(instance, data); - } - - public async findSqs(instance: InstanceDto) { - logger.verbose('requested findSqs from ' + instance.instanceName + ' instance'); - return this.sqsService.find(instance); - } -} diff --git a/src/api/integrations/sqs/dto/sqs.dto.ts b/src/api/integrations/sqs/dto/sqs.dto.ts deleted file mode 100644 index 9b8aeedd..00000000 --- a/src/api/integrations/sqs/dto/sqs.dto.ts +++ /dev/null @@ -1,4 +0,0 @@ -export class SqsDto { - enabled: boolean; - events?: string[]; -} diff --git a/src/api/integrations/sqs/libs/sqs.server.ts b/src/api/integrations/sqs/libs/sqs.server.ts deleted file mode 100644 index 3dc1d95d..00000000 --- a/src/api/integrations/sqs/libs/sqs.server.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { SQS } from '@aws-sdk/client-sqs'; - -import { configService, Sqs } from '../../../../config/env.config'; -import { Logger } from '../../../../config/logger.config'; - -const logger = new Logger('SQS'); - -let sqs: SQS; - -export const initSQS = () => { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - return new Promise((resolve, reject) => { - const awsConfig = configService.get('SQS'); - sqs = new SQS({ - credentials: { - accessKeyId: awsConfig.ACCESS_KEY_ID, - secretAccessKey: awsConfig.SECRET_ACCESS_KEY, - }, - - region: awsConfig.REGION, - }); - - logger.info('SQS initialized'); - resolve(); - }); -}; - -export const getSQS = (): SQS => { - return sqs; -}; - -export const initQueues = (instanceName: string, events: string[]) => { - if (!events || !events.length) return; - - const queues = events.map((event) => { - return `${event.replace(/_/g, '_').toLowerCase()}`; - }); - - const sqs = getSQS(); - - queues.forEach((event) => { - const queueName = `${instanceName}_${event}.fifo`; - - sqs.createQueue( - { - QueueName: queueName, - Attributes: { - FifoQueue: 'true', - }, - }, - (err, data) => { - if (err) { - logger.error(`Error creating queue ${queueName}: ${err.message}`); - } else { - logger.info(`Queue ${queueName} created: ${data.QueueUrl}`); - } - }, - ); - }); -}; - -export const removeQueues = (instanceName: string, events: string[]) => { - if (!events || !events.length) return; - - const sqs = getSQS(); - - const queues = events.map((event) => { - return `${event.replace(/_/g, '_').toLowerCase()}`; - }); - - queues.forEach((event) => { - const queueName = `${instanceName}_${event}.fifo`; - - sqs.getQueueUrl( - { - QueueName: queueName, - }, - (err, data) => { - if (err) { - logger.error(`Error getting queue URL for ${queueName}: ${err.message}`); - } else { - const queueUrl = data.QueueUrl; - - sqs.deleteQueue( - { - QueueUrl: queueUrl, - }, - (deleteErr) => { - if (deleteErr) { - logger.error(`Error deleting queue ${queueName}: ${deleteErr.message}`); - } else { - logger.info(`Queue ${queueName} deleted`); - } - }, - ); - } - }, - ); - }); -}; diff --git a/src/api/integrations/sqs/models/sqs.model.ts b/src/api/integrations/sqs/models/sqs.model.ts deleted file mode 100644 index c3ac4fb1..00000000 --- a/src/api/integrations/sqs/models/sqs.model.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Schema } from 'mongoose'; - -import { dbserver } from '../../../../libs/db.connect'; - -export class SqsRaw { - _id?: string; - enabled?: boolean; - events?: string[]; -} - -const sqsSchema = new Schema({ - _id: { type: String, _id: true }, - enabled: { type: Boolean, required: true }, - events: { type: [String], required: true }, -}); - -export const SqsModel = dbserver?.model(SqsRaw.name, sqsSchema, 'sqs'); -export type ISqsModel = typeof SqsModel; diff --git a/src/api/integrations/sqs/repository/sqs.repository.ts b/src/api/integrations/sqs/repository/sqs.repository.ts deleted file mode 100644 index 7e149daa..00000000 --- a/src/api/integrations/sqs/repository/sqs.repository.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { readFileSync } from 'fs'; -import { join } from 'path'; - -import { ConfigService } from '../../../../config/env.config'; -import { Logger } from '../../../../config/logger.config'; -import { IInsert, Repository } from '../../../abstract/abstract.repository'; -import { ISqsModel, SqsRaw } from '../../../models'; - -export class SqsRepository extends Repository { - constructor(private readonly sqsModel: ISqsModel, private readonly configService: ConfigService) { - super(configService); - } - - private readonly logger = new Logger('SqsRepository'); - - public async create(data: SqsRaw, instance: string): Promise { - try { - this.logger.verbose('creating sqs'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('saving sqs to db'); - const insert = await this.sqsModel.replaceOne({ _id: instance }, { ...data }, { upsert: true }); - - this.logger.verbose('sqs saved to db: ' + insert.modifiedCount + ' sqs'); - return { insertCount: insert.modifiedCount }; - } - - this.logger.verbose('saving sqs to store'); - - this.writeStore({ - path: join(this.storePath, 'sqs'), - fileName: instance, - data, - }); - - this.logger.verbose('sqs saved to store in path: ' + join(this.storePath, 'sqs') + '/' + instance); - - this.logger.verbose('sqs created'); - return { insertCount: 1 }; - } catch (error) { - return error; - } - } - - public async find(instance: string): Promise { - try { - this.logger.verbose('finding sqs'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding sqs in db'); - return await this.sqsModel.findOne({ _id: instance }); - } - - this.logger.verbose('finding sqs in store'); - return JSON.parse( - readFileSync(join(this.storePath, 'sqs', instance + '.json'), { - encoding: 'utf-8', - }), - ) as SqsRaw; - } catch (error) { - return {}; - } - } -} diff --git a/src/api/integrations/sqs/routes/sqs.router.ts b/src/api/integrations/sqs/routes/sqs.router.ts deleted file mode 100644 index 80d14838..00000000 --- a/src/api/integrations/sqs/routes/sqs.router.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { RequestHandler, Router } from 'express'; - -import { Logger } from '../../../../config/logger.config'; -import { instanceNameSchema, sqsSchema } from '../../../../validate/validate.schema'; -import { RouterBroker } from '../../../abstract/abstract.router'; -import { InstanceDto } from '../../../dto/instance.dto'; -import { HttpStatus } from '../../../routes/index.router'; -import { sqsController } from '../../../server.module'; -import { SqsDto } from '../dto/sqs.dto'; - -const logger = new Logger('SqsRouter'); - -export class SqsRouter extends RouterBroker { - constructor(...guards: RequestHandler[]) { - super(); - this.router - .post(this.routerPath('set'), ...guards, async (req, res) => { - logger.verbose('request received in setSqs'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - const response = await this.dataValidate({ - request: req, - schema: sqsSchema, - ClassRef: SqsDto, - execute: (instance, data) => sqsController.createSqs(instance, data), - }); - - res.status(HttpStatus.CREATED).json(response); - }) - .get(this.routerPath('find'), ...guards, async (req, res) => { - logger.verbose('request received in findSqs'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - const response = await this.dataValidate({ - request: req, - schema: instanceNameSchema, - ClassRef: InstanceDto, - execute: (instance) => sqsController.findSqs(instance), - }); - - res.status(HttpStatus.OK).json(response); - }); - } - - public readonly router = Router(); -} diff --git a/src/api/integrations/sqs/services/sqs.service.ts b/src/api/integrations/sqs/services/sqs.service.ts deleted file mode 100644 index 52780104..00000000 --- a/src/api/integrations/sqs/services/sqs.service.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { Logger } from '../../../../config/logger.config'; -import { InstanceDto } from '../../../dto/instance.dto'; -import { SqsRaw } from '../../../models'; -import { WAMonitoringService } from '../../../services/monitor.service'; -import { SqsDto } from '../dto/sqs.dto'; -import { initQueues } from '../libs/sqs.server'; - -export class SqsService { - constructor(private readonly waMonitor: WAMonitoringService) {} - - private readonly logger = new Logger(SqsService.name); - - public create(instance: InstanceDto, data: SqsDto) { - this.logger.verbose('create sqs: ' + instance.instanceName); - this.waMonitor.waInstances[instance.instanceName].setSqs(data); - - initQueues(instance.instanceName, data.events); - return { sqs: { ...instance, sqs: data } }; - } - - public async find(instance: InstanceDto): Promise { - try { - this.logger.verbose('find sqs: ' + instance.instanceName); - const result = await this.waMonitor.waInstances[instance.instanceName].findSqs(); - - if (Object.keys(result).length === 0) { - throw new Error('Sqs not found'); - } - - return result; - } catch (error) { - return { enabled: false, events: [] }; - } - } -} diff --git a/src/api/integrations/sqs/validate/sqs.schema.ts b/src/api/integrations/sqs/validate/sqs.schema.ts deleted file mode 100644 index 54379c29..00000000 --- a/src/api/integrations/sqs/validate/sqs.schema.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { JSONSchema7 } from 'json-schema'; -import { v4 } from 'uuid'; - -const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => { - const properties = {}; - propertyNames.forEach( - (property) => - (properties[property] = { - minLength: 1, - description: `The "${property}" cannot be empty`, - }), - ); - return { - if: { - propertyNames: { - enum: [...propertyNames], - }, - }, - then: { properties }, - }; -}; - -export const sqsSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - enabled: { type: 'boolean', enum: [true, false] }, - events: { - type: 'array', - minItems: 0, - items: { - type: 'string', - enum: [ - 'APPLICATION_STARTUP', - 'QRCODE_UPDATED', - 'MESSAGES_SET', - 'MESSAGES_UPSERT', - 'MESSAGES_UPDATE', - 'MESSAGES_DELETE', - 'SEND_MESSAGE', - 'CONTACTS_SET', - 'CONTACTS_UPSERT', - 'CONTACTS_UPDATE', - 'PRESENCE_UPDATE', - 'CHATS_SET', - 'CHATS_UPSERT', - 'CHATS_UPDATE', - 'CHATS_DELETE', - 'GROUPS_UPSERT', - 'GROUP_UPDATE', - 'GROUP_PARTICIPANTS_UPDATE', - 'CONNECTION_UPDATE', - 'LABELS_EDIT', - 'LABELS_ASSOCIATION', - 'CALL', - 'NEW_JWT_TOKEN', - 'TYPEBOT_START', - 'TYPEBOT_CHANGE_STATUS', - 'CHAMA_AI_ACTION', - ], - }, - }, - }, - required: ['enabled'], - ...isNotEmpty('enabled'), -}; diff --git a/src/api/integrations/storage/s3/controllers/s3.controller.ts b/src/api/integrations/storage/s3/controllers/s3.controller.ts new file mode 100644 index 00000000..a72adc64 --- /dev/null +++ b/src/api/integrations/storage/s3/controllers/s3.controller.ts @@ -0,0 +1,15 @@ +import { InstanceDto } from '@api/dto/instance.dto'; +import { MediaDto } from '@api/integrations/storage/s3/dto/media.dto'; +import { S3Service } from '@api/integrations/storage/s3/services/s3.service'; + +export class S3Controller { + constructor(private readonly s3Service: S3Service) {} + + public async getMedia(instance: InstanceDto, data: MediaDto) { + return this.s3Service.getMedia(instance, data); + } + + public async getMediaUrl(instance: InstanceDto, data: MediaDto) { + return this.s3Service.getMediaUrl(instance, data); + } +} diff --git a/src/api/integrations/storage/s3/dto/media.dto.ts b/src/api/integrations/storage/s3/dto/media.dto.ts new file mode 100644 index 00000000..1c6c5855 --- /dev/null +++ b/src/api/integrations/storage/s3/dto/media.dto.ts @@ -0,0 +1,6 @@ +export class MediaDto { + id?: string; + type?: string; + messageId?: number; + expiry?: number; +} diff --git a/src/api/integrations/storage/s3/libs/minio.server.ts b/src/api/integrations/storage/s3/libs/minio.server.ts new file mode 100644 index 00000000..5a66305c --- /dev/null +++ b/src/api/integrations/storage/s3/libs/minio.server.ts @@ -0,0 +1,139 @@ +import { ConfigService, S3 } from '@config/env.config'; +import { Logger } from '@config/logger.config'; +import { BadRequestException } from '@exceptions'; +import * as MinIo from 'minio'; +import { join } from 'path'; +import { Readable, Transform } from 'stream'; + +const logger = new Logger('S3 Service'); + +const BUCKET = new ConfigService().get('S3'); + +interface Metadata extends MinIo.ItemBucketMetadata { + 'Content-Type': string; +} + +const minioClient = (() => { + if (BUCKET?.ENABLE) { + return new MinIo.Client({ + endPoint: BUCKET.ENDPOINT, + port: BUCKET.PORT, + useSSL: BUCKET.USE_SSL, + accessKey: BUCKET.ACCESS_KEY, + secretKey: BUCKET.SECRET_KEY, + region: BUCKET.REGION, + }); + } +})(); + +const bucketName = process.env.S3_BUCKET; + +const bucketExists = async () => { + if (minioClient) { + try { + const list = await minioClient.listBuckets(); + return list.find((bucket) => bucket.name === bucketName); + } catch (error) { + return false; + } + } +}; + +const setBucketPolicy = async () => { + if (minioClient) { + const policy = { + Version: '2012-10-17', + Statement: [ + { + Effect: 'Allow', + Principal: '*', + Action: ['s3:GetObject'], + Resource: [`arn:aws:s3:::${bucketName}/*`], + }, + ], + }; + await minioClient.setBucketPolicy(bucketName, JSON.stringify(policy)); + } +}; + +const createBucket = async () => { + if (minioClient) { + try { + const exists = await bucketExists(); + if (!exists) { + await minioClient.makeBucket(bucketName); + } + + await setBucketPolicy(); + + logger.info(`S3 Bucket ${bucketName} - ON`); + return true; + } catch (error) { + logger.error('S3 ERROR:'); + logger.error(error); + return false; + } + } +}; + +createBucket(); + +const uploadFile = async (fileName: string, file: Buffer | Transform | Readable, size: number, metadata: Metadata) => { + if (minioClient) { + const objectName = join('evolution-api', fileName); + try { + metadata['custom-header-application'] = 'evolution-api'; + return await minioClient.putObject(bucketName, objectName, file, size, metadata); + } catch (error) { + logger.error(error); + return error; + } + } +}; + +const getObjectUrl = async (fileName: string, expiry?: number) => { + if (minioClient) { + try { + const objectName = join('evolution-api', fileName); + if (expiry) { + return await minioClient.presignedGetObject(bucketName, objectName, expiry); + } + return await minioClient.presignedGetObject(bucketName, objectName); + } catch (error) { + throw new BadRequestException(error?.message); + } + } +}; + +const uploadTempFile = async ( + folder: string, + fileName: string, + file: Buffer | Transform | Readable, + size: number, + metadata: Metadata, +) => { + if (minioClient) { + const objectName = join(folder, fileName); + try { + metadata['custom-header-application'] = 'evolution-api'; + return await minioClient.putObject(bucketName, objectName, file, size, metadata); + } catch (error) { + logger.error(error); + return error; + } + } +}; + +const deleteFile = async (folder: string, fileName: string) => { + if (minioClient) { + const objectName = join(folder, fileName); + try { + return await minioClient.removeObject(bucketName, objectName); + } catch (error) { + logger.error(error); + return error; + } + } +}; + +export { BUCKET, deleteFile, getObjectUrl, uploadFile, uploadTempFile }; diff --git a/src/api/integrations/storage/s3/routes/s3.router.ts b/src/api/integrations/storage/s3/routes/s3.router.ts new file mode 100644 index 00000000..0ef8379e --- /dev/null +++ b/src/api/integrations/storage/s3/routes/s3.router.ts @@ -0,0 +1,35 @@ +import { RouterBroker } from '@api/abstract/abstract.router'; +import { MediaDto } from '@api/integrations/storage/s3/dto/media.dto'; +import { s3Schema, s3UrlSchema } from '@api/integrations/storage/s3/validate/s3.schema'; +import { HttpStatus } from '@api/routes/index.router'; +import { s3Controller } from '@api/server.module'; +import { RequestHandler, Router } from 'express'; + +export class S3Router extends RouterBroker { + constructor(...guards: RequestHandler[]) { + super(); + this.router + .post(this.routerPath('getMedia'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: s3Schema, + ClassRef: MediaDto, + execute: (instance, data) => s3Controller.getMedia(instance, data), + }); + + res.status(HttpStatus.CREATED).json(response); + }) + .post(this.routerPath('getMediaUrl'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: s3UrlSchema, + ClassRef: MediaDto, + execute: (instance, data) => s3Controller.getMediaUrl(instance, data), + }); + + res.status(HttpStatus.OK).json(response); + }); + } + + public readonly router: Router = Router(); +} diff --git a/src/api/integrations/storage/s3/services/s3.service.ts b/src/api/integrations/storage/s3/services/s3.service.ts new file mode 100644 index 00000000..3a0c913b --- /dev/null +++ b/src/api/integrations/storage/s3/services/s3.service.ts @@ -0,0 +1,50 @@ +import { InstanceDto } from '@api/dto/instance.dto'; +import { MediaDto } from '@api/integrations/storage/s3/dto/media.dto'; +import { getObjectUrl } from '@api/integrations/storage/s3/libs/minio.server'; +import { PrismaRepository } from '@api/repository/repository.service'; +import { Logger } from '@config/logger.config'; +import { BadRequestException } from '@exceptions'; + +export class S3Service { + constructor(private readonly prismaRepository: PrismaRepository) {} + + private readonly logger = new Logger('S3Service'); + + public async getMedia(instance: InstanceDto, query?: MediaDto) { + try { + const where: any = { + instanceId: instance.instanceId, + ...query, + }; + + const media = await this.prismaRepository.media.findMany({ + where, + select: { + id: true, + fileName: true, + type: true, + mimetype: true, + createdAt: true, + Message: true, + }, + }); + + if (!media || media.length === 0) { + throw 'Media not found'; + } + + return media; + } catch (error) { + throw new BadRequestException(error); + } + } + + public async getMediaUrl(instance: InstanceDto, data: MediaDto) { + const media = (await this.getMedia(instance, { id: data.id }))[0]; + const mediaUrl = await getObjectUrl(media.fileName, data.expiry); + return { + mediaUrl, + ...media, + }; + } +} diff --git a/src/api/integrations/storage/s3/validate/s3.schema.ts b/src/api/integrations/storage/s3/validate/s3.schema.ts new file mode 100644 index 00000000..00709a9b --- /dev/null +++ b/src/api/integrations/storage/s3/validate/s3.schema.ts @@ -0,0 +1,43 @@ +import { JSONSchema7 } from 'json-schema'; +import { v4 } from 'uuid'; + +const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => { + const properties = {}; + propertyNames.forEach( + (property) => + (properties[property] = { + minLength: 1, + description: `The "${property}" cannot be empty`, + }), + ); + return { + if: { + propertyNames: { + enum: [...propertyNames], + }, + }, + then: { properties }, + }; +}; + +export const s3Schema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + id: { type: 'string' }, + type: { type: 'string' }, + messageId: { type: 'integer' }, + }, + ...isNotEmpty('id', 'type', 'messageId'), +}; + +export const s3UrlSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + id: { type: 'string', pattern: '\\d+', minLength: 1 }, + expiry: { type: 'string', pattern: '\\d+', minLength: 1 }, + }, + ...isNotEmpty('id'), + required: ['id'], +}; diff --git a/src/api/integrations/storage/storage.router.ts b/src/api/integrations/storage/storage.router.ts new file mode 100644 index 00000000..7bbcb837 --- /dev/null +++ b/src/api/integrations/storage/storage.router.ts @@ -0,0 +1,12 @@ +import { S3Router } from '@api/integrations/storage/s3/routes/s3.router'; +import { Router } from 'express'; + +export class StorageRouter { + public readonly router: Router; + + constructor(...guards: any[]) { + this.router = Router(); + + this.router.use('/s3', new S3Router(...guards).router); + } +} diff --git a/src/api/integrations/typebot/controllers/typebot.controller.ts b/src/api/integrations/typebot/controllers/typebot.controller.ts deleted file mode 100644 index bb52a370..00000000 --- a/src/api/integrations/typebot/controllers/typebot.controller.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { Logger } from '../../../../config/logger.config'; -import { InstanceDto } from '../../../dto/instance.dto'; -import { TypebotDto } from '../dto/typebot.dto'; -import { TypebotService } from '../services/typebot.service'; - -const logger = new Logger('TypebotController'); - -export class TypebotController { - constructor(private readonly typebotService: TypebotService) {} - - public async createTypebot(instance: InstanceDto, data: TypebotDto) { - logger.verbose('requested createTypebot from ' + instance.instanceName + ' instance'); - - if (!data.enabled) { - logger.verbose('typebot disabled'); - data.url = ''; - data.typebot = ''; - data.expire = 0; - data.sessions = []; - } else { - const saveData = await this.typebotService.find(instance); - - if (saveData.enabled) { - logger.verbose('typebot enabled'); - data.sessions = saveData.sessions; - } - } - - return this.typebotService.create(instance, data); - } - - public async findTypebot(instance: InstanceDto) { - logger.verbose('requested findTypebot from ' + instance.instanceName + ' instance'); - return this.typebotService.find(instance); - } - - public async changeStatus(instance: InstanceDto, data: any) { - logger.verbose('requested changeStatus from ' + instance.instanceName + ' instance'); - return this.typebotService.changeStatus(instance, data); - } - - public async startTypebot(instance: InstanceDto, data: any) { - logger.verbose('requested startTypebot from ' + instance.instanceName + ' instance'); - return this.typebotService.startTypebot(instance, data); - } -} diff --git a/src/api/integrations/typebot/dto/typebot.dto.ts b/src/api/integrations/typebot/dto/typebot.dto.ts deleted file mode 100644 index 6adfcf33..00000000 --- a/src/api/integrations/typebot/dto/typebot.dto.ts +++ /dev/null @@ -1,27 +0,0 @@ -export class Session { - remoteJid?: string; - sessionId?: string; - status?: string; - createdAt?: number; - updateAt?: number; - prefilledVariables?: PrefilledVariables; -} - -export class PrefilledVariables { - remoteJid?: string; - pushName?: string; - messageType?: string; - additionalData?: { [key: string]: any }; -} - -export class TypebotDto { - enabled?: boolean; - url: string; - typebot?: string; - expire?: number; - keyword_finish?: string; - delay_message?: number; - unknown_message?: string; - listening_from_me?: boolean; - sessions?: Session[]; -} diff --git a/src/api/integrations/typebot/models/typebot.model.ts b/src/api/integrations/typebot/models/typebot.model.ts deleted file mode 100644 index 9060b6e0..00000000 --- a/src/api/integrations/typebot/models/typebot.model.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { Schema } from 'mongoose'; - -import { dbserver } from '../../../../libs/db.connect'; - -class Session { - remoteJid?: string; - sessionId?: string; - status?: string; - createdAt?: number; - updateAt?: number; - prefilledVariables?: { - remoteJid?: string; - pushName?: string; - additionalData?: { [key: string]: any }; - }; -} - -export class TypebotRaw { - _id?: string; - enabled?: boolean; - url: string; - typebot?: string; - expire?: number; - keyword_finish?: string; - delay_message?: number; - unknown_message?: string; - listening_from_me?: boolean; - sessions?: Session[]; -} - -const typebotSchema = new Schema({ - _id: { type: String, _id: true }, - enabled: { type: Boolean, required: true }, - url: { type: String, required: true }, - typebot: { type: String, required: true }, - expire: { type: Number, required: true }, - keyword_finish: { type: String, required: true }, - delay_message: { type: Number, required: true }, - unknown_message: { type: String, required: true }, - listening_from_me: { type: Boolean, required: true }, - sessions: [ - { - remoteJid: { type: String, required: true }, - sessionId: { type: String, required: true }, - status: { type: String, required: true }, - createdAt: { type: Number, required: true }, - updateAt: { type: Number, required: true }, - prefilledVariables: { - remoteJid: { type: String, required: false }, - pushName: { type: String, required: false }, - additionalData: { type: Schema.Types.Mixed, required: false }, - }, - }, - ], -}); - -export const TypebotModel = dbserver?.model(TypebotRaw.name, typebotSchema, 'typebot'); -export type ITypebotModel = typeof TypebotModel; diff --git a/src/api/integrations/typebot/repository/typebot.repository.ts b/src/api/integrations/typebot/repository/typebot.repository.ts deleted file mode 100644 index 45453c63..00000000 --- a/src/api/integrations/typebot/repository/typebot.repository.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { readFileSync } from 'fs'; -import { join } from 'path'; - -import { ConfigService } from '../../../../config/env.config'; -import { Logger } from '../../../../config/logger.config'; -import { IInsert, Repository } from '../../../abstract/abstract.repository'; -import { ITypebotModel, TypebotRaw } from '../../../models'; - -export class TypebotRepository extends Repository { - constructor(private readonly typebotModel: ITypebotModel, private readonly configService: ConfigService) { - super(configService); - } - - private readonly logger = new Logger('TypebotRepository'); - - public async create(data: TypebotRaw, instance: string): Promise { - try { - this.logger.verbose('creating typebot'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('saving typebot to db'); - const insert = await this.typebotModel.replaceOne({ _id: instance }, { ...data }, { upsert: true }); - - this.logger.verbose('typebot saved to db: ' + insert.modifiedCount + ' typebot'); - return { insertCount: insert.modifiedCount }; - } - - this.logger.verbose('saving typebot to store'); - - this.writeStore({ - path: join(this.storePath, 'typebot'), - fileName: instance, - data, - }); - - this.logger.verbose('typebot saved to store in path: ' + join(this.storePath, 'typebot') + '/' + instance); - - this.logger.verbose('typebot created'); - return { insertCount: 1 }; - } catch (error) { - return error; - } - } - - public async find(instance: string): Promise { - try { - this.logger.verbose('finding typebot'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding typebot in db'); - return await this.typebotModel.findOne({ _id: instance }); - } - - this.logger.verbose('finding typebot in store'); - return JSON.parse( - readFileSync(join(this.storePath, 'typebot', instance + '.json'), { - encoding: 'utf-8', - }), - ) as TypebotRaw; - } catch (error) { - return { - enabled: false, - url: '', - typebot: '', - expire: 0, - sessions: [], - }; - } - } -} diff --git a/src/api/integrations/typebot/routes/typebot.router.ts b/src/api/integrations/typebot/routes/typebot.router.ts deleted file mode 100644 index 2eed2b39..00000000 --- a/src/api/integrations/typebot/routes/typebot.router.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { RequestHandler, Router } from 'express'; - -import { Logger } from '../../../../config/logger.config'; -import { - instanceNameSchema, - typebotSchema, - typebotStartSchema, - typebotStatusSchema, -} from '../../../../validate/validate.schema'; -import { RouterBroker } from '../../../abstract/abstract.router'; -import { InstanceDto } from '../../../dto/instance.dto'; -import { HttpStatus } from '../../../routes/index.router'; -import { typebotController } from '../../../server.module'; -import { TypebotDto } from '../dto/typebot.dto'; - -const logger = new Logger('TypebotRouter'); - -export class TypebotRouter extends RouterBroker { - constructor(...guards: RequestHandler[]) { - super(); - this.router - .post(this.routerPath('set'), ...guards, async (req, res) => { - logger.verbose('request received in setTypebot'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - const response = await this.dataValidate({ - request: req, - schema: typebotSchema, - ClassRef: TypebotDto, - execute: (instance, data) => typebotController.createTypebot(instance, data), - }); - - res.status(HttpStatus.CREATED).json(response); - }) - .get(this.routerPath('find'), ...guards, async (req, res) => { - logger.verbose('request received in findTypebot'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - const response = await this.dataValidate({ - request: req, - schema: instanceNameSchema, - ClassRef: InstanceDto, - execute: (instance) => typebotController.findTypebot(instance), - }); - - res.status(HttpStatus.OK).json(response); - }) - .post(this.routerPath('changeStatus'), ...guards, async (req, res) => { - logger.verbose('request received in changeStatusTypebot'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - const response = await this.dataValidate({ - request: req, - schema: typebotStatusSchema, - ClassRef: InstanceDto, - execute: (instance, data) => typebotController.changeStatus(instance, data), - }); - - res.status(HttpStatus.OK).json(response); - }) - .post(this.routerPath('start'), ...guards, async (req, res) => { - logger.verbose('request received in startTypebot'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - const response = await this.dataValidate({ - request: req, - schema: typebotStartSchema, - ClassRef: InstanceDto, - execute: (instance, data) => typebotController.startTypebot(instance, data), - }); - - res.status(HttpStatus.OK).json(response); - }); - } - - public readonly router = Router(); -} diff --git a/src/api/integrations/typebot/services/typebot.service.ts b/src/api/integrations/typebot/services/typebot.service.ts deleted file mode 100644 index ebdaa920..00000000 --- a/src/api/integrations/typebot/services/typebot.service.ts +++ /dev/null @@ -1,980 +0,0 @@ -import axios from 'axios'; -import EventEmitter2 from 'eventemitter2'; - -import { ConfigService, Typebot } from '../../../../config/env.config'; -import { Logger } from '../../../../config/logger.config'; -import { InstanceDto } from '../../../dto/instance.dto'; -import { MessageRaw } from '../../../models'; -import { WAMonitoringService } from '../../../services/monitor.service'; -import { Events } from '../../../types/wa.types'; -import { Session, TypebotDto } from '../dto/typebot.dto'; - -export class TypebotService { - constructor( - private readonly waMonitor: WAMonitoringService, - private readonly configService: ConfigService, - private readonly eventEmitter: EventEmitter2, - ) { - this.eventEmitter.on('typebot:end', async (data) => { - const keep_open = this.configService.get('TYPEBOT').KEEP_OPEN; - if (keep_open) return; - - await this.clearSessions(data.instance, data.remoteJid); - }); - } - - private readonly logger = new Logger(TypebotService.name); - - public create(instance: InstanceDto, data: TypebotDto) { - this.logger.verbose('create typebot: ' + instance.instanceName); - this.waMonitor.waInstances[instance.instanceName].setTypebot(data); - - return { typebot: { ...instance, typebot: data } }; - } - - public async find(instance: InstanceDto): Promise { - try { - this.logger.verbose('find typebot: ' + instance.instanceName); - const result = await this.waMonitor.waInstances[instance.instanceName].findTypebot(); - - if (Object.keys(result).length === 0) { - throw new Error('Typebot not found'); - } - - return result; - } catch (error) { - return { enabled: false, url: '', typebot: '', expire: 0, sessions: [] }; - } - } - - public async changeStatus(instance: InstanceDto, data: any) { - const remoteJid = data.remoteJid; - const status = data.status; - - const findData = await this.find(instance); - - const session = findData.sessions.find((session) => session.remoteJid === remoteJid); - - if (session) { - if (status === 'closed') { - findData.sessions.splice(findData.sessions.indexOf(session), 1); - - const typebotData = { - enabled: findData.enabled, - url: findData.url, - typebot: findData.typebot, - expire: findData.expire, - keyword_finish: findData.keyword_finish, - delay_message: findData.delay_message, - unknown_message: findData.unknown_message, - listening_from_me: findData.listening_from_me, - sessions: findData.sessions, - }; - - this.create(instance, typebotData); - - return { typebot: { ...instance, typebot: typebotData } }; - } - - findData.sessions.map((session) => { - if (session.remoteJid === remoteJid) { - session.status = status; - } - }); - } else if (status === 'paused') { - const session: Session = { - remoteJid: remoteJid, - sessionId: Math.floor(Math.random() * 10000000000).toString(), - status: status, - createdAt: Date.now(), - updateAt: Date.now(), - prefilledVariables: { - remoteJid: remoteJid, - pushName: '', - additionalData: {}, - }, - }; - findData.sessions.push(session); - } - - const typebotData = { - enabled: findData.enabled, - url: findData.url, - typebot: findData.typebot, - expire: findData.expire, - keyword_finish: findData.keyword_finish, - delay_message: findData.delay_message, - unknown_message: findData.unknown_message, - listening_from_me: findData.listening_from_me, - sessions: findData.sessions, - }; - - this.create(instance, typebotData); - - this.waMonitor.waInstances[instance.instanceName].sendDataWebhook(Events.TYPEBOT_CHANGE_STATUS, { - remoteJid: remoteJid, - status: status, - url: findData.url, - typebot: findData.typebot, - session, - }); - - return { typebot: { ...instance, typebot: typebotData } }; - } - - public async clearSessions(instance: InstanceDto, remoteJid: string) { - const findTypebot = await this.find(instance); - const sessions = (findTypebot.sessions as Session[]) ?? []; - - const sessionWithRemoteJid = sessions.filter((session) => session.remoteJid === remoteJid); - - if (sessionWithRemoteJid.length > 0) { - sessionWithRemoteJid.forEach((session) => { - sessions.splice(sessions.indexOf(session), 1); - }); - - const typebotData = { - enabled: findTypebot.enabled, - url: findTypebot.url, - typebot: findTypebot.typebot, - expire: findTypebot.expire, - keyword_finish: findTypebot.keyword_finish, - delay_message: findTypebot.delay_message, - unknown_message: findTypebot.unknown_message, - listening_from_me: findTypebot.listening_from_me, - sessions, - }; - - this.create(instance, typebotData); - - return sessions; - } - - return sessions; - } - - public async startTypebot(instance: InstanceDto, data: any) { - if (data.remoteJid === 'status@broadcast') return; - - const remoteJid = data.remoteJid; - const url = data.url; - const typebot = data.typebot; - const startSession = data.startSession; - const variables = data.variables; - const findTypebot = await this.find(instance); - const expire = findTypebot.expire; - const keyword_finish = findTypebot.keyword_finish; - const delay_message = findTypebot.delay_message; - const unknown_message = findTypebot.unknown_message; - const listening_from_me = findTypebot.listening_from_me; - - const prefilledVariables = { - remoteJid: remoteJid, - instanceName: instance.instanceName, - }; - - if (variables?.length) { - variables.forEach((variable: { name: string | number; value: string }) => { - prefilledVariables[variable.name] = variable.value; - }); - } - - if (startSession) { - const newSessions = await this.clearSessions(instance, remoteJid); - - const response = await this.createNewSession(instance, { - enabled: findTypebot.enabled, - url: url, - typebot: typebot, - remoteJid: remoteJid, - expire: expire, - keyword_finish: keyword_finish, - delay_message: delay_message, - unknown_message: unknown_message, - listening_from_me: listening_from_me, - sessions: newSessions, - prefilledVariables: prefilledVariables, - }); - - if (response.sessionId) { - await this.sendWAMessage(instance, remoteJid, response.messages, response.input, response.clientSideActions); - - this.waMonitor.waInstances[instance.instanceName].sendDataWebhook(Events.TYPEBOT_START, { - remoteJid: remoteJid, - url: url, - typebot: typebot, - prefilledVariables: prefilledVariables, - sessionId: `${response.sessionId}`, - }); - } else { - throw new Error('Session ID not found in response'); - } - } else { - const id = Math.floor(Math.random() * 10000000000).toString(); - - try { - const version = this.configService.get('TYPEBOT').API_VERSION; - let url: string; - let reqData: {}; - if (version === 'latest') { - url = `${data.url}/api/v1/typebots/${data.typebot}/startChat`; - - reqData = { - prefilledVariables: prefilledVariables, - }; - } else { - url = `${data.url}/api/v1/sendMessage`; - - reqData = { - startParams: { - publicId: data.typebot, - prefilledVariables: prefilledVariables, - }, - }; - } - const request = await axios.post(url, reqData); - - await this.sendWAMessage( - instance, - remoteJid, - request.data.messages, - request.data.input, - request.data.clientSideActions, - ); - - this.waMonitor.waInstances[instance.instanceName].sendDataWebhook(Events.TYPEBOT_START, { - remoteJid: remoteJid, - url: url, - typebot: typebot, - variables: variables, - sessionId: id, - }); - } catch (error) { - this.logger.error(error); - return; - } - } - - return { - typebot: { - ...instance, - typebot: { - url: url, - remoteJid: remoteJid, - typebot: typebot, - prefilledVariables: prefilledVariables, - }, - }, - }; - } - - private getTypeMessage(msg: any) { - this.logger.verbose('get type message'); - const types = { - conversation: msg.conversation, - extendedTextMessage: msg.extendedTextMessage?.text, - audioMessage: msg.audioMessage?.url, - imageMessage: msg.imageMessage?.url, - videoMessage: msg.videoMessage?.url, - documentMessage: msg.documentMessage?.fileName, - contactMessage: msg.contactMessage?.displayName, - locationMessage: msg.locationMessage?.degreesLatitude, - viewOnceMessageV2: - msg.viewOnceMessageV2?.message?.imageMessage?.url || - msg.viewOnceMessageV2?.message?.videoMessage?.url || - msg.viewOnceMessageV2?.message?.audioMessage?.url, - listResponseMessage: msg.listResponseMessage?.singleSelectReply?.selectedRowId, - responseRowId: msg.listResponseMessage?.singleSelectReply?.selectedRowId, - }; - - const messageType = Object.keys(types).find((key) => types[key] !== undefined) || 'unknown'; - - this.logger.verbose('Type message: ' + JSON.stringify(types)); - return { ...types, messageType }; - } - - private getMessageContent(types: any) { - this.logger.verbose('get message content'); - const typeKey = Object.keys(types).find((key) => types[key] !== undefined); - - const result = typeKey ? types[typeKey] : undefined; - - this.logger.verbose('message content: ' + result); - - return result; - } - - private getConversationMessage(msg: any) { - this.logger.verbose('get conversation message'); - - const types = this.getTypeMessage(msg); - - const messageContent = this.getMessageContent(types); - - this.logger.verbose('conversation message: ' + messageContent); - - return messageContent; - } - - private getAudioMessageContent(msg: any) { - this.logger.verbose('get audio message content'); - - const types = this.getTypeMessage(msg); - - const audioContent = types.audioMessage; - - this.logger.verbose('audio message URL: ' + audioContent); - - return audioContent; - } - - private getImageMessageContent(msg: any) { - this.logger.verbose('get image message content'); - - const types = this.getTypeMessage(msg); - - const imageContent = types.imageMessage; - - this.logger.verbose('image message URL: ' + imageContent); - - return imageContent; - } - - private getVideoMessageContent(msg: any) { - this.logger.verbose('get video message content'); - - const types = this.getTypeMessage(msg); - - const videoContent = types.videoMessage; - - this.logger.verbose('video message URL: ' + videoContent); - - return videoContent; - } - - private getDocumentMessageContent(msg: any) { - this.logger.verbose('get document message content'); - - const types = this.getTypeMessage(msg); - - const documentContent = types.documentMessage; - - this.logger.verbose('document message fileName: ' + documentContent); - - return documentContent; - } - - private getContactMessageContent(msg: any) { - this.logger.verbose('get contact message content'); - - const types = this.getTypeMessage(msg); - - const contactContent = types.contactMessage; - - this.logger.verbose('contact message displayName: ' + contactContent); - - return contactContent; - } - - private getLocationMessageContent(msg: any) { - this.logger.verbose('get location message content'); - - const types = this.getTypeMessage(msg); - - const locationContent = types.locationMessage; - - this.logger.verbose('location message degreesLatitude: ' + locationContent); - - return locationContent; - } - - private getViewOnceMessageV2Content(msg: any) { - this.logger.verbose('get viewOnceMessageV2 content'); - - const types = this.getTypeMessage(msg); - - const viewOnceContent = types.viewOnceMessageV2; - - this.logger.verbose('viewOnceMessageV2 URL: ' + viewOnceContent); - - return viewOnceContent; - } - - private getListResponseMessageContent(msg: any) { - this.logger.verbose('get listResponseMessage content'); - - const types = this.getTypeMessage(msg); - - const listResponseContent = types.listResponseMessage || types.responseRowId; - - this.logger.verbose('listResponseMessage selectedRowId: ' + listResponseContent); - - return listResponseContent; - } - public async createNewSession(instance: InstanceDto, data: any) { - if (data.remoteJid === 'status@broadcast') return; - const id = Math.floor(Math.random() * 10000000000).toString(); - - try { - const version = this.configService.get('TYPEBOT').API_VERSION; - let url: string; - let reqData: {}; - if (version === 'latest') { - url = `${data.url}/api/v1/typebots/${data.typebot}/startChat`; - - reqData = { - prefilledVariables: { - ...data.prefilledVariables, - remoteJid: data.remoteJid, - pushName: data.pushName || data.prefilledVariables?.pushName || '', - instanceName: instance.instanceName, - }, - }; - } else { - url = `${data.url}/api/v1/sendMessage`; - - reqData = { - startParams: { - publicId: data.typebot, - prefilledVariables: { - ...data.prefilledVariables, - remoteJid: data.remoteJid, - pushName: data.pushName || data.prefilledVariables?.pushName || '', - instanceName: instance.instanceName, - }, - }, - }; - } - const request = await axios.post(url, reqData); - - if (request?.data?.sessionId) { - data.sessions.push({ - remoteJid: data.remoteJid, - sessionId: `${id}-${request.data.sessionId}`, - status: 'opened', - createdAt: Date.now(), - updateAt: Date.now(), - prefilledVariables: { - ...data.prefilledVariables, - remoteJid: data.remoteJid, - pushName: data.pushName || '', - instanceName: instance.instanceName, - }, - }); - - const typebotData = { - enabled: data.enabled, - url: data.url, - typebot: data.typebot, - expire: data.expire, - keyword_finish: data.keyword_finish, - delay_message: data.delay_message, - unknown_message: data.unknown_message, - listening_from_me: data.listening_from_me, - sessions: data.sessions, - }; - - this.create(instance, typebotData); - } - return request.data; - } catch (error) { - this.logger.error(error); - return; - } - } - - public async sendWAMessage( - instance: InstanceDto, - remoteJid: string, - messages: any[], - input: any[], - clientSideActions: any[], - ) { - processMessages( - this.waMonitor.waInstances[instance.instanceName], - messages, - input, - clientSideActions, - this.eventEmitter, - applyFormatting, - ).catch((err) => { - console.error('Erro ao processar mensagens:', err); - }); - - function findItemAndGetSecondsToWait(array, targetId) { - if (!array) return null; - - for (const item of array) { - if (item.lastBubbleBlockId === targetId) { - return item.wait?.secondsToWaitFor; - } - } - return null; - } - - function applyFormatting(element) { - let text = ''; - - if (element.text) { - text += element.text; - } - - if (element.children && element.type !== 'a') { - for (const child of element.children) { - text += applyFormatting(child); - } - } - - if (element.type === 'p') { - text = text.trim() + '\n'; - } - - if (element.type === 'ol') { - text = - '\n' + - text - .split('\n') - .map((line, index) => (line ? `${index + 1}. ${line}` : '')) - .join('\n'); - } - - if (element.type === 'li') { - text = text - .split('\n') - .map((line) => (line ? ` ${line}` : '')) - .join('\n'); - } - - let formats = ''; - - if (element.bold) { - formats += '*'; - } - - if (element.italic) { - formats += '_'; - } - - if (element.underline) { - formats += '~'; - } - - let formattedText = `${formats}${text}${formats.split('').reverse().join('')}`; - - if (element.url) { - formattedText = element.children[0]?.text ? `[${formattedText}]\n(${element.url})` : `${element.url}`; - } - - return formattedText; - } - - async function processMessages(instance, messages, input, clientSideActions, eventEmitter, applyFormatting) { - for (const message of messages) { - if (message.type === 'text') { - let formattedText = ''; - - for (const richText of message.content.richText) { - for (const element of richText.children) { - formattedText += applyFormatting(element); - } - formattedText += '\n'; - } - - formattedText = formattedText.replace(/\*\*/g, '').replace(/__/, '').replace(/~~/, '').replace(/\n$/, ''); - - await instance.textMessage({ - number: remoteJid.split('@')[0], - options: { - delay: instance.localTypebot.delay_message || 1000, - presence: 'composing', - }, - textMessage: { - text: formattedText, - }, - }); - } - - if (message.type === 'image') { - await instance.mediaMessage({ - number: remoteJid.split('@')[0], - options: { - delay: instance.localTypebot.delay_message || 1000, - presence: 'composing', - }, - mediaMessage: { - mediatype: 'image', - media: message.content.url, - }, - }); - } - - if (message.type === 'video') { - await instance.mediaMessage({ - number: remoteJid.split('@')[0], - options: { - delay: instance.localTypebot.delay_message || 1000, - presence: 'composing', - }, - mediaMessage: { - mediatype: 'video', - media: message.content.url, - }, - }); - } - - if (message.type === 'audio') { - await instance.audioWhatsapp({ - number: remoteJid.split('@')[0], - options: { - delay: instance.localTypebot.delay_message || 1000, - presence: 'recording', - encoding: true, - }, - audioMessage: { - audio: message.content.url, - }, - }); - } - - const wait = findItemAndGetSecondsToWait(clientSideActions, message.id); - - if (wait) { - await new Promise((resolve) => setTimeout(resolve, wait * 1000)); - } - } - - if (input) { - if (input.type === 'choice input') { - let formattedText = ''; - - const items = input.items; - - for (const item of items) { - formattedText += `▶️ ${item.content}\n`; - } - - formattedText = formattedText.replace(/\n$/, ''); - - await instance.textMessage({ - number: remoteJid.split('@')[0], - options: { - delay: instance.localTypebot.delay_message || 1000, - presence: 'composing', - }, - textMessage: { - text: formattedText, - }, - }); - } - } else { - eventEmitter.emit('typebot:end', { - instance: instance, - remoteJid: remoteJid, - }); - } - } - } - - public async sendTypebot(instance: InstanceDto, remoteJid: string, msg: MessageRaw) { - const findTypebot = await this.find(instance); - const url = findTypebot.url; - const typebot = findTypebot.typebot; - const sessions = (findTypebot.sessions as Session[]) ?? []; - const expire = findTypebot.expire; - const keyword_finish = findTypebot.keyword_finish; - const delay_message = findTypebot.delay_message; - const unknown_message = findTypebot.unknown_message; - const listening_from_me = findTypebot.listening_from_me; - const messageType = this.getTypeMessage(msg.message).messageType; - - const session = sessions.find((session) => session.remoteJid === remoteJid); - - try { - if (session && expire && expire > 0) { - const now = Date.now(); - - const diff = now - session.updateAt; - - const diffInMinutes = Math.floor(diff / 1000 / 60); - - if (diffInMinutes > expire) { - const newSessions = await this.clearSessions(instance, remoteJid); - - const data = await this.createNewSession(instance, { - enabled: findTypebot.enabled, - url: url, - typebot: typebot, - expire: expire, - keyword_finish: keyword_finish, - delay_message: delay_message, - unknown_message: unknown_message, - listening_from_me: listening_from_me, - sessions: newSessions, - remoteJid: remoteJid, - pushName: msg.pushName, - }); - - await this.sendWAMessage(instance, remoteJid, data.messages, data.input, data.clientSideActions); - - if (data.messages.length === 0) { - const content = this.getConversationMessage(msg.message); - - if (!content) { - if (unknown_message) { - this.waMonitor.waInstances[instance.instanceName].textMessage({ - number: remoteJid.split('@')[0], - options: { - delay: delay_message || 1000, - presence: 'composing', - }, - textMessage: { - text: unknown_message, - }, - }); - } - return; - } - - if (keyword_finish && content.toLowerCase() === keyword_finish.toLowerCase()) { - const newSessions = await this.clearSessions(instance, remoteJid); - - const typebotData = { - enabled: findTypebot.enabled, - url: url, - typebot: typebot, - expire: expire, - keyword_finish: keyword_finish, - delay_message: delay_message, - unknown_message: unknown_message, - listening_from_me: listening_from_me, - sessions: newSessions, - }; - - this.create(instance, typebotData); - - return; - } - - try { - const version = this.configService.get('TYPEBOT').API_VERSION; - let urlTypebot: string; - let reqData: {}; - if (version === 'latest') { - urlTypebot = `${url}/api/v1/sessions/${data.sessionId}/continueChat`; - reqData = { - message: content, - }; - } else { - urlTypebot = `${url}/api/v1/sendMessage`; - reqData = { - message: content, - sessionId: data.sessionId, - }; - } - - const request = await axios.post(urlTypebot, reqData); - - await this.sendWAMessage( - instance, - remoteJid, - request.data.messages, - request.data.input, - request.data.clientSideActions, - ); - } catch (error) { - this.logger.error(error); - return; - } - } - - return; - } - } - - if (session && session.status !== 'opened') { - return; - } - - if (!session) { - const data = await this.createNewSession(instance, { - enabled: findTypebot.enabled, - url: url, - typebot: typebot, - expire: expire, - keyword_finish: keyword_finish, - delay_message: delay_message, - unknown_message: unknown_message, - listening_from_me: listening_from_me, - sessions: sessions, - remoteJid: remoteJid, - pushName: msg.pushName, - prefilledVariables: { - messageType: messageType, - }, - }); - - await this.sendWAMessage(instance, remoteJid, data.messages, data.input, data.clientSideActions); - - if (data.messages.length === 0) { - const content = this.getConversationMessage(msg.message); - - if (!content) { - if (unknown_message) { - this.waMonitor.waInstances[instance.instanceName].textMessage({ - number: remoteJid.split('@')[0], - options: { - delay: delay_message || 1000, - presence: 'composing', - }, - textMessage: { - text: unknown_message, - }, - }); - } - return; - } - - if (keyword_finish && content.toLowerCase() === keyword_finish.toLowerCase()) { - const newSessions = await this.clearSessions(instance, remoteJid); - - const typebotData = { - enabled: findTypebot.enabled, - url: url, - typebot: typebot, - expire: expire, - keyword_finish: keyword_finish, - delay_message: delay_message, - unknown_message: unknown_message, - listening_from_me: listening_from_me, - sessions: newSessions, - }; - - this.create(instance, typebotData); - - return; - } - - let request: any; - try { - const version = this.configService.get('TYPEBOT').API_VERSION; - let urlTypebot: string; - let reqData: {}; - if (version === 'latest') { - urlTypebot = `${url}/api/v1/sessions/${data.sessionId}/continueChat`; - reqData = { - message: content, - }; - } else { - urlTypebot = `${url}/api/v1/sendMessage`; - reqData = { - message: content, - sessionId: data.sessionId, - }; - } - request = await axios.post(urlTypebot, reqData); - - await this.sendWAMessage( - instance, - remoteJid, - request.data.messages, - request.data.input, - request.data.clientSideActions, - ); - } catch (error) { - this.logger.error(error); - return; - } - } - return; - } - - sessions.map((session) => { - if (session.remoteJid === remoteJid) { - session.updateAt = Date.now(); - } - }); - - const typebotData = { - enabled: findTypebot.enabled, - url: url, - typebot: typebot, - expire: expire, - keyword_finish: keyword_finish, - delay_message: delay_message, - unknown_message: unknown_message, - listening_from_me: listening_from_me, - sessions, - }; - - this.create(instance, typebotData); - - const content = this.getConversationMessage(msg.message); - - if (!content) { - if (unknown_message) { - this.waMonitor.waInstances[instance.instanceName].textMessage({ - number: remoteJid.split('@')[0], - options: { - delay: delay_message || 1000, - presence: 'composing', - }, - textMessage: { - text: unknown_message, - }, - }); - } - return; - } - - if (keyword_finish && content.toLowerCase() === keyword_finish.toLowerCase()) { - const newSessions = await this.clearSessions(instance, remoteJid); - - const typebotData = { - enabled: findTypebot.enabled, - url: url, - typebot: typebot, - expire: expire, - keyword_finish: keyword_finish, - delay_message: delay_message, - unknown_message: unknown_message, - listening_from_me: listening_from_me, - sessions: newSessions, - }; - - this.create(instance, typebotData); - - return; - } - - const version = this.configService.get('TYPEBOT').API_VERSION; - let urlTypebot: string; - let reqData: {}; - if (version === 'latest') { - urlTypebot = `${url}/api/v1/sessions/${session.sessionId.split('-')[1]}/continueChat`; - reqData = { - message: content, - }; - } else { - urlTypebot = `${url}/api/v1/sendMessage`; - reqData = { - message: content, - sessionId: session.sessionId.split('-')[1], - }; - } - const request = await axios.post(urlTypebot, reqData); - - await this.sendWAMessage( - instance, - remoteJid, - request.data.messages, - request.data.input, - request.data.clientSideActions, - ); - - return; - } catch (error) { - this.logger.error(error); - return; - } - } -} diff --git a/src/api/integrations/typebot/validate/typebot.schema.ts b/src/api/integrations/typebot/validate/typebot.schema.ts deleted file mode 100644 index fde9d973..00000000 --- a/src/api/integrations/typebot/validate/typebot.schema.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { JSONSchema7 } from 'json-schema'; -import { v4 } from 'uuid'; - -const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => { - const properties = {}; - propertyNames.forEach( - (property) => - (properties[property] = { - minLength: 1, - description: `The "${property}" cannot be empty`, - }), - ); - return { - if: { - propertyNames: { - enum: [...propertyNames], - }, - }, - then: { properties }, - }; -}; - -export const typebotSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - enabled: { type: 'boolean', enum: [true, false] }, - url: { type: 'string' }, - typebot: { type: 'string' }, - expire: { type: 'integer' }, - delay_message: { type: 'integer' }, - unknown_message: { type: 'string' }, - listening_from_me: { type: 'boolean', enum: [true, false] }, - }, - required: ['enabled', 'url', 'typebot', 'expire', 'delay_message', 'unknown_message', 'listening_from_me'], - ...isNotEmpty('enabled', 'url', 'typebot', 'expire', 'delay_message', 'unknown_message', 'listening_from_me'), -}; - -export const typebotStatusSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - remoteJid: { type: 'string' }, - status: { type: 'string', enum: ['opened', 'closed', 'paused'] }, - }, - required: ['remoteJid', 'status'], - ...isNotEmpty('remoteJid', 'status'), -}; - -export const typebotStartSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - remoteJid: { type: 'string' }, - url: { type: 'string' }, - typebot: { type: 'string' }, - }, - required: ['remoteJid', 'url', 'typebot'], - ...isNotEmpty('remoteJid', 'url', 'typebot'), -}; diff --git a/src/api/integrations/websocket/controllers/websocket.controller.ts b/src/api/integrations/websocket/controllers/websocket.controller.ts deleted file mode 100644 index 2d207b74..00000000 --- a/src/api/integrations/websocket/controllers/websocket.controller.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { Logger } from '../../../../config/logger.config'; -import { InstanceDto } from '../../../dto/instance.dto'; -import { WebsocketDto } from '../dto/websocket.dto'; -import { WebsocketService } from '../services/websocket.service'; - -const logger = new Logger('WebsocketController'); - -export class WebsocketController { - constructor(private readonly websocketService: WebsocketService) {} - - public async createWebsocket(instance: InstanceDto, data: WebsocketDto) { - logger.verbose('requested createWebsocket from ' + instance.instanceName + ' instance'); - - if (!data.enabled) { - logger.verbose('websocket disabled'); - data.events = []; - } - - if (data.events.length === 0) { - logger.verbose('websocket events empty'); - data.events = [ - 'APPLICATION_STARTUP', - 'QRCODE_UPDATED', - 'MESSAGES_SET', - 'MESSAGES_UPSERT', - 'MESSAGES_UPDATE', - 'MESSAGES_DELETE', - 'SEND_MESSAGE', - 'CONTACTS_SET', - 'CONTACTS_UPSERT', - 'CONTACTS_UPDATE', - 'PRESENCE_UPDATE', - 'CHATS_SET', - 'CHATS_UPSERT', - 'CHATS_UPDATE', - 'CHATS_DELETE', - 'GROUPS_UPSERT', - 'GROUP_UPDATE', - 'GROUP_PARTICIPANTS_UPDATE', - 'CONNECTION_UPDATE', - 'LABELS_EDIT', - 'LABELS_ASSOCIATION', - 'CALL', - 'NEW_JWT_TOKEN', - 'TYPEBOT_START', - 'TYPEBOT_CHANGE_STATUS', - 'CHAMA_AI_ACTION', - ]; - } - - return this.websocketService.create(instance, data); - } - - public async findWebsocket(instance: InstanceDto) { - logger.verbose('requested findWebsocket from ' + instance.instanceName + ' instance'); - return this.websocketService.find(instance); - } -} diff --git a/src/api/integrations/websocket/dto/websocket.dto.ts b/src/api/integrations/websocket/dto/websocket.dto.ts deleted file mode 100644 index 27f6d785..00000000 --- a/src/api/integrations/websocket/dto/websocket.dto.ts +++ /dev/null @@ -1,4 +0,0 @@ -export class WebsocketDto { - enabled: boolean; - events?: string[]; -} diff --git a/src/api/integrations/websocket/libs/socket.server.ts b/src/api/integrations/websocket/libs/socket.server.ts deleted file mode 100644 index 81f97847..00000000 --- a/src/api/integrations/websocket/libs/socket.server.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { Server } from 'http'; -import { Server as SocketIO } from 'socket.io'; - -import { configService, Cors, Websocket } from '../../../../config/env.config'; -import { Logger } from '../../../../config/logger.config'; - -const logger = new Logger('Socket'); - -let io: SocketIO; - -const cors = configService.get('CORS').ORIGIN; - -export const initIO = (httpServer: Server) => { - if (configService.get('WEBSOCKET')?.ENABLED) { - io = new SocketIO(httpServer, { - cors: { - origin: cors, - }, - }); - - io.on('connection', (socket) => { - logger.info('User connected'); - - socket.on('disconnect', () => { - logger.info('User disconnected'); - }); - }); - - logger.info('Socket.io initialized'); - return io; - } - return null; -}; - -export const getIO = (): SocketIO => { - logger.verbose('Getting Socket.io'); - - if (!io) { - logger.error('Socket.io not initialized'); - throw new Error('Socket.io not initialized'); - } - - return io; -}; diff --git a/src/api/integrations/websocket/models/websocket.model.ts b/src/api/integrations/websocket/models/websocket.model.ts deleted file mode 100644 index 9e824597..00000000 --- a/src/api/integrations/websocket/models/websocket.model.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Schema } from 'mongoose'; - -import { dbserver } from '../../../../libs/db.connect'; - -export class WebsocketRaw { - _id?: string; - enabled?: boolean; - events?: string[]; -} - -const websocketSchema = new Schema({ - _id: { type: String, _id: true }, - enabled: { type: Boolean, required: true }, - events: { type: [String], required: true }, -}); - -export const WebsocketModel = dbserver?.model(WebsocketRaw.name, websocketSchema, 'websocket'); -export type IWebsocketModel = typeof WebsocketModel; diff --git a/src/api/integrations/websocket/repository/websocket.repository.ts b/src/api/integrations/websocket/repository/websocket.repository.ts deleted file mode 100644 index 48d5b7d3..00000000 --- a/src/api/integrations/websocket/repository/websocket.repository.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { readFileSync } from 'fs'; -import { join } from 'path'; - -import { ConfigService } from '../../../../config/env.config'; -import { Logger } from '../../../../config/logger.config'; -import { IInsert, Repository } from '../../../abstract/abstract.repository'; -import { IWebsocketModel, WebsocketRaw } from '../../../models'; - -export class WebsocketRepository extends Repository { - constructor(private readonly websocketModel: IWebsocketModel, private readonly configService: ConfigService) { - super(configService); - } - - private readonly logger = new Logger('WebsocketRepository'); - - public async create(data: WebsocketRaw, instance: string): Promise { - try { - this.logger.verbose('creating websocket'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('saving websocket to db'); - const insert = await this.websocketModel.replaceOne({ _id: instance }, { ...data }, { upsert: true }); - - this.logger.verbose('websocket saved to db: ' + insert.modifiedCount + ' websocket'); - return { insertCount: insert.modifiedCount }; - } - - this.logger.verbose('saving websocket to store'); - - this.writeStore({ - path: join(this.storePath, 'websocket'), - fileName: instance, - data, - }); - - this.logger.verbose('websocket saved to store in path: ' + join(this.storePath, 'websocket') + '/' + instance); - - this.logger.verbose('websocket created'); - return { insertCount: 1 }; - } catch (error) { - return error; - } - } - - public async find(instance: string): Promise { - try { - this.logger.verbose('finding websocket'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding websocket in db'); - return await this.websocketModel.findOne({ _id: instance }); - } - - this.logger.verbose('finding websocket in store'); - return JSON.parse( - readFileSync(join(this.storePath, 'websocket', instance + '.json'), { - encoding: 'utf-8', - }), - ) as WebsocketRaw; - } catch (error) { - return {}; - } - } -} diff --git a/src/api/integrations/websocket/routes/websocket.router.ts b/src/api/integrations/websocket/routes/websocket.router.ts deleted file mode 100644 index 0c39d53c..00000000 --- a/src/api/integrations/websocket/routes/websocket.router.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { RequestHandler, Router } from 'express'; - -import { Logger } from '../../../../config/logger.config'; -import { instanceNameSchema, websocketSchema } from '../../../../validate/validate.schema'; -import { RouterBroker } from '../../../abstract/abstract.router'; -import { InstanceDto } from '../../../dto/instance.dto'; -import { HttpStatus } from '../../../routes/index.router'; -import { websocketController } from '../../../server.module'; -import { WebsocketDto } from '../dto/websocket.dto'; - -const logger = new Logger('WebsocketRouter'); - -export class WebsocketRouter extends RouterBroker { - constructor(...guards: RequestHandler[]) { - super(); - this.router - .post(this.routerPath('set'), ...guards, async (req, res) => { - logger.verbose('request received in setWebsocket'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - const response = await this.dataValidate({ - request: req, - schema: websocketSchema, - ClassRef: WebsocketDto, - execute: (instance, data) => websocketController.createWebsocket(instance, data), - }); - - res.status(HttpStatus.CREATED).json(response); - }) - .get(this.routerPath('find'), ...guards, async (req, res) => { - logger.verbose('request received in findWebsocket'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - const response = await this.dataValidate({ - request: req, - schema: instanceNameSchema, - ClassRef: InstanceDto, - execute: (instance) => websocketController.findWebsocket(instance), - }); - - res.status(HttpStatus.OK).json(response); - }); - } - - public readonly router = Router(); -} diff --git a/src/api/integrations/websocket/services/websocket.service.ts b/src/api/integrations/websocket/services/websocket.service.ts deleted file mode 100644 index fcbb4353..00000000 --- a/src/api/integrations/websocket/services/websocket.service.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { Logger } from '../../../../config/logger.config'; -import { InstanceDto } from '../../../dto/instance.dto'; -import { WebsocketRaw } from '../../../models'; -import { WAMonitoringService } from '../../../services/monitor.service'; -import { WebsocketDto } from '../dto/websocket.dto'; - -export class WebsocketService { - constructor(private readonly waMonitor: WAMonitoringService) {} - - private readonly logger = new Logger(WebsocketService.name); - - public create(instance: InstanceDto, data: WebsocketDto) { - this.logger.verbose('create websocket: ' + instance.instanceName); - this.waMonitor.waInstances[instance.instanceName].setWebsocket(data); - - return { websocket: { ...instance, websocket: data } }; - } - - public async find(instance: InstanceDto): Promise { - try { - this.logger.verbose('find websocket: ' + instance.instanceName); - const result = await this.waMonitor.waInstances[instance.instanceName].findWebsocket(); - - if (Object.keys(result).length === 0) { - throw new Error('Websocket not found'); - } - - return result; - } catch (error) { - return { enabled: false, events: [] }; - } - } -} diff --git a/src/api/integrations/websocket/validate/websocket.schema.ts b/src/api/integrations/websocket/validate/websocket.schema.ts deleted file mode 100644 index ddddeee2..00000000 --- a/src/api/integrations/websocket/validate/websocket.schema.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { JSONSchema7 } from 'json-schema'; -import { v4 } from 'uuid'; - -const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => { - const properties = {}; - propertyNames.forEach( - (property) => - (properties[property] = { - minLength: 1, - description: `The "${property}" cannot be empty`, - }), - ); - return { - if: { - propertyNames: { - enum: [...propertyNames], - }, - }, - then: { properties }, - }; -}; - -export const websocketSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - enabled: { type: 'boolean', enum: [true, false] }, - events: { - type: 'array', - minItems: 0, - items: { - type: 'string', - enum: [ - 'APPLICATION_STARTUP', - 'QRCODE_UPDATED', - 'MESSAGES_SET', - 'MESSAGES_UPSERT', - 'MESSAGES_UPDATE', - 'MESSAGES_DELETE', - 'SEND_MESSAGE', - 'CONTACTS_SET', - 'CONTACTS_UPSERT', - 'CONTACTS_UPDATE', - 'PRESENCE_UPDATE', - 'CHATS_SET', - 'CHATS_UPSERT', - 'CHATS_UPDATE', - 'CHATS_DELETE', - 'GROUPS_UPSERT', - 'GROUP_UPDATE', - 'GROUP_PARTICIPANTS_UPDATE', - 'CONNECTION_UPDATE', - 'LABELS_EDIT', - 'LABELS_ASSOCIATION', - 'CALL', - 'NEW_JWT_TOKEN', - 'TYPEBOT_START', - 'TYPEBOT_CHANGE_STATUS', - 'CHAMA_AI_ACTION', - ], - }, - }, - }, - required: ['enabled'], - ...isNotEmpty('enabled'), -}; diff --git a/src/api/models/auth.model.ts b/src/api/models/auth.model.ts deleted file mode 100644 index 9ae5537f..00000000 --- a/src/api/models/auth.model.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Schema } from 'mongoose'; - -import { dbserver } from '../../libs/db.connect'; - -export class AuthRaw { - _id?: string; - jwt?: string; - apikey?: string; - instanceId?: string; -} - -const authSchema = new Schema({ - _id: { type: String, _id: true }, - jwt: { type: String, minlength: 1 }, - apikey: { type: String, minlength: 1 }, - instanceId: { type: String, minlength: 1 }, -}); - -export const AuthModel = dbserver?.model(AuthRaw.name, authSchema, 'authentication'); -export type IAuthModel = typeof AuthModel; diff --git a/src/api/models/chat.model.ts b/src/api/models/chat.model.ts deleted file mode 100644 index 9e713a13..00000000 --- a/src/api/models/chat.model.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Schema } from 'mongoose'; - -import { dbserver } from '../../libs/db.connect'; - -export class ChatRaw { - _id?: string; - id?: string; - owner: string; - lastMsgTimestamp?: number; - labels?: string[]; -} - -type ChatRawBoolean = { - [P in keyof T]?: 0 | 1; -}; -export type ChatRawSelect = ChatRawBoolean; - -const chatSchema = new Schema({ - _id: { type: String, _id: true }, - id: { type: String, required: true, minlength: 1 }, - owner: { type: String, required: true, minlength: 1 }, - labels: { type: [String], default: [] }, -}); - -export const ChatModel = dbserver?.model(ChatRaw.name, chatSchema, 'chats'); -export type IChatModel = typeof ChatModel; diff --git a/src/api/models/contact.model.ts b/src/api/models/contact.model.ts deleted file mode 100644 index a915bb19..00000000 --- a/src/api/models/contact.model.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Schema } from 'mongoose'; - -import { dbserver } from '../../libs/db.connect'; - -export class ContactRaw { - _id?: string; - pushName?: string; - id?: string; - profilePictureUrl?: string; - owner: string; -} - -type ContactRawBoolean = { - [P in keyof T]?: 0 | 1; -}; -export type ContactRawSelect = ContactRawBoolean; - -const contactSchema = new Schema({ - _id: { type: String, _id: true }, - pushName: { type: String, minlength: 1 }, - id: { type: String, required: true, minlength: 1 }, - profilePictureUrl: { type: String, minlength: 1 }, - owner: { type: String, required: true, minlength: 1 }, -}); - -export const ContactModel = dbserver?.model(ContactRaw.name, contactSchema, 'contacts'); -export type IContactModel = typeof ContactModel; diff --git a/src/api/models/index.ts b/src/api/models/index.ts deleted file mode 100644 index 42399bc5..00000000 --- a/src/api/models/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -export * from '../integrations/chamaai/models/chamaai.model'; -export * from '../integrations/chatwoot/models/chatwoot.model'; -export * from '../integrations/rabbitmq/models/rabbitmq.model'; -export * from '../integrations/sqs/models/sqs.model'; -export * from '../integrations/typebot/models/typebot.model'; -export * from '../integrations/websocket/models/websocket.model'; -export * from './auth.model'; -export * from './chat.model'; -export * from './contact.model'; -export * from './integration.model'; -export * from './label.model'; -export * from './message.model'; -export * from './proxy.model'; -export * from './settings.model'; -export * from './webhook.model'; diff --git a/src/api/models/integration.model.ts b/src/api/models/integration.model.ts deleted file mode 100644 index 3bacd7ee..00000000 --- a/src/api/models/integration.model.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Schema } from 'mongoose'; - -import { dbserver } from '../../libs/db.connect'; - -export class IntegrationRaw { - _id?: string; - integration?: string; - number?: string; - token?: string; -} - -const integrationSchema = new Schema({ - _id: { type: String, _id: true }, - integration: { type: String, required: true }, - number: { type: String, required: true }, - token: { type: String, required: true }, -}); - -export const IntegrationModel = dbserver?.model(IntegrationRaw.name, integrationSchema, 'integration'); -export type IntegrationModel = typeof IntegrationModel; diff --git a/src/api/models/label.model.ts b/src/api/models/label.model.ts deleted file mode 100644 index 99c39909..00000000 --- a/src/api/models/label.model.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { Schema } from 'mongoose'; - -import { dbserver } from '../../libs/db.connect'; - -export class LabelRaw { - _id?: string; - id?: string; - owner: string; - name: string; - color: number; - predefinedId?: string; -} - -type LabelRawBoolean = { - [P in keyof T]?: 0 | 1; -}; -export type LabelRawSelect = LabelRawBoolean; - -const labelSchema = new Schema({ - _id: { type: String, _id: true }, - id: { type: String, required: true, minlength: 1 }, - owner: { type: String, required: true, minlength: 1 }, - name: { type: String, required: true, minlength: 1 }, - color: { type: Number, required: true, min: 0, max: 19 }, - predefinedId: { type: String }, -}); - -export const LabelModel = dbserver?.model(LabelRaw.name, labelSchema, 'labels'); -export type ILabelModel = typeof LabelModel; diff --git a/src/api/models/message.model.ts b/src/api/models/message.model.ts deleted file mode 100644 index 95cb5513..00000000 --- a/src/api/models/message.model.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { Schema } from 'mongoose'; - -import { dbserver } from '../../libs/db.connect'; -import { wa } from '../types/wa.types'; - -class Key { - id?: string; - remoteJid?: string; - fromMe?: boolean; - participant?: string; -} - -class ChatwootMessage { - messageId?: number; - inboxId?: number; - conversationId?: number; - contactInbox?: { sourceId: string }; - isRead?: boolean; -} - -export class MessageRaw { - _id?: string; - key?: Key; - pushName?: string; - participant?: string; - message?: object; - messageType?: string; - messageTimestamp?: number | Long.Long; - owner: string; - source?: 'android' | 'web' | 'ios' | 'unknown' | 'desktop'; - source_id?: string; - source_reply_id?: string; - chatwoot?: ChatwootMessage; - contextInfo?: any; - status?: wa.StatusMessage | any; -} - -type MessageRawBoolean = { - [P in keyof T]?: 0 | 1; -}; -export type MessageRawSelect = Omit, 'key'>, 'chatwoot'> & { - key?: MessageRawBoolean; - chatwoot?: MessageRawBoolean; -}; - -const messageSchema = new Schema({ - _id: { type: String, _id: true }, - key: { - id: { type: String, required: true, minlength: 1 }, - remoteJid: { type: String, required: true, minlength: 1 }, - fromMe: { type: Boolean, required: true }, - participant: { type: String, minlength: 1 }, - }, - pushName: { type: String }, - participant: { type: String }, - messageType: { type: String }, - message: { type: Object }, - source: { type: String, minlength: 3, enum: ['android', 'web', 'ios', 'unknown', 'desktop'] }, - messageTimestamp: { type: Number, required: true }, - owner: { type: String, required: true, minlength: 1 }, - chatwoot: { - messageId: { type: Number }, - inboxId: { type: Number }, - conversationId: { type: Number }, - contactInbox: { type: Object }, - isRead: { type: Boolean }, - }, -}); - -messageSchema.index({ 'chatwoot.messageId': 1, owner: 1 }); -messageSchema.index({ 'key.id': 1 }); -messageSchema.index({ 'key.id': 1, owner: 1 }); -messageSchema.index({ owner: 1 }); - -export const MessageModel = dbserver?.model(MessageRaw.name, messageSchema, 'messages'); -export type IMessageModel = typeof MessageModel; - -export class MessageUpdateRaw { - _id?: string; - remoteJid?: string; - id?: string; - fromMe?: boolean; - participant?: string; - datetime?: number; - status?: wa.StatusMessage; - owner: string; - pollUpdates?: any; -} - -const messageUpdateSchema = new Schema({ - _id: { type: String, _id: true }, - remoteJid: { type: String, required: true, min: 1 }, - id: { type: String, required: true, min: 1 }, - fromMe: { type: Boolean, required: true }, - participant: { type: String, min: 1 }, - datetime: { type: Number, required: true, min: 1 }, - status: { type: String, required: true }, - owner: { type: String, required: true, min: 1 }, -}); - -export const MessageUpModel = dbserver?.model(MessageUpdateRaw.name, messageUpdateSchema, 'messageUpdate'); -export type IMessageUpModel = typeof MessageUpModel; diff --git a/src/api/models/proxy.model.ts b/src/api/models/proxy.model.ts deleted file mode 100644 index 4096f58f..00000000 --- a/src/api/models/proxy.model.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Schema } from 'mongoose'; - -import { dbserver } from '../../libs/db.connect'; - -class Proxy { - host?: string; - port?: string; - protocol?: string; - username?: string; - password?: string; -} - -export class ProxyRaw { - _id?: string; - enabled?: boolean; - proxy?: Proxy; -} - -const proxySchema = new Schema({ - _id: { type: String, _id: true }, - enabled: { type: Boolean, required: true }, - proxy: { - host: { type: String, required: true }, - port: { type: String, required: true }, - protocol: { type: String, required: true }, - username: { type: String, required: false }, - password: { type: String, required: false }, - }, -}); - -export const ProxyModel = dbserver?.model(ProxyRaw.name, proxySchema, 'proxy'); -export type IProxyModel = typeof ProxyModel; diff --git a/src/api/models/settings.model.ts b/src/api/models/settings.model.ts deleted file mode 100644 index 64c032ed..00000000 --- a/src/api/models/settings.model.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Schema } from 'mongoose'; - -import { dbserver } from '../../libs/db.connect'; - -export class SettingsRaw { - _id?: string; - reject_call?: boolean; - msg_call?: string; - groups_ignore?: boolean; - always_online?: boolean; - read_messages?: boolean; - read_status?: boolean; - sync_full_history?: boolean; -} - -const settingsSchema = new Schema({ - _id: { type: String, _id: true }, - reject_call: { type: Boolean, required: true }, - msg_call: { type: String, required: true }, - groups_ignore: { type: Boolean, required: true }, - always_online: { type: Boolean, required: true }, - read_messages: { type: Boolean, required: true }, - read_status: { type: Boolean, required: true }, - sync_full_history: { type: Boolean, required: true }, -}); - -export const SettingsModel = dbserver?.model(SettingsRaw.name, settingsSchema, 'settings'); -export type ISettingsModel = typeof SettingsModel; diff --git a/src/api/models/webhook.model.ts b/src/api/models/webhook.model.ts deleted file mode 100644 index 9a1bb43d..00000000 --- a/src/api/models/webhook.model.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Schema } from 'mongoose'; - -import { dbserver } from '../../libs/db.connect'; - -export class WebhookRaw { - _id?: string; - url?: string; - enabled?: boolean; - events?: string[]; - webhook_by_events?: boolean; - webhook_base64?: boolean; -} - -const webhookSchema = new Schema({ - _id: { type: String, _id: true }, - url: { type: String, required: true }, - enabled: { type: Boolean, required: true }, - events: { type: [String], required: true }, - webhook_by_events: { type: Boolean, required: true }, - webhook_base64: { type: Boolean, required: true }, -}); - -export const WebhookModel = dbserver?.model(WebhookRaw.name, webhookSchema, 'webhook'); -export type IWebhookModel = typeof WebhookModel; diff --git a/src/api/provider/sessions.ts b/src/api/provider/sessions.ts new file mode 100644 index 00000000..05668232 --- /dev/null +++ b/src/api/provider/sessions.ts @@ -0,0 +1,149 @@ +import { Auth, ConfigService, ProviderSession } from '@config/env.config'; +import { Logger } from '@config/logger.config'; +import axios from 'axios'; +import { execSync } from 'child_process'; + +type ResponseSuccess = { status: number; data?: any }; +type ResponseProvider = Promise<[ResponseSuccess?, Error?]>; + +export class ProviderFiles { + constructor(private readonly configService: ConfigService) { + this.baseUrl = `http://${this.config.HOST}:${this.config.PORT}/session/${this.config.PREFIX}`; + this.globalApiToken = this.configService.get('AUTHENTICATION').API_KEY.KEY; + } + + private readonly logger = new Logger('ProviderFiles'); + + private baseUrl: string; + private globalApiToken: string; + + private readonly config = Object.freeze(this.configService.get('PROVIDER')); + + get isEnabled() { + return !!this.config?.ENABLED; + } + + public async onModuleInit() { + if (this.config.ENABLED) { + const url = `http://${this.config.HOST}:${this.config.PORT}`; + try { + const response = await axios.options(url + '/ping'); + if (response?.data != 'pong') { + throw new Error('Offline file provider.'); + } + + await axios.post(`${url}/session`, { group: this.config.PREFIX }, { headers: { apikey: this.globalApiToken } }); + } catch (error) { + this.logger.error(['Failed to connect to the file server', error?.message, error?.stack]); + const pid = process.pid; + execSync(`kill -9 ${pid}`); + } + } + } + + public async onModuleDestroy() { + // + } + + public async create(instance: string): ResponseProvider { + try { + const response = await axios.post( + `${this.baseUrl}`, + { + instance, + }, + { headers: { apikey: this.globalApiToken } }, + ); + return [{ status: response.status, data: response?.data }]; + } catch (error) { + return [ + { + status: error?.response?.status, + data: error?.response?.data, + }, + error, + ]; + } + } + + public async write(instance: string, key: string, data: any): ResponseProvider { + try { + const response = await axios.post(`${this.baseUrl}/${instance}/${key}`, data, { + headers: { apikey: this.globalApiToken }, + }); + return [{ status: response.status, data: response?.data }]; + } catch (error) { + return [ + { + status: error?.response?.status, + data: error?.response?.data, + }, + error, + ]; + } + } + + public async read(instance: string, key: string): ResponseProvider { + try { + const response = await axios.get(`${this.baseUrl}/${instance}/${key}`, { + headers: { apikey: this.globalApiToken }, + }); + return [{ status: response.status, data: response?.data }]; + } catch (error) { + return [ + { + status: error?.response?.status, + data: error?.response?.data, + }, + error, + ]; + } + } + + public async delete(instance: string, key: string): ResponseProvider { + try { + const response = await axios.delete(`${this.baseUrl}/${instance}/${key}`, { + headers: { apikey: this.globalApiToken }, + }); + return [{ status: response.status, data: response?.data }]; + } catch (error) { + return [ + { + status: error?.response?.status, + data: error?.response?.data, + }, + error, + ]; + } + } + + public async allInstances(): ResponseProvider { + try { + const response = await axios.get(`${this.baseUrl}/list-instances`, { headers: { apikey: this.globalApiToken } }); + return [{ status: response.status, data: response?.data as string[] }]; + } catch (error) { + return [ + { + status: error?.response?.status, + data: error?.response?.data, + }, + error, + ]; + } + } + + public async removeSession(instance: string): ResponseProvider { + try { + const response = await axios.delete(`${this.baseUrl}/${instance}`, { headers: { apikey: this.globalApiToken } }); + return [{ status: response.status, data: response?.data }]; + } catch (error) { + return [ + { + status: error?.response?.status, + data: error?.response?.data, + }, + error, + ]; + } + } +} diff --git a/src/api/repository/auth.repository.ts b/src/api/repository/auth.repository.ts deleted file mode 100644 index 6a296902..00000000 --- a/src/api/repository/auth.repository.ts +++ /dev/null @@ -1,149 +0,0 @@ -import { opendirSync, readFileSync } from 'fs'; -import { join } from 'path'; - -import { Auth, ConfigService } from '../../config/env.config'; -import { Logger } from '../../config/logger.config'; -import { AUTH_DIR } from '../../config/path.config'; -import { IInsert, Repository } from '../abstract/abstract.repository'; -import { AuthRaw, IAuthModel, IntegrationModel } from '../models'; - -export class AuthRepository extends Repository { - constructor( - private readonly authModel: IAuthModel, - private readonly integrationModel: IntegrationModel, - readonly configService: ConfigService, - ) { - super(configService); - this.auth = configService.get('AUTHENTICATION'); - } - - private readonly auth: Auth; - private readonly logger = new Logger('AuthRepository'); - - public async create(data: AuthRaw, instance: string): Promise { - try { - this.logger.verbose('creating auth'); - - if (this.dbSettings.ENABLED) { - this.logger.verbose('saving auth to db'); - const insert = await this.authModel.replaceOne({ _id: instance }, { ...data }, { upsert: true }); - - this.logger.verbose('auth saved to db: ' + insert.modifiedCount + ' auth'); - return { insertCount: insert.modifiedCount }; - } - - this.logger.verbose('saving auth to store'); - - this.writeStore({ - path: join(AUTH_DIR, this.auth.TYPE), - fileName: instance, - data, - }); - this.logger.verbose('auth saved to store in path: ' + join(AUTH_DIR, this.auth.TYPE) + '/' + instance); - - this.logger.verbose('auth created'); - return { insertCount: 1 }; - } catch (error) { - return { error } as any; - } - } - - public async find(instance: string): Promise { - try { - this.logger.verbose('finding auth'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding auth in db'); - return await this.authModel.findOne({ _id: instance }); - } - - this.logger.verbose('finding auth in store'); - - return JSON.parse( - readFileSync(join(AUTH_DIR, this.auth.TYPE, instance + '.json'), { - encoding: 'utf-8', - }), - ) as AuthRaw; - } catch (error) { - return {}; - } - } - - public async findByKey(key: string): Promise { - try { - this.logger.verbose('finding auth'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding auth in db'); - return await this.authModel.findOne({ apikey: key }); - } - - return {}; - } catch (error) { - return {}; - } - } - - public async list(): Promise { - try { - if (this.dbSettings.ENABLED) { - this.logger.verbose('listing auth in db'); - return await this.authModel.find(); - } - - this.logger.verbose('listing auth in store'); - - const auths: AuthRaw[] = []; - const openDir = opendirSync(join(AUTH_DIR, this.auth.TYPE), { - encoding: 'utf-8', - }); - for await (const dirent of openDir) { - if (dirent.isFile()) { - auths.push( - JSON.parse( - readFileSync(join(AUTH_DIR, this.auth.TYPE, dirent.name), { - encoding: 'utf-8', - }), - ), - ); - } - } - - return auths; - } catch (error) { - return []; - } - } - - public async findInstanceNameById(instanceId: string): Promise { - try { - this.logger.verbose('finding auth by instanceId'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding auth in db'); - const response = await this.authModel.findOne({ instanceId }); - - return response._id; - } - - this.logger.verbose('finding auth in store is not supported'); - } catch (error) { - return null; - } - } - - public async findInstanceNameByNumber(number: string): Promise { - try { - this.logger.verbose('finding auth by number'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding auth in db'); - const instance = await this.integrationModel.findOne({ number }); - - const response = await this.authModel.findOne({ _id: instance._id }); - - return response._id; - } - - this.logger.verbose('finding auth in store is not supported'); - } catch (error) { - return null; - } - } -} diff --git a/src/api/repository/chat.repository.ts b/src/api/repository/chat.repository.ts deleted file mode 100644 index 5f2f50ce..00000000 --- a/src/api/repository/chat.repository.ts +++ /dev/null @@ -1,177 +0,0 @@ -import { opendirSync, readFileSync, rmSync } from 'fs'; -import { join } from 'path'; - -import { ConfigService, StoreConf } from '../../config/env.config'; -import { Logger } from '../../config/logger.config'; -import { IInsert, Repository } from '../abstract/abstract.repository'; -import { ChatRaw, ChatRawSelect, IChatModel } from '../models'; - -export class ChatQuery { - select?: ChatRawSelect; - where: ChatRaw; -} - -export class ChatRepository extends Repository { - constructor(private readonly chatModel: IChatModel, private readonly configService: ConfigService) { - super(configService); - } - - private readonly logger = new Logger('ChatRepository'); - - public async insert(data: ChatRaw[], instanceName: string, saveDb = false): Promise { - this.logger.verbose('inserting chats'); - if (data.length === 0) { - this.logger.verbose('no chats to insert'); - return; - } - - try { - this.logger.verbose('saving chats to store'); - if (this.dbSettings.ENABLED && saveDb) { - this.logger.verbose('saving chats to db'); - const insert = await this.chatModel.insertMany([...data]); - - this.logger.verbose('chats saved to db: ' + insert.length + ' chats'); - return { insertCount: insert.length }; - } - - this.logger.verbose('saving chats to store'); - - const store = this.configService.get('STORE'); - - if (store.CHATS) { - this.logger.verbose('saving chats to store'); - data.forEach((chat) => { - this.writeStore({ - path: join(this.storePath, 'chats', instanceName), - fileName: chat.id, - data: chat, - }); - this.logger.verbose( - 'chats saved to store in path: ' + join(this.storePath, 'chats', instanceName) + '/' + chat.id, - ); - }); - - this.logger.verbose('chats saved to store'); - return { insertCount: data.length }; - } - - this.logger.verbose('chats not saved to store'); - return { insertCount: 0 }; - } catch (error) { - return error; - } finally { - data = undefined; - } - } - - public async find(query: ChatQuery): Promise { - try { - this.logger.verbose('finding chats'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding chats in db'); - return await this.chatModel.find({ owner: query.where.owner }).select(query.select ?? {}); - } - - this.logger.verbose('finding chats in store'); - - const chats: ChatRaw[] = []; - const openDir = opendirSync(join(this.storePath, 'chats', query.where.owner)); - for await (const dirent of openDir) { - if (dirent.isFile()) { - chats.push( - JSON.parse( - readFileSync(join(this.storePath, 'chats', query.where.owner, dirent.name), { - encoding: 'utf-8', - }), - ), - ); - } - } - - this.logger.verbose('chats found in store: ' + chats.length + ' chats'); - return chats; - } catch (error) { - return []; - } - } - - public async delete(query: ChatQuery) { - try { - this.logger.verbose('deleting chats'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('deleting chats in db'); - return await this.chatModel.deleteOne({ ...query.where }); - } - - this.logger.verbose('deleting chats in store'); - rmSync(join(this.storePath, 'chats', query.where.owner, query.where.id + '.josn'), { - force: true, - recursive: true, - }); - - return { deleted: { chatId: query.where.id } }; - } catch (error) { - return { error: error?.toString() }; - } - } - - public async update(data: ChatRaw[], instanceName: string, saveDb = false): Promise { - try { - this.logger.verbose('updating chats'); - - if (data.length === 0) { - this.logger.verbose('no chats to update'); - return; - } - - if (this.dbSettings.ENABLED && saveDb) { - this.logger.verbose('updating chats in db'); - - const chats = data.map((chat) => { - return { - updateOne: { - filter: { id: chat.id }, - update: { ...chat }, - upsert: true, - }, - }; - }); - - const { nModified } = await this.chatModel.bulkWrite(chats); - - this.logger.verbose('chats updated in db: ' + nModified + ' chats'); - return { insertCount: nModified }; - } - - this.logger.verbose('updating chats in store'); - - const store = this.configService.get('STORE'); - - if (store.CONTACTS) { - this.logger.verbose('updating chats in store'); - data.forEach((chat) => { - this.writeStore({ - path: join(this.storePath, 'chats', instanceName), - fileName: chat.id, - data: chat, - }); - this.logger.verbose( - 'chats updated in store in path: ' + join(this.storePath, 'chats', instanceName) + '/' + chat.id, - ); - }); - - this.logger.verbose('chats updated in store: ' + data.length + ' chats'); - - return { insertCount: data.length }; - } - - this.logger.verbose('chats not updated'); - return { insertCount: 0 }; - } catch (error) { - return error; - } finally { - data = undefined; - } - } -} diff --git a/src/api/repository/contact.repository.ts b/src/api/repository/contact.repository.ts deleted file mode 100644 index d26ada35..00000000 --- a/src/api/repository/contact.repository.ts +++ /dev/null @@ -1,227 +0,0 @@ -import { opendirSync, readFileSync } from 'fs'; -import { join } from 'path'; - -import { ConfigService, StoreConf } from '../../config/env.config'; -import { Logger } from '../../config/logger.config'; -import { IInsert, Repository } from '../abstract/abstract.repository'; -import { ContactRaw, ContactRawSelect, IContactModel } from '../models'; - -export class ContactQuery { - select?: ContactRawSelect; - where: ContactRaw; -} - -export class ContactQueryMany { - owner: ContactRaw['owner']; - ids: ContactRaw['id'][]; -} - -export class ContactRepository extends Repository { - constructor(private readonly contactModel: IContactModel, private readonly configService: ConfigService) { - super(configService); - } - - private readonly logger = new Logger('ContactRepository'); - - public async insert(data: ContactRaw[], instanceName: string, saveDb = false): Promise { - this.logger.verbose('inserting contacts'); - - if (data.length === 0) { - this.logger.verbose('no contacts to insert'); - return; - } - - try { - if (this.dbSettings.ENABLED && saveDb) { - this.logger.verbose('saving contacts to db'); - - const insert = await this.contactModel.insertMany([...data]); - - this.logger.verbose('contacts saved to db: ' + insert.length + ' contacts'); - return { insertCount: insert.length }; - } - - this.logger.verbose('saving contacts to store'); - - const store = this.configService.get('STORE'); - - if (store.CONTACTS) { - this.logger.verbose('saving contacts to store'); - data.forEach((contact) => { - this.writeStore({ - path: join(this.storePath, 'contacts', instanceName), - fileName: contact.id, - data: contact, - }); - this.logger.verbose( - 'contacts saved to store in path: ' + join(this.storePath, 'contacts', instanceName) + '/' + contact.id, - ); - }); - - this.logger.verbose('contacts saved to store: ' + data.length + ' contacts'); - return { insertCount: data.length }; - } - - this.logger.verbose('contacts not saved'); - return { insertCount: 0 }; - } catch (error) { - return error; - } finally { - data = undefined; - } - } - - public async update(data: ContactRaw[], instanceName: string, saveDb = false): Promise { - try { - this.logger.verbose('updating contacts'); - - if (data.length === 0) { - this.logger.verbose('no contacts to update'); - return; - } - - if (this.dbSettings.ENABLED && saveDb) { - this.logger.verbose('updating contacts in db'); - - const contacts = data.map((contact) => { - return { - updateOne: { - filter: { id: contact.id }, - update: { ...contact }, - upsert: true, - }, - }; - }); - - const { nModified } = await this.contactModel.bulkWrite(contacts); - - this.logger.verbose('contacts updated in db: ' + nModified + ' contacts'); - return { insertCount: nModified }; - } - - this.logger.verbose('updating contacts in store'); - - const store = this.configService.get('STORE'); - - if (store.CONTACTS) { - this.logger.verbose('updating contacts in store'); - data.forEach((contact) => { - this.writeStore({ - path: join(this.storePath, 'contacts', instanceName), - fileName: contact.id, - data: contact, - }); - this.logger.verbose( - 'contacts updated in store in path: ' + join(this.storePath, 'contacts', instanceName) + '/' + contact.id, - ); - }); - - this.logger.verbose('contacts updated in store: ' + data.length + ' contacts'); - - return { insertCount: data.length }; - } - - this.logger.verbose('contacts not updated'); - return { insertCount: 0 }; - } catch (error) { - return error; - } finally { - data = undefined; - } - } - - public async find(query: ContactQuery): Promise { - try { - this.logger.verbose('finding contacts'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding contacts in db'); - return await this.contactModel.find({ ...query.where }).select(query.select ?? {}); - } - - this.logger.verbose('finding contacts in store'); - const contacts: ContactRaw[] = []; - if (query?.where?.id) { - this.logger.verbose('finding contacts in store by id'); - contacts.push( - JSON.parse( - readFileSync(join(this.storePath, 'contacts', query.where.owner, query.where.id + '.json'), { - encoding: 'utf-8', - }), - ), - ); - } else { - this.logger.verbose('finding contacts in store by owner'); - - const openDir = opendirSync(join(this.storePath, 'contacts', query.where.owner), { - encoding: 'utf-8', - }); - for await (const dirent of openDir) { - if (dirent.isFile()) { - contacts.push( - JSON.parse( - readFileSync(join(this.storePath, 'contacts', query.where.owner, dirent.name), { - encoding: 'utf-8', - }), - ), - ); - } - } - } - - this.logger.verbose('contacts found in store: ' + contacts.length + ' contacts'); - return contacts; - } catch (error) { - return []; - } - } - - public async findManyById(query: ContactQueryMany): Promise { - try { - this.logger.verbose('finding contacts'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding contacts in db'); - return await this.contactModel.find({ - owner: query.owner, - id: { $in: query.ids }, - }); - } - - this.logger.verbose('finding contacts in store'); - const contacts: ContactRaw[] = []; - if (query.ids.length > 0) { - this.logger.verbose('finding contacts in store by id'); - query.ids.forEach((id) => { - contacts.push( - JSON.parse( - readFileSync(join(this.storePath, 'contacts', query.owner, id + '.json'), { - encoding: 'utf-8', - }), - ), - ); - }); - } else { - this.logger.verbose('finding contacts in store by owner'); - - const openDir = opendirSync(join(this.storePath, 'contacts', query.owner), { - encoding: 'utf-8', - }); - for await (const dirent of openDir) { - if (dirent.isFile()) { - contacts.push( - JSON.parse( - readFileSync(join(this.storePath, 'contacts', query.owner, dirent.name), { - encoding: 'utf-8', - }), - ), - ); - } - } - } - - this.logger.verbose('contacts found in store: ' + contacts.length + ' contacts'); - return contacts; - } catch (error) { - return []; - } - } -} diff --git a/src/api/repository/integration.repository.ts b/src/api/repository/integration.repository.ts deleted file mode 100644 index 09cb8a9a..00000000 --- a/src/api/repository/integration.repository.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { readFileSync } from 'fs'; -import { join } from 'path'; - -import { ConfigService } from '../../config/env.config'; -import { Logger } from '../../config/logger.config'; -import { IInsert, Repository } from '../abstract/abstract.repository'; -import { IntegrationModel, IntegrationRaw } from '../models'; - -export class IntegrationRepository extends Repository { - constructor(private readonly integrationModel: IntegrationModel, private readonly configService: ConfigService) { - super(configService); - } - - private readonly logger = new Logger('IntegrationRepository'); - - public async create(data: IntegrationRaw, instance: string): Promise { - try { - this.logger.verbose('creating integration'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('saving integration to db'); - const insert = await this.integrationModel.replaceOne({ _id: instance }, { ...data }, { upsert: true }); - - this.logger.verbose('integration saved to db: ' + insert.modifiedCount + ' integration'); - return { insertCount: insert.modifiedCount }; - } - - this.logger.verbose('saving integration to store'); - - this.writeStore({ - path: join(this.storePath, 'integration'), - fileName: instance, - data, - }); - - this.logger.verbose( - 'integration saved to store in path: ' + join(this.storePath, 'integration') + '/' + instance, - ); - - this.logger.verbose('integration created'); - return { insertCount: 1 }; - } catch (error) { - return error; - } - } - - public async find(instance: string): Promise { - try { - this.logger.verbose('finding integration'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding integration in db'); - return await this.integrationModel.findOne({ _id: instance }); - } - - this.logger.verbose('finding integration in store'); - return JSON.parse( - readFileSync(join(this.storePath, 'integration', instance + '.json'), { - encoding: 'utf-8', - }), - ) as IntegrationRaw; - } catch (error) { - return {}; - } - } -} diff --git a/src/api/repository/label.repository.ts b/src/api/repository/label.repository.ts deleted file mode 100644 index 7bbb0e58..00000000 --- a/src/api/repository/label.repository.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { opendirSync, readFileSync, rmSync } from 'fs'; -import { join } from 'path'; - -import { ConfigService, StoreConf } from '../../config/env.config'; -import { Logger } from '../../config/logger.config'; -import { IInsert, Repository } from '../abstract/abstract.repository'; -import { ILabelModel, LabelRaw, LabelRawSelect } from '../models'; - -export class LabelQuery { - select?: LabelRawSelect; - where: Partial; -} - -export class LabelRepository extends Repository { - constructor(private readonly labelModel: ILabelModel, private readonly configService: ConfigService) { - super(configService); - } - - private readonly logger = new Logger('LabelRepository'); - - public async insert(data: LabelRaw, instanceName: string, saveDb = false): Promise { - this.logger.verbose('inserting labels'); - - try { - if (this.dbSettings.ENABLED && saveDb) { - this.logger.verbose('saving labels to db'); - const insert = await this.labelModel.findOneAndUpdate({ id: data.id }, data, { upsert: true }); - - this.logger.verbose(`label ${data.name} saved to db`); - return { insertCount: Number(!!insert._id) }; - } - - this.logger.verbose('saving label to store'); - - const store = this.configService.get('STORE'); - - if (store.LABELS) { - this.logger.verbose('saving label to store'); - this.writeStore({ - path: join(this.storePath, 'labels', instanceName), - fileName: data.id, - data, - }); - this.logger.verbose( - 'labels saved to store in path: ' + join(this.storePath, 'labels', instanceName) + '/' + data.id, - ); - - this.logger.verbose(`label ${data.name} saved to store`); - return { insertCount: 1 }; - } - - this.logger.verbose('labels not saved to store'); - return { insertCount: 0 }; - } catch (error) { - return error; - } finally { - data = undefined; - } - } - - public async find(query: LabelQuery): Promise { - try { - this.logger.verbose('finding labels'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding labels in db'); - return await this.labelModel.find({ owner: query.where.owner }).select(query.select ?? {}); - } - - this.logger.verbose('finding labels in store'); - - const labels: LabelRaw[] = []; - const openDir = opendirSync(join(this.storePath, 'labels', query.where.owner)); - for await (const dirent of openDir) { - if (dirent.isFile()) { - labels.push( - JSON.parse( - readFileSync(join(this.storePath, 'labels', query.where.owner, dirent.name), { - encoding: 'utf-8', - }), - ), - ); - } - } - - this.logger.verbose('labels found in store: ' + labels.length + ' labels'); - return labels; - } catch (error) { - return []; - } - } - - public async delete(query: LabelQuery) { - try { - this.logger.verbose('deleting labels'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('deleting labels in db'); - return await this.labelModel.deleteOne({ ...query.where }); - } - - this.logger.verbose('deleting labels in store'); - rmSync(join(this.storePath, 'labels', query.where.owner, query.where.id + '.josn'), { - force: true, - recursive: true, - }); - - return { deleted: { labelId: query.where.id } }; - } catch (error) { - return { error: error?.toString() }; - } - } -} diff --git a/src/api/repository/message.repository.ts b/src/api/repository/message.repository.ts deleted file mode 100644 index 9802bfae..00000000 --- a/src/api/repository/message.repository.ts +++ /dev/null @@ -1,240 +0,0 @@ -import { opendirSync, readFileSync, rmSync } from 'fs'; -import { join } from 'path'; - -import { ConfigService, StoreConf } from '../../config/env.config'; -import { Logger } from '../../config/logger.config'; -import { IInsert, Repository } from '../abstract/abstract.repository'; -import { IMessageModel, MessageRaw, MessageRawSelect } from '../models'; - -export class MessageQuery { - select?: MessageRawSelect; - where: MessageRaw; - limit?: number; -} - -export class MessageRepository extends Repository { - constructor(private readonly messageModel: IMessageModel, private readonly configService: ConfigService) { - super(configService); - } - - private readonly logger = new Logger('MessageRepository'); - - public buildQuery(query: MessageQuery): MessageQuery { - for (const [o, p] of Object.entries(query?.where || {})) { - if (typeof p === 'object' && p !== null && !Array.isArray(p)) { - for (const [k, v] of Object.entries(p)) { - query.where[`${o}.${k}`] = v; - } - delete query.where[o]; - } - } - - for (const [o, p] of Object.entries(query?.select || {})) { - if (typeof p === 'object' && p !== null && !Array.isArray(p)) { - for (const [k, v] of Object.entries(p)) { - query.select[`${o}.${k}`] = v; - } - delete query.select[o]; - } - } - - return query; - } - - public async insert(data: MessageRaw[], instanceName: string, saveDb = false): Promise { - this.logger.verbose('inserting messages'); - - if (!Array.isArray(data) || data.length === 0) { - this.logger.verbose('no messages to insert'); - return; - } - - try { - if (this.dbSettings.ENABLED && saveDb) { - this.logger.verbose('saving messages to db'); - const cleanedData = data.map((obj) => { - const cleanedObj = { ...obj }; - if ('extendedTextMessage' in obj.message) { - const extendedTextMessage = obj.message.extendedTextMessage as { - contextInfo?: { - mentionedJid?: any; - }; - }; - - if (typeof extendedTextMessage === 'object' && extendedTextMessage !== null) { - if ('contextInfo' in extendedTextMessage) { - delete extendedTextMessage.contextInfo?.mentionedJid; - extendedTextMessage.contextInfo = {}; - } - } - } - return cleanedObj; - }); - - const insert = await this.messageModel.insertMany([...cleanedData]); - - this.logger.verbose('messages saved to db: ' + insert.length + ' messages'); - return { insertCount: insert.length }; - } - - this.logger.verbose('saving messages to store'); - - const store = this.configService.get('STORE'); - - if (store.MESSAGES) { - this.logger.verbose('saving messages to store'); - - data.forEach((message) => { - this.writeStore({ - path: join(this.storePath, 'messages', instanceName), - fileName: message.key.id, - data: message, - }); - this.logger.verbose( - 'messages saved to store in path: ' + join(this.storePath, 'messages', instanceName) + '/' + message.key.id, - ); - }); - - this.logger.verbose('messages saved to store: ' + data.length + ' messages'); - return { insertCount: data.length }; - } - - this.logger.verbose('messages not saved to store'); - return { insertCount: 0 }; - } catch (error) { - console.log('ERROR: ', error); - return error; - } finally { - data = undefined; - } - } - - public async find(query: MessageQuery) { - try { - this.logger.verbose('finding messages'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding messages in db'); - query = this.buildQuery(query); - - return await this.messageModel - .find({ ...query.where }) - .select(query.select || {}) - .sort({ messageTimestamp: -1 }) - .limit(query?.limit ?? 0); - } - - this.logger.verbose('finding messages in store'); - const messages: MessageRaw[] = []; - if (query?.where?.key?.id) { - this.logger.verbose('finding messages in store by id'); - messages.push( - JSON.parse( - readFileSync(join(this.storePath, 'messages', query.where.owner, query.where.key.id + '.json'), { - encoding: 'utf-8', - }), - ), - ); - } else { - this.logger.verbose('finding messages in store by owner'); - const openDir = opendirSync(join(this.storePath, 'messages', query.where.owner), { - encoding: 'utf-8', - }); - - for await (const dirent of openDir) { - if (dirent.isFile()) { - messages.push( - JSON.parse( - readFileSync(join(this.storePath, 'messages', query.where.owner, dirent.name), { - encoding: 'utf-8', - }), - ), - ); - } - } - } - - this.logger.verbose('messages found in store: ' + messages.length + ' messages'); - return messages - .sort((x, y) => { - return (y.messageTimestamp as number) - (x.messageTimestamp as number); - }) - .splice(0, query?.limit ?? messages.length); - } catch (error) { - this.logger.error(`error on message find: ${error.toString()}`); - return []; - } - } - - public async update(data: MessageRaw[], instanceName: string, saveDb?: boolean): Promise { - try { - if (this.dbSettings.ENABLED && saveDb) { - this.logger.verbose('updating messages in db'); - - const messages = data.map((message) => { - return { - updateOne: { - filter: { 'key.id': message.key.id }, - update: { ...message }, - }, - }; - }); - - const { nModified } = await this.messageModel.bulkWrite(messages); - - this.logger.verbose('messages updated in db: ' + nModified + ' messages'); - return { insertCount: nModified }; - } - - this.logger.verbose('updating messages in store'); - - const store = this.configService.get('STORE'); - - if (store.MESSAGES) { - this.logger.verbose('updating messages in store'); - data.forEach((message) => { - this.writeStore({ - path: join(this.storePath, 'messages', instanceName), - fileName: message.key.id, - data: message, - }); - this.logger.verbose( - 'messages updated in store in path: ' + - join(this.storePath, 'messages', instanceName) + - '/' + - message.key.id, - ); - }); - - this.logger.verbose('messages updated in store: ' + data.length + ' messages'); - return { insertCount: data.length }; - } - - this.logger.verbose('messages not updated'); - return { insertCount: 0 }; - } catch (error) { - this.logger.error(error); - } - } - - public async delete(query: MessageQuery) { - try { - this.logger.verbose('deleting message'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('deleting message in db'); - query = this.buildQuery(query); - - return await this.messageModel.deleteOne({ ...query.where }); - } - - this.logger.verbose('deleting message in store'); - rmSync(join(this.storePath, 'messages', query.where.owner, query.where.key.id + '.json'), { - force: true, - recursive: true, - }); - - return { deleted: { messageId: query.where.key.id } }; - } catch (error) { - return { error: error?.toString() }; - } - } -} diff --git a/src/api/repository/messageUp.repository.ts b/src/api/repository/messageUp.repository.ts deleted file mode 100644 index b97bf59b..00000000 --- a/src/api/repository/messageUp.repository.ts +++ /dev/null @@ -1,120 +0,0 @@ -import { opendirSync, readFileSync } from 'fs'; -import { join } from 'path'; - -import { ConfigService, StoreConf } from '../../config/env.config'; -import { Logger } from '../../config/logger.config'; -import { IInsert, Repository } from '../abstract/abstract.repository'; -import { IMessageUpModel, MessageUpdateRaw } from '../models'; - -export class MessageUpQuery { - where: MessageUpdateRaw; - limit?: number; -} - -export class MessageUpRepository extends Repository { - constructor(private readonly messageUpModel: IMessageUpModel, private readonly configService: ConfigService) { - super(configService); - } - - private readonly logger = new Logger('MessageUpRepository'); - - public async insert(data: MessageUpdateRaw[], instanceName: string, saveDb?: boolean): Promise { - this.logger.verbose('inserting message up'); - - if (data.length === 0) { - this.logger.verbose('no message up to insert'); - return; - } - - try { - if (this.dbSettings.ENABLED && saveDb) { - this.logger.verbose('saving message up to db'); - const insert = await this.messageUpModel.insertMany([...data]); - - this.logger.verbose('message up saved to db: ' + insert.length + ' message up'); - return { insertCount: insert.length }; - } - - this.logger.verbose('saving message up to store'); - - const store = this.configService.get('STORE'); - - if (store.MESSAGE_UP) { - this.logger.verbose('saving message up to store'); - data.forEach((update) => { - this.writeStore({ - path: join(this.storePath, 'message-up', instanceName), - fileName: update.id, - data: update, - }); - this.logger.verbose( - 'message up saved to store in path: ' + join(this.storePath, 'message-up', instanceName) + '/' + update.id, - ); - }); - - this.logger.verbose('message up saved to store: ' + data.length + ' message up'); - return { insertCount: data.length }; - } - - this.logger.verbose('message up not saved to store'); - return { insertCount: 0 }; - } catch (error) { - return error; - } - } - - public async find(query: MessageUpQuery) { - try { - this.logger.verbose('finding message up'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding message up in db'); - return await this.messageUpModel - .find({ ...query.where }) - .sort({ datetime: -1 }) - .limit(query?.limit ?? 0); - } - - this.logger.verbose('finding message up in store'); - - const messageUpdate: MessageUpdateRaw[] = []; - if (query?.where?.id) { - this.logger.verbose('finding message up in store by id'); - - messageUpdate.push( - JSON.parse( - readFileSync(join(this.storePath, 'message-up', query.where.owner, query.where.id + '.json'), { - encoding: 'utf-8', - }), - ), - ); - } else { - this.logger.verbose('finding message up in store by owner'); - - const openDir = opendirSync(join(this.storePath, 'message-up', query.where.owner), { - encoding: 'utf-8', - }); - - for await (const dirent of openDir) { - if (dirent.isFile()) { - messageUpdate.push( - JSON.parse( - readFileSync(join(this.storePath, 'message-up', query.where.owner, dirent.name), { - encoding: 'utf-8', - }), - ), - ); - } - } - } - - this.logger.verbose('message up found in store: ' + messageUpdate.length + ' message up'); - return messageUpdate - .sort((x, y) => { - return y.datetime - x.datetime; - }) - .splice(0, query?.limit ?? messageUpdate.length); - } catch (error) { - return []; - } - } -} diff --git a/src/api/repository/proxy.repository.ts b/src/api/repository/proxy.repository.ts deleted file mode 100644 index 169e798f..00000000 --- a/src/api/repository/proxy.repository.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { readFileSync } from 'fs'; -import { join } from 'path'; - -import { ConfigService } from '../../config/env.config'; -import { Logger } from '../../config/logger.config'; -import { IInsert, Repository } from '../abstract/abstract.repository'; -import { IProxyModel, ProxyRaw } from '../models'; - -export class ProxyRepository extends Repository { - constructor(private readonly proxyModel: IProxyModel, private readonly configService: ConfigService) { - super(configService); - } - - private readonly logger = new Logger('ProxyRepository'); - - public async create(data: ProxyRaw, instance: string): Promise { - try { - this.logger.verbose('creating proxy'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('saving proxy to db'); - const insert = await this.proxyModel.replaceOne({ _id: instance }, { ...data }, { upsert: true }); - - this.logger.verbose('proxy saved to db: ' + insert.modifiedCount + ' proxy'); - return { insertCount: insert.modifiedCount }; - } - - this.logger.verbose('saving proxy to store'); - - this.writeStore({ - path: join(this.storePath, 'proxy'), - fileName: instance, - data, - }); - - this.logger.verbose('proxy saved to store in path: ' + join(this.storePath, 'proxy') + '/' + instance); - - this.logger.verbose('proxy created'); - return { insertCount: 1 }; - } catch (error) { - return error; - } - } - - public async find(instance: string): Promise { - try { - this.logger.verbose('finding proxy'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding proxy in db'); - return await this.proxyModel.findOne({ _id: instance }); - } - - this.logger.verbose('finding proxy in store'); - return JSON.parse( - readFileSync(join(this.storePath, 'proxy', instance + '.json'), { - encoding: 'utf-8', - }), - ) as ProxyRaw; - } catch (error) { - return {}; - } - } -} diff --git a/src/api/repository/repository.manager.ts b/src/api/repository/repository.manager.ts deleted file mode 100644 index 5fd9e55e..00000000 --- a/src/api/repository/repository.manager.ts +++ /dev/null @@ -1,168 +0,0 @@ -import fs from 'fs'; -import { MongoClient } from 'mongodb'; -import { join } from 'path'; - -import { Auth, ConfigService, Database } from '../../config/env.config'; -import { Logger } from '../../config/logger.config'; -import { ChamaaiRepository } from '../integrations/chamaai/repository/chamaai.repository'; -import { ChatwootRepository } from '../integrations/chatwoot/repository/chatwoot.repository'; -import { RabbitmqRepository } from '../integrations/rabbitmq/repository/rabbitmq.repository'; -import { SqsRepository } from '../integrations/sqs/repository/sqs.repository'; -import { TypebotRepository } from '../integrations/typebot/repository/typebot.repository'; -import { WebsocketRepository } from '../integrations/websocket/repository/websocket.repository'; -import { AuthRepository } from './auth.repository'; -import { ChatRepository } from './chat.repository'; -import { ContactRepository } from './contact.repository'; -import { IntegrationRepository } from './integration.repository'; -import { LabelRepository } from './label.repository'; -import { MessageRepository } from './message.repository'; -import { MessageUpRepository } from './messageUp.repository'; -import { ProxyRepository } from './proxy.repository'; -import { SettingsRepository } from './settings.repository'; -import { WebhookRepository } from './webhook.repository'; -export class RepositoryBroker { - constructor( - public readonly message: MessageRepository, - public readonly chat: ChatRepository, - public readonly contact: ContactRepository, - public readonly messageUpdate: MessageUpRepository, - public readonly webhook: WebhookRepository, - public readonly chatwoot: ChatwootRepository, - public readonly settings: SettingsRepository, - public readonly websocket: WebsocketRepository, - public readonly rabbitmq: RabbitmqRepository, - public readonly sqs: SqsRepository, - public readonly typebot: TypebotRepository, - public readonly proxy: ProxyRepository, - public readonly chamaai: ChamaaiRepository, - public readonly integration: IntegrationRepository, - public readonly auth: AuthRepository, - public readonly labels: LabelRepository, - private configService: ConfigService, - dbServer?: MongoClient, - ) { - this.dbClient = dbServer; - this.__init_repo_without_db__(); - } - - private dbClient?: MongoClient; - private readonly logger = new Logger('RepositoryBroker'); - - public get dbServer() { - return this.dbClient; - } - - private __init_repo_without_db__() { - this.logger.verbose('initializing repository without db'); - if (!this.configService.get('DATABASE').ENABLED) { - const storePath = join(process.cwd(), 'store'); - - this.logger.verbose('creating store path: ' + storePath); - try { - const authDir = join(storePath, 'auth', this.configService.get('AUTHENTICATION').TYPE); - const chatsDir = join(storePath, 'chats'); - const contactsDir = join(storePath, 'contacts'); - const messagesDir = join(storePath, 'messages'); - const messageUpDir = join(storePath, 'message-up'); - const webhookDir = join(storePath, 'webhook'); - const chatwootDir = join(storePath, 'chatwoot'); - const settingsDir = join(storePath, 'settings'); - const websocketDir = join(storePath, 'websocket'); - const rabbitmqDir = join(storePath, 'rabbitmq'); - const sqsDir = join(storePath, 'sqs'); - const typebotDir = join(storePath, 'typebot'); - const proxyDir = join(storePath, 'proxy'); - const chamaaiDir = join(storePath, 'chamaai'); - const integrationDir = join(storePath, 'integration'); - const tempDir = join(storePath, 'temp'); - - if (!fs.existsSync(authDir)) { - this.logger.verbose('creating auth dir: ' + authDir); - fs.mkdirSync(authDir, { recursive: true }); - } - if (!fs.existsSync(chatsDir)) { - this.logger.verbose('creating chats dir: ' + chatsDir); - fs.mkdirSync(chatsDir, { recursive: true }); - } - if (!fs.existsSync(contactsDir)) { - this.logger.verbose('creating contacts dir: ' + contactsDir); - fs.mkdirSync(contactsDir, { recursive: true }); - } - if (!fs.existsSync(messagesDir)) { - this.logger.verbose('creating messages dir: ' + messagesDir); - fs.mkdirSync(messagesDir, { recursive: true }); - } - if (!fs.existsSync(messageUpDir)) { - this.logger.verbose('creating message-up dir: ' + messageUpDir); - fs.mkdirSync(messageUpDir, { recursive: true }); - } - if (!fs.existsSync(webhookDir)) { - this.logger.verbose('creating webhook dir: ' + webhookDir); - fs.mkdirSync(webhookDir, { recursive: true }); - } - if (!fs.existsSync(chatwootDir)) { - this.logger.verbose('creating chatwoot dir: ' + chatwootDir); - fs.mkdirSync(chatwootDir, { recursive: true }); - } - if (!fs.existsSync(settingsDir)) { - this.logger.verbose('creating settings dir: ' + settingsDir); - fs.mkdirSync(settingsDir, { recursive: true }); - } - if (!fs.existsSync(websocketDir)) { - this.logger.verbose('creating websocket dir: ' + websocketDir); - fs.mkdirSync(websocketDir, { recursive: true }); - } - if (!fs.existsSync(rabbitmqDir)) { - this.logger.verbose('creating rabbitmq dir: ' + rabbitmqDir); - fs.mkdirSync(rabbitmqDir, { recursive: true }); - } - if (!fs.existsSync(sqsDir)) { - this.logger.verbose('creating sqs dir: ' + sqsDir); - fs.mkdirSync(sqsDir, { recursive: true }); - } - if (!fs.existsSync(typebotDir)) { - this.logger.verbose('creating typebot dir: ' + typebotDir); - fs.mkdirSync(typebotDir, { recursive: true }); - } - if (!fs.existsSync(proxyDir)) { - this.logger.verbose('creating proxy dir: ' + proxyDir); - fs.mkdirSync(proxyDir, { recursive: true }); - } - if (!fs.existsSync(chamaaiDir)) { - this.logger.verbose('creating chamaai dir: ' + chamaaiDir); - fs.mkdirSync(chamaaiDir, { recursive: true }); - } - if (!fs.existsSync(integrationDir)) { - this.logger.verbose('creating integration dir: ' + integrationDir); - fs.mkdirSync(integrationDir, { recursive: true }); - } - if (!fs.existsSync(tempDir)) { - this.logger.verbose('creating temp dir: ' + tempDir); - fs.mkdirSync(tempDir, { recursive: true }); - } - } catch (error) { - this.logger.error(error); - } - } else { - try { - const storePath = join(process.cwd(), 'store'); - - this.logger.verbose('creating store path: ' + storePath); - - const tempDir = join(storePath, 'temp'); - const chatwootDir = join(storePath, 'chatwoot'); - - if (!fs.existsSync(chatwootDir)) { - this.logger.verbose('creating chatwoot dir: ' + chatwootDir); - fs.mkdirSync(chatwootDir, { recursive: true }); - } - if (!fs.existsSync(tempDir)) { - this.logger.verbose('creating temp dir: ' + tempDir); - fs.mkdirSync(tempDir, { recursive: true }); - } - } catch (error) { - this.logger.error(error); - } - } - } -} diff --git a/src/api/repository/repository.service.ts b/src/api/repository/repository.service.ts new file mode 100644 index 00000000..793bb0c8 --- /dev/null +++ b/src/api/repository/repository.service.ts @@ -0,0 +1,28 @@ +import { ConfigService } from '@config/env.config'; +import { Logger } from '@config/logger.config'; +import { PrismaClient } from '@prisma/client'; + +export class Query { + where?: T; + sort?: 'asc' | 'desc'; + page?: number; + offset?: number; +} + +export class PrismaRepository extends PrismaClient { + constructor(private readonly configService: ConfigService) { + super(); + } + + private readonly logger = new Logger('PrismaRepository'); + + public async onModuleInit() { + await this.$connect(); + this.logger.info('Repository:Prisma - ON'); + } + + public async onModuleDestroy() { + await this.$disconnect(); + this.logger.warn('Repository:Prisma - OFF'); + } +} diff --git a/src/api/repository/settings.repository.ts b/src/api/repository/settings.repository.ts deleted file mode 100644 index 4d09d79f..00000000 --- a/src/api/repository/settings.repository.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { readFileSync } from 'fs'; -import { join } from 'path'; - -import { ConfigService } from '../../config/env.config'; -import { Logger } from '../../config/logger.config'; -import { IInsert, Repository } from '../abstract/abstract.repository'; -import { ISettingsModel, SettingsRaw } from '../models'; - -export class SettingsRepository extends Repository { - constructor(private readonly settingsModel: ISettingsModel, private readonly configService: ConfigService) { - super(configService); - } - - private readonly logger = new Logger('SettingsRepository'); - - public async create(data: SettingsRaw, instance: string): Promise { - try { - this.logger.verbose('creating settings'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('saving settings to db'); - const insert = await this.settingsModel.replaceOne({ _id: instance }, { ...data }, { upsert: true }); - - this.logger.verbose('settings saved to db: ' + insert.modifiedCount + ' settings'); - return { insertCount: insert.modifiedCount }; - } - - this.logger.verbose('saving settings to store'); - - this.writeStore({ - path: join(this.storePath, 'settings'), - fileName: instance, - data, - }); - - this.logger.verbose('settings saved to store in path: ' + join(this.storePath, 'settings') + '/' + instance); - - this.logger.verbose('settings created'); - return { insertCount: 1 }; - } catch (error) { - return error; - } - } - - public async find(instance: string): Promise { - try { - this.logger.verbose('finding settings'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding settings in db'); - return await this.settingsModel.findOne({ _id: instance }); - } - - this.logger.verbose('finding settings in store'); - return JSON.parse( - readFileSync(join(this.storePath, 'settings', instance + '.json'), { - encoding: 'utf-8', - }), - ) as SettingsRaw; - } catch (error) { - return {}; - } - } -} diff --git a/src/api/repository/webhook.repository.ts b/src/api/repository/webhook.repository.ts deleted file mode 100644 index 10074516..00000000 --- a/src/api/repository/webhook.repository.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { readFileSync } from 'fs'; -import { join } from 'path'; - -import { ConfigService } from '../../config/env.config'; -import { Logger } from '../../config/logger.config'; -import { IInsert, Repository } from '../abstract/abstract.repository'; -import { IWebhookModel, WebhookRaw } from '../models'; - -export class WebhookRepository extends Repository { - constructor(private readonly webhookModel: IWebhookModel, private readonly configService: ConfigService) { - super(configService); - } - - private readonly logger = new Logger('WebhookRepository'); - - public async create(data: WebhookRaw, instance: string): Promise { - try { - this.logger.verbose('creating webhook'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('saving webhook to db'); - const insert = await this.webhookModel.replaceOne({ _id: instance }, { ...data }, { upsert: true }); - - this.logger.verbose('webhook saved to db: ' + insert.modifiedCount + ' webhook'); - return { insertCount: insert.modifiedCount }; - } - - this.logger.verbose('saving webhook to store'); - - this.writeStore({ - path: join(this.storePath, 'webhook'), - fileName: instance, - data, - }); - - this.logger.verbose('webhook saved to store in path: ' + join(this.storePath, 'webhook') + '/' + instance); - - this.logger.verbose('webhook created'); - return { insertCount: 1 }; - } catch (error) { - return error; - } - } - - public async find(instance: string): Promise { - try { - this.logger.verbose('finding webhook'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding webhook in db'); - return await this.webhookModel.findOne({ _id: instance }); - } - - this.logger.verbose('finding webhook in store'); - return JSON.parse( - readFileSync(join(this.storePath, 'webhook', instance + '.json'), { - encoding: 'utf-8', - }), - ) as WebhookRaw; - } catch (error) { - return {}; - } - } -} diff --git a/src/api/routes/call.router.ts b/src/api/routes/call.router.ts new file mode 100644 index 00000000..e049cc4f --- /dev/null +++ b/src/api/routes/call.router.ts @@ -0,0 +1,25 @@ +import { RouterBroker } from '@api/abstract/abstract.router'; +import { OfferCallDto } from '@api/dto/call.dto'; +import { callController } from '@api/server.module'; +import { offerCallSchema } from '@validate/validate.schema'; +import { RequestHandler, Router } from 'express'; + +import { HttpStatus } from './index.router'; + +export class CallRouter extends RouterBroker { + constructor(...guards: RequestHandler[]) { + super(); + this.router.post(this.routerPath('offer'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: offerCallSchema, + ClassRef: OfferCallDto, + execute: (instance, data) => callController.offerCall(instance, data), + }); + + return res.status(HttpStatus.CREATED).json(response); + }); + } + + public readonly router: Router = Router(); +} diff --git a/src/api/routes/chat.router.ts b/src/api/routes/chat.router.ts index 4debf3d1..20126c1a 100644 --- a/src/api/routes/chat.router.ts +++ b/src/api/routes/chat.router.ts @@ -1,6 +1,24 @@ -import { RequestHandler, Router } from 'express'; - -import { Logger } from '../../config/logger.config'; +import { RouterBroker } from '@api/abstract/abstract.router'; +import { + ArchiveChatDto, + BlockUserDto, + DeleteMessage, + getBase64FromMediaMessageDto, + MarkChatUnreadDto, + NumberDto, + PrivacySettingDto, + ProfileNameDto, + ProfilePictureDto, + ProfileStatusDto, + ReadMessageDto, + SendPresenceDto, + UpdateMessageDto, + WhatsAppNumberDto, +} from '@api/dto/chat.dto'; +import { InstanceDto } from '@api/dto/instance.dto'; +import { Query } from '@api/repository/repository.service'; +import { chatController } from '@api/server.module'; +import { Contact, Message, MessageUpdate } from '@prisma/client'; import { archiveChatSchema, blockUserSchema, @@ -18,45 +36,16 @@ import { readMessageSchema, updateMessageSchema, whatsappNumberSchema, -} from '../../validate/validate.schema'; -import { RouterBroker } from '../abstract/abstract.router'; -import { - ArchiveChatDto, - BlockUserDto, - DeleteMessage, - getBase64FromMediaMessageDto, - MarkChatUnreadDto, - NumberDto, - PrivacySettingDto, - ProfileNameDto, - ProfilePictureDto, - ProfileStatusDto, - ReadMessageDto, - SendPresenceDto, - UpdateMessageDto, - WhatsAppNumberDto, -} from '../dto/chat.dto'; -import { InstanceDto } from '../dto/instance.dto'; -import { ContactQuery } from '../repository/contact.repository'; -import { MessageQuery } from '../repository/message.repository'; -import { MessageUpQuery } from '../repository/messageUp.repository'; -import { chatController } from '../server.module'; -import { HttpStatus } from './index.router'; +} from '@validate/validate.schema'; +import { RequestHandler, Router } from 'express'; -const logger = new Logger('ChatRouter'); +import { HttpStatus } from './index.router'; export class ChatRouter extends RouterBroker { constructor(...guards: RequestHandler[]) { super(); this.router .post(this.routerPath('whatsappNumbers'), ...guards, async (req, res) => { - logger.verbose('request received in whatsappNumbers'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - const response = await this.dataValidate({ request: req, schema: whatsappNumberSchema, @@ -66,14 +55,7 @@ export class ChatRouter extends RouterBroker { return res.status(HttpStatus.OK).json(response); }) - .put(this.routerPath('markMessageAsRead'), ...guards, async (req, res) => { - logger.verbose('request received in markMessageAsRead'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - + .post(this.routerPath('markMessageAsRead'), ...guards, async (req, res) => { const response = await this.dataValidate({ request: req, schema: readMessageSchema, @@ -83,14 +65,7 @@ export class ChatRouter extends RouterBroker { return res.status(HttpStatus.CREATED).json(response); }) - .put(this.routerPath('archiveChat'), ...guards, async (req, res) => { - logger.verbose('request received in archiveChat'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - + .post(this.routerPath('archiveChat'), ...guards, async (req, res) => { const response = await this.dataValidate({ request: req, schema: archiveChatSchema, @@ -100,14 +75,7 @@ export class ChatRouter extends RouterBroker { return res.status(HttpStatus.CREATED).json(response); }) - .put(this.routerPath('markChatUnread'), ...guards, async (req, res) => { - logger.verbose('request received in markChatUnread'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - + .post(this.routerPath('markChatUnread'), ...guards, async (req, res) => { const response = await this.dataValidate({ request: req, schema: markChatUnreadSchema, @@ -118,13 +86,6 @@ export class ChatRouter extends RouterBroker { return res.status(HttpStatus.CREATED).json(response); }) .delete(this.routerPath('deleteMessageForEveryone'), ...guards, async (req, res) => { - logger.verbose('request received in deleteMessageForEveryone'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - const response = await this.dataValidate({ request: req, schema: deleteMessageSchema, @@ -135,13 +96,6 @@ export class ChatRouter extends RouterBroker { return res.status(HttpStatus.CREATED).json(response); }) .post(this.routerPath('fetchProfilePictureUrl'), ...guards, async (req, res) => { - logger.verbose('request received in fetchProfilePictureUrl'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - const response = await this.dataValidate({ request: req, schema: profilePictureSchema, @@ -151,48 +105,7 @@ export class ChatRouter extends RouterBroker { return res.status(HttpStatus.OK).json(response); }) - .post(this.routerPath('fetchProfile'), ...guards, async (req, res) => { - logger.verbose('request received in fetchProfile'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - - const response = await this.dataValidate({ - request: req, - schema: profileSchema, - ClassRef: NumberDto, - execute: (instance, data) => chatController.fetchProfile(instance, data), - }); - - return res.status(HttpStatus.OK).json(response); - }) - .post(this.routerPath('findContacts'), ...guards, async (req, res) => { - logger.verbose('request received in findContacts'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - - const response = await this.dataValidate({ - request: req, - schema: contactValidateSchema, - ClassRef: ContactQuery, - execute: (instance, data) => chatController.fetchContacts(instance, data), - }); - - return res.status(HttpStatus.OK).json(response); - }) .post(this.routerPath('getBase64FromMediaMessage'), ...guards, async (req, res) => { - logger.verbose('request received in getBase64FromMediaMessage'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - const response = await this.dataValidate({ request: req, schema: null, @@ -202,64 +115,18 @@ export class ChatRouter extends RouterBroker { return res.status(HttpStatus.CREATED).json(response); }) - .post(this.routerPath('findMessages'), ...guards, async (req, res) => { - logger.verbose('request received in findMessages'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - - const response = await this.dataValidate({ + // TODO: corrigir updateMessage para medias tambem + .post(this.routerPath('updateMessage'), ...guards, async (req, res) => { + const response = await this.dataValidate({ request: req, - schema: messageValidateSchema, - ClassRef: MessageQuery, - execute: (instance, data) => chatController.fetchMessages(instance, data), - }); - - return res.status(HttpStatus.OK).json(response); - }) - .post(this.routerPath('findStatusMessage'), ...guards, async (req, res) => { - logger.verbose('request received in findStatusMessage'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - - const response = await this.dataValidate({ - request: req, - schema: messageUpSchema, - ClassRef: MessageUpQuery, - execute: (instance, data) => chatController.fetchStatusMessage(instance, data), - }); - - return res.status(HttpStatus.OK).json(response); - }) - .get(this.routerPath('findChats'), ...guards, async (req, res) => { - logger.verbose('request received in findChats'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - - const response = await this.dataValidate({ - request: req, - schema: null, - ClassRef: InstanceDto, - execute: (instance) => chatController.fetchChats(instance), + schema: updateMessageSchema, + ClassRef: UpdateMessageDto, + execute: (instance, data) => chatController.updateMessage(instance, data), }); return res.status(HttpStatus.OK).json(response); }) .post(this.routerPath('sendPresence'), ...guards, async (req, res) => { - logger.verbose('request received in sendPresence'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); const response = await this.dataValidate({ request: req, schema: presenceSchema, @@ -269,49 +136,58 @@ export class ChatRouter extends RouterBroker { return res.status(HttpStatus.CREATED).json(response); }) - // Profile routes - .get(this.routerPath('fetchPrivacySettings'), ...guards, async (req, res) => { - logger.verbose('request received in fetchPrivacySettings'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - - const response = await this.dataValidate({ + .post(this.routerPath('updateBlockStatus'), ...guards, async (req, res) => { + const response = await this.dataValidate({ request: req, - schema: null, - ClassRef: InstanceDto, - execute: (instance) => chatController.fetchPrivacySettings(instance), - }); - - return res.status(HttpStatus.OK).json(response); - }) - .put(this.routerPath('updatePrivacySettings'), ...guards, async (req, res) => { - logger.verbose('request received in updatePrivacySettings'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - - const response = await this.dataValidate({ - request: req, - schema: privacySettingsSchema, - ClassRef: PrivacySettingDto, - execute: (instance, data) => chatController.updatePrivacySettings(instance, data), + schema: blockUserSchema, + ClassRef: BlockUserDto, + execute: (instance, data) => chatController.blockUser(instance, data), }); return res.status(HttpStatus.CREATED).json(response); }) + .post(this.routerPath('findContacts'), ...guards, async (req, res) => { + const response = await this.dataValidate>({ + request: req, + schema: contactValidateSchema, + ClassRef: Query, + execute: (instance, data) => chatController.fetchContacts(instance, data), + }); + + return res.status(HttpStatus.OK).json(response); + }) + .post(this.routerPath('findMessages'), ...guards, async (req, res) => { + const response = await this.dataValidate>({ + request: req, + schema: messageValidateSchema, + ClassRef: Query, + execute: (instance, data) => chatController.fetchMessages(instance, data), + }); + + return res.status(HttpStatus.OK).json(response); + }) + .post(this.routerPath('findStatusMessage'), ...guards, async (req, res) => { + const response = await this.dataValidate>({ + request: req, + schema: messageUpSchema, + ClassRef: Query, + execute: (instance, data) => chatController.fetchStatusMessage(instance, data), + }); + + return res.status(HttpStatus.OK).json(response); + }) + .post(this.routerPath('findChats'), ...guards, async (req, res) => { + const response = await this.dataValidate>({ + request: req, + schema: contactValidateSchema, + ClassRef: Query, + execute: (instance, data) => chatController.fetchChats(instance, data), + }); + + return res.status(HttpStatus.OK).json(response); + }) + // Profile routes .post(this.routerPath('fetchBusinessProfile'), ...guards, async (req, res) => { - logger.verbose('request received in fetchBusinessProfile'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - const response = await this.dataValidate({ request: req, schema: profilePictureSchema, @@ -321,14 +197,18 @@ export class ChatRouter extends RouterBroker { return res.status(HttpStatus.OK).json(response); }) + .post(this.routerPath('fetchProfile'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: profileSchema, + ClassRef: NumberDto, + execute: (instance, data) => chatController.fetchProfile(instance, data), + }); + + return res.status(HttpStatus.OK).json(response); + }) + .post(this.routerPath('updateProfileName'), ...guards, async (req, res) => { - logger.verbose('request received in updateProfileName'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - const response = await this.dataValidate({ request: req, schema: profileNameSchema, @@ -339,13 +219,6 @@ export class ChatRouter extends RouterBroker { return res.status(HttpStatus.OK).json(response); }) .post(this.routerPath('updateProfileStatus'), ...guards, async (req, res) => { - logger.verbose('request received in updateProfileStatus'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - const response = await this.dataValidate({ request: req, schema: profileStatusSchema, @@ -355,14 +228,7 @@ export class ChatRouter extends RouterBroker { return res.status(HttpStatus.OK).json(response); }) - .put(this.routerPath('updateProfilePicture'), ...guards, async (req, res) => { - logger.verbose('request received in updateProfilePicture'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - + .post(this.routerPath('updateProfilePicture'), ...guards, async (req, res) => { const response = await this.dataValidate({ request: req, schema: profilePictureSchema, @@ -373,13 +239,6 @@ export class ChatRouter extends RouterBroker { return res.status(HttpStatus.OK).json(response); }) .delete(this.routerPath('removeProfilePicture'), ...guards, async (req, res) => { - logger.verbose('request received in removeProfilePicture'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - const response = await this.dataValidate({ request: req, schema: profilePictureSchema, @@ -389,41 +248,27 @@ export class ChatRouter extends RouterBroker { return res.status(HttpStatus.OK).json(response); }) - .put(this.routerPath('updateMessage'), ...guards, async (req, res) => { - logger.verbose('request received in updateMessage'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - - const response = await this.dataValidate({ + .get(this.routerPath('fetchPrivacySettings'), ...guards, async (req, res) => { + const response = await this.dataValidate({ request: req, - schema: updateMessageSchema, - ClassRef: UpdateMessageDto, - execute: (instance, data) => chatController.updateMessage(instance, data), + schema: null, + ClassRef: InstanceDto, + execute: (instance) => chatController.fetchPrivacySettings(instance), }); return res.status(HttpStatus.OK).json(response); }) - .put(this.routerPath('updateBlockStatus'), ...guards, async (req, res) => { - logger.verbose('request received in updateBlockStatus'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - - const response = await this.dataValidate({ + .post(this.routerPath('updatePrivacySettings'), ...guards, async (req, res) => { + const response = await this.dataValidate({ request: req, - schema: blockUserSchema, - ClassRef: BlockUserDto, - execute: (instance, data) => chatController.blockUser(instance, data), + schema: privacySettingsSchema, + ClassRef: PrivacySettingDto, + execute: (instance, data) => chatController.updatePrivacySettings(instance, data), }); return res.status(HttpStatus.CREATED).json(response); }); } - public readonly router = Router(); + public readonly router: Router = Router(); } diff --git a/src/api/routes/group.router.ts b/src/api/routes/group.router.ts index 244dfee2..7086b117 100644 --- a/src/api/routes/group.router.ts +++ b/src/api/routes/group.router.ts @@ -1,21 +1,4 @@ -import { RequestHandler, Router } from 'express'; - -import { Logger } from '../../config/logger.config'; -import { - AcceptGroupInviteSchema, - createGroupSchema, - getParticipantsSchema, - groupInviteSchema, - groupJidSchema, - groupSendInviteSchema, - toggleEphemeralSchema, - updateGroupDescriptionSchema, - updateGroupPictureSchema, - updateGroupSubjectSchema, - updateParticipantsSchema, - updateSettingsSchema, -} from '../../validate/validate.schema'; -import { RouterBroker } from '../abstract/abstract.router'; +import { RouterBroker } from '@api/abstract/abstract.router'; import { AcceptGroupInvite, CreateGroupDto, @@ -29,23 +12,31 @@ import { GroupToggleEphemeralDto, GroupUpdateParticipantDto, GroupUpdateSettingDto, -} from '../dto/group.dto'; -import { groupController } from '../server.module'; -import { HttpStatus } from './index.router'; +} from '@api/dto/group.dto'; +import { groupController } from '@api/server.module'; +import { + AcceptGroupInviteSchema, + createGroupSchema, + getParticipantsSchema, + groupInviteSchema, + groupJidSchema, + groupSendInviteSchema, + toggleEphemeralSchema, + updateGroupDescriptionSchema, + updateGroupPictureSchema, + updateGroupSubjectSchema, + updateParticipantsSchema, + updateSettingsSchema, +} from '@validate/validate.schema'; +import { RequestHandler, Router } from 'express'; -const logger = new Logger('GroupRouter'); +import { HttpStatus } from './index.router'; export class GroupRouter extends RouterBroker { constructor(...guards: RequestHandler[]) { super(); this.router .post(this.routerPath('create'), ...guards, async (req, res) => { - logger.verbose('request received in createGroup'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); const response = await this.dataValidate({ request: req, schema: createGroupSchema, @@ -55,14 +46,7 @@ export class GroupRouter extends RouterBroker { res.status(HttpStatus.CREATED).json(response); }) - .put(this.routerPath('updateGroupSubject'), ...guards, async (req, res) => { - logger.verbose('request received in updateGroupSubject'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - + .post(this.routerPath('updateGroupSubject'), ...guards, async (req, res) => { const response = await this.groupValidate({ request: req, schema: updateGroupSubjectSchema, @@ -72,13 +56,7 @@ export class GroupRouter extends RouterBroker { res.status(HttpStatus.CREATED).json(response); }) - .put(this.routerPath('updateGroupPicture'), ...guards, async (req, res) => { - logger.verbose('request received in updateGroupPicture'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); + .post(this.routerPath('updateGroupPicture'), ...guards, async (req, res) => { const response = await this.groupValidate({ request: req, schema: updateGroupPictureSchema, @@ -88,13 +66,7 @@ export class GroupRouter extends RouterBroker { res.status(HttpStatus.CREATED).json(response); }) - .put(this.routerPath('updateGroupDescription'), ...guards, async (req, res) => { - logger.verbose('request received in updateGroupDescription'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); + .post(this.routerPath('updateGroupDescription'), ...guards, async (req, res) => { const response = await this.groupValidate({ request: req, schema: updateGroupDescriptionSchema, @@ -105,12 +77,6 @@ export class GroupRouter extends RouterBroker { res.status(HttpStatus.CREATED).json(response); }) .get(this.routerPath('findGroupInfos'), ...guards, async (req, res) => { - logger.verbose('request received in findGroupInfos'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); const response = await this.groupValidate({ request: req, schema: groupJidSchema, @@ -121,12 +87,6 @@ export class GroupRouter extends RouterBroker { res.status(HttpStatus.OK).json(response); }) .get(this.routerPath('fetchAllGroups'), ...guards, async (req, res) => { - logger.verbose('request received in fetchAllGroups'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); const response = await this.getParticipantsValidate({ request: req, schema: getParticipantsSchema, @@ -137,12 +97,6 @@ export class GroupRouter extends RouterBroker { res.status(HttpStatus.OK).json(response); }) .get(this.routerPath('participants'), ...guards, async (req, res) => { - logger.verbose('request received in participants'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); const response = await this.groupValidate({ request: req, schema: groupJidSchema, @@ -153,12 +107,6 @@ export class GroupRouter extends RouterBroker { res.status(HttpStatus.OK).json(response); }) .get(this.routerPath('inviteCode'), ...guards, async (req, res) => { - logger.verbose('request received in inviteCode'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); const response = await this.groupValidate({ request: req, schema: groupJidSchema, @@ -169,12 +117,6 @@ export class GroupRouter extends RouterBroker { res.status(HttpStatus.OK).json(response); }) .get(this.routerPath('inviteInfo'), ...guards, async (req, res) => { - logger.verbose('request received in inviteInfo'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); const response = await this.inviteCodeValidate({ request: req, schema: groupInviteSchema, @@ -185,12 +127,6 @@ export class GroupRouter extends RouterBroker { res.status(HttpStatus.OK).json(response); }) .get(this.routerPath('acceptInviteCode'), ...guards, async (req, res) => { - logger.verbose('request received in acceptInviteCode'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); const response = await this.inviteCodeValidate({ request: req, schema: AcceptGroupInviteSchema, @@ -201,12 +137,6 @@ export class GroupRouter extends RouterBroker { res.status(HttpStatus.OK).json(response); }) .post(this.routerPath('sendInvite'), ...guards, async (req, res) => { - logger.verbose('request received in sendInvite'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); const response = await this.groupNoValidate({ request: req, schema: groupSendInviteSchema, @@ -216,13 +146,7 @@ export class GroupRouter extends RouterBroker { res.status(HttpStatus.OK).json(response); }) - .put(this.routerPath('revokeInviteCode'), ...guards, async (req, res) => { - logger.verbose('request received in revokeInviteCode'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); + .post(this.routerPath('revokeInviteCode'), ...guards, async (req, res) => { const response = await this.groupValidate({ request: req, schema: groupJidSchema, @@ -232,13 +156,7 @@ export class GroupRouter extends RouterBroker { res.status(HttpStatus.CREATED).json(response); }) - .put(this.routerPath('updateParticipant'), ...guards, async (req, res) => { - logger.verbose('request received in updateParticipant'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); + .post(this.routerPath('updateParticipant'), ...guards, async (req, res) => { const response = await this.groupValidate({ request: req, schema: updateParticipantsSchema, @@ -248,13 +166,7 @@ export class GroupRouter extends RouterBroker { res.status(HttpStatus.CREATED).json(response); }) - .put(this.routerPath('updateSetting'), ...guards, async (req, res) => { - logger.verbose('request received in updateSetting'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); + .post(this.routerPath('updateSetting'), ...guards, async (req, res) => { const response = await this.groupValidate({ request: req, schema: updateSettingsSchema, @@ -264,13 +176,7 @@ export class GroupRouter extends RouterBroker { res.status(HttpStatus.CREATED).json(response); }) - .put(this.routerPath('toggleEphemeral'), ...guards, async (req, res) => { - logger.verbose('request received in toggleEphemeral'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); + .post(this.routerPath('toggleEphemeral'), ...guards, async (req, res) => { const response = await this.groupValidate({ request: req, schema: toggleEphemeralSchema, @@ -281,12 +187,6 @@ export class GroupRouter extends RouterBroker { res.status(HttpStatus.CREATED).json(response); }) .delete(this.routerPath('leaveGroup'), ...guards, async (req, res) => { - logger.verbose('request received in leaveGroup'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); const response = await this.groupValidate({ request: req, schema: {}, @@ -298,5 +198,5 @@ export class GroupRouter extends RouterBroker { }); } - public readonly router = Router(); + public readonly router: Router = Router(); } diff --git a/src/api/routes/index.router.ts b/src/api/routes/index.router.ts index 3b26671f..a4a7c071 100644 --- a/src/api/routes/index.router.ts +++ b/src/api/routes/index.router.ts @@ -1,15 +1,17 @@ +import { authGuard } from '@api/guards/auth.guard'; +import { instanceExistsGuard, instanceLoggedGuard } from '@api/guards/instance.guard'; +import Telemetry from '@api/guards/telemetry.guard'; +import { ChannelRouter } from '@api/integrations/channel/channel.router'; +import { ChatbotRouter } from '@api/integrations/chatbot/chatbot.router'; +import { EventRouter } from '@api/integrations/event/event.router'; +import { StorageRouter } from '@api/integrations/storage/storage.router'; +import { configService } from '@config/env.config'; import { Router } from 'express'; import fs from 'fs'; +import mimeTypes from 'mime-types'; +import path from 'path'; -import { Auth, configService } from '../../config/env.config'; -import { authGuard } from '../guards/auth.guard'; -import { instanceExistsGuard, instanceLoggedGuard } from '../guards/instance.guard'; -import { ChamaaiRouter } from '../integrations/chamaai/routes/chamaai.router'; -import { ChatwootRouter } from '../integrations/chatwoot/routes/chatwoot.router'; -import { RabbitmqRouter } from '../integrations/rabbitmq/routes/rabbitmq.router'; -import { SqsRouter } from '../integrations/sqs/routes/sqs.router'; -import { TypebotRouter } from '../integrations/typebot/routes/typebot.router'; -import { WebsocketRouter } from '../integrations/websocket/routes/websocket.router'; +import { CallRouter } from './call.router'; import { ChatRouter } from './chat.router'; import { GroupRouter } from './group.router'; import { InstanceRouter } from './instance.router'; @@ -17,8 +19,8 @@ import { LabelRouter } from './label.router'; import { ProxyRouter } from './proxy.router'; import { MessageRouter } from './sendMessage.router'; import { SettingsRouter } from './settings.router'; +import { TemplateRouter } from './template.router'; import { ViewsRouter } from './view.router'; -import { WebhookRouter } from './webhook.router'; enum HttpStatus { OK = 200, @@ -30,39 +32,64 @@ enum HttpStatus { INTERNAL_SERVER_ERROR = 500, } -const router = Router(); -const authType = configService.get('AUTHENTICATION').TYPE; +const router: Router = Router(); const serverConfig = configService.get('SERVER'); -const guards = [instanceExistsGuard, instanceLoggedGuard, authGuard[authType]]; +const guards = [instanceExistsGuard, instanceLoggedGuard, authGuard['apikey']]; + +const telemetry = new Telemetry(); const packageJson = JSON.parse(fs.readFileSync('./package.json', 'utf8')); if (!serverConfig.DISABLE_MANAGER) router.use('/manager', new ViewsRouter().router); +router.get('/assets/*', (req, res) => { + const fileName = req.params[0]; + const basePath = path.join(process.cwd(), 'manager', 'dist'); + + const filePath = path.join(basePath, 'assets/', fileName); + + if (fs.existsSync(filePath)) { + res.set('Content-Type', mimeTypes.lookup(filePath) || 'text/css'); + res.send(fs.readFileSync(filePath)); + } else { + res.status(404).send('File not found'); + } +}); + router + .use((req, res, next) => telemetry.collectTelemetry(req, res, next)) + .get('/', (req, res) => { res.status(HttpStatus.OK).json({ status: HttpStatus.OK, message: 'Welcome to the Evolution API, it is working!', version: packageJson.version, - swagger: !serverConfig.DISABLE_DOCS ? `${req.protocol}://${req.get('host')}/docs` : undefined, + clientName: process.env.DATABASE_CONNECTION_CLIENT_NAME, manager: !serverConfig.DISABLE_MANAGER ? `${req.protocol}://${req.get('host')}/manager` : undefined, documentation: `https://doc.evolution-api.com`, }); }) + .post('/verify-creds', authGuard['apikey'], async (req, res) => { + return res.status(HttpStatus.OK).json({ + status: HttpStatus.OK, + message: 'Credentials are valid', + facebookAppId: process.env.FACEBOOK_APP_ID, + facebookConfigId: process.env.FACEBOOK_CONFIG_ID, + facebookUserToken: process.env.FACEBOOK_USER_TOKEN, + }); + }) .use('/instance', new InstanceRouter(configService, ...guards).router) .use('/message', new MessageRouter(...guards).router) + .use('/call', new CallRouter(...guards).router) .use('/chat', new ChatRouter(...guards).router) .use('/group', new GroupRouter(...guards).router) - .use('/webhook', new WebhookRouter(configService, ...guards).router) - .use('/chatwoot', new ChatwootRouter(...guards).router) + .use('/template', new TemplateRouter(configService, ...guards).router) .use('/settings', new SettingsRouter(...guards).router) - .use('/websocket', new WebsocketRouter(...guards).router) - .use('/rabbitmq', new RabbitmqRouter(...guards).router) - .use('/sqs', new SqsRouter(...guards).router) - .use('/typebot', new TypebotRouter(...guards).router) .use('/proxy', new ProxyRouter(...guards).router) - .use('/chamaai', new ChamaaiRouter(...guards).router) - .use('/label', new LabelRouter(...guards).router); + .use('/label', new LabelRouter(...guards).router) + .use('', new ChannelRouter(configService, ...guards).router) + .use('', new EventRouter(configService, ...guards).router) + .use('', new ChatbotRouter(...guards).router) + .use('', new StorageRouter(...guards).router); export { HttpStatus, router }; diff --git a/src/api/routes/instance.router.ts b/src/api/routes/instance.router.ts index d2cc6fb8..dd990c3b 100644 --- a/src/api/routes/instance.router.ts +++ b/src/api/routes/instance.router.ts @@ -1,81 +1,44 @@ +import { RouterBroker } from '@api/abstract/abstract.router'; +import { InstanceDto, SetPresenceDto } from '@api/dto/instance.dto'; +import { instanceController } from '@api/server.module'; +import { ConfigService } from '@config/env.config'; +import { instanceSchema, presenceOnlySchema } from '@validate/validate.schema'; import { RequestHandler, Router } from 'express'; -import { Auth, ConfigService, Database } from '../../config/env.config'; -import { Logger } from '../../config/logger.config'; -import { dbserver } from '../../libs/db.connect'; -import { instanceNameSchema, oldTokenSchema, presenceOnlySchema } from '../../validate/validate.schema'; -import { RouterBroker } from '../abstract/abstract.router'; -import { InstanceDto, SetPresenceDto } from '../dto/instance.dto'; -import { instanceController } from '../server.module'; -import { OldToken } from '../services/auth.service'; import { HttpStatus } from './index.router'; -const logger = new Logger('InstanceRouter'); - export class InstanceRouter extends RouterBroker { - constructor(readonly configService: ConfigService, ...guards: RequestHandler[]) { + constructor( + readonly configService: ConfigService, + ...guards: RequestHandler[] + ) { super(); - const auth = configService.get('AUTHENTICATION'); this.router .post('/create', ...guards, async (req, res) => { - logger.verbose('request received in createInstance'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - + console.log('create instance', req.body); const response = await this.dataValidate({ request: req, - schema: instanceNameSchema, + schema: instanceSchema, ClassRef: InstanceDto, execute: (instance) => instanceController.createInstance(instance), }); return res.status(HttpStatus.CREATED).json(response); }) - .put(this.routerPath('restart'), ...guards, async (req, res) => { - logger.verbose('request received in restartInstance'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); + .post(this.routerPath('restart'), ...guards, async (req, res) => { const response = await this.dataValidate({ request: req, - schema: instanceNameSchema, + schema: null, ClassRef: InstanceDto, execute: (instance) => instanceController.restartInstance(instance), }); return res.status(HttpStatus.OK).json(response); }) - .post(this.routerPath('registerMobileCode'), ...guards, async (req, res) => { - logger.verbose('request received in registerMobileCode'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - const response = await this.dataValidate({ - request: req, - schema: instanceNameSchema, - ClassRef: SetPresenceDto, - execute: (instance, data) => instanceController.registerMobileCode(instance, data), - }); - - return res.status(HttpStatus.OK).json(response); - }) .get(this.routerPath('connect'), ...guards, async (req, res) => { - logger.verbose('request received in connectInstance'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); const response = await this.dataValidate({ request: req, - schema: instanceNameSchema, + schema: null, ClassRef: InstanceDto, execute: (instance) => instanceController.connectToWhatsapp(instance), }); @@ -83,15 +46,9 @@ export class InstanceRouter extends RouterBroker { return res.status(HttpStatus.OK).json(response); }) .get(this.routerPath('connectionState'), ...guards, async (req, res) => { - logger.verbose('request received in connectionState'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); const response = await this.dataValidate({ request: req, - schema: instanceNameSchema, + schema: null, ClassRef: InstanceDto, execute: (instance) => instanceController.connectionState(instance), }); @@ -99,14 +56,8 @@ export class InstanceRouter extends RouterBroker { return res.status(HttpStatus.OK).json(response); }) .get(this.routerPath('fetchInstances', false), ...guards, async (req, res) => { - logger.verbose('request received in fetchInstances'); - logger.verbose('request body: '); - logger.verbose(req.body); - const key = req.get('apikey'); - logger.verbose('request query: '); - logger.verbose(req.query); const response = await this.dataValidate({ request: req, schema: null, @@ -117,12 +68,6 @@ export class InstanceRouter extends RouterBroker { return res.status(HttpStatus.OK).json(response); }) .post(this.routerPath('setPresence'), ...guards, async (req, res) => { - logger.verbose('request received in setPresence'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); const response = await this.dataValidate({ request: req, schema: presenceOnlySchema, @@ -133,15 +78,9 @@ export class InstanceRouter extends RouterBroker { return res.status(HttpStatus.CREATED).json(response); }) .delete(this.routerPath('logout'), ...guards, async (req, res) => { - logger.verbose('request received in logoutInstances'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); const response = await this.dataValidate({ request: req, - schema: instanceNameSchema, + schema: null, ClassRef: InstanceDto, execute: (instance) => instanceController.logout(instance), }); @@ -149,63 +88,16 @@ export class InstanceRouter extends RouterBroker { return res.status(HttpStatus.OK).json(response); }) .delete(this.routerPath('delete'), ...guards, async (req, res) => { - logger.verbose('request received in deleteInstances'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); const response = await this.dataValidate({ request: req, - schema: instanceNameSchema, + schema: null, ClassRef: InstanceDto, execute: (instance) => instanceController.deleteInstance(instance), }); return res.status(HttpStatus.OK).json(response); }); - - if (auth.TYPE === 'jwt') { - this.router.put('/refreshToken', async (req, res) => { - logger.verbose('request received in refreshToken'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - const response = await this.dataValidate({ - request: req, - schema: oldTokenSchema, - ClassRef: OldToken, - execute: (_, data) => instanceController.refreshToken(_, data), - }); - - return res.status(HttpStatus.CREATED).json(response); - }); - } - - this.router.delete('/deleteDatabase', async (req, res) => { - logger.verbose('request received in deleteDatabase'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - const db = this.configService.get('DATABASE'); - if (db.ENABLED) { - try { - await dbserver.dropDatabase(); - return res - .status(HttpStatus.CREATED) - .json({ status: 'SUCCESS', error: false, response: { message: 'database deleted' } }); - } catch (error) { - return res.status(HttpStatus.INTERNAL_SERVER_ERROR).json({ error: true, message: error.message }); - } - } - - return res.status(HttpStatus.INTERNAL_SERVER_ERROR).json({ error: true, message: 'Database is not enabled' }); - }); } - public readonly router = Router(); + public readonly router: Router = Router(); } diff --git a/src/api/routes/label.router.ts b/src/api/routes/label.router.ts index a6002bb9..bfb4a085 100644 --- a/src/api/routes/label.router.ts +++ b/src/api/routes/label.router.ts @@ -1,26 +1,16 @@ +import { RouterBroker } from '@api/abstract/abstract.router'; +import { HandleLabelDto, LabelDto } from '@api/dto/label.dto'; +import { labelController } from '@api/server.module'; +import { handleLabelSchema } from '@validate/validate.schema'; import { RequestHandler, Router } from 'express'; -import { Logger } from '../../config/logger.config'; -import { handleLabelSchema } from '../../validate/validate.schema'; -import { RouterBroker } from '../abstract/abstract.router'; -import { HandleLabelDto, LabelDto } from '../dto/label.dto'; -import { labelController } from '../server.module'; import { HttpStatus } from './index.router'; -const logger = new Logger('LabelRouter'); - export class LabelRouter extends RouterBroker { constructor(...guards: RequestHandler[]) { super(); this.router .get(this.routerPath('findLabels'), ...guards, async (req, res) => { - logger.verbose('request received in findLabels'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - const response = await this.dataValidate({ request: req, schema: null, @@ -30,14 +20,7 @@ export class LabelRouter extends RouterBroker { return res.status(HttpStatus.OK).json(response); }) - .put(this.routerPath('handleLabel'), ...guards, async (req, res) => { - logger.verbose('request received in handleLabel'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - + .post(this.routerPath('handleLabel'), ...guards, async (req, res) => { const response = await this.dataValidate({ request: req, schema: handleLabelSchema, @@ -49,5 +32,5 @@ export class LabelRouter extends RouterBroker { }); } - public readonly router = Router(); + public readonly router: Router = Router(); } diff --git a/src/api/routes/proxy.router.ts b/src/api/routes/proxy.router.ts index 284fe368..e04c587b 100644 --- a/src/api/routes/proxy.router.ts +++ b/src/api/routes/proxy.router.ts @@ -1,26 +1,17 @@ +import { RouterBroker } from '@api/abstract/abstract.router'; +import { InstanceDto } from '@api/dto/instance.dto'; +import { ProxyDto } from '@api/dto/proxy.dto'; +import { proxyController } from '@api/server.module'; +import { instanceSchema, proxySchema } from '@validate/validate.schema'; import { RequestHandler, Router } from 'express'; -import { Logger } from '../../config/logger.config'; -import { instanceNameSchema, proxySchema } from '../../validate/validate.schema'; -import { RouterBroker } from '../abstract/abstract.router'; -import { InstanceDto } from '../dto/instance.dto'; -import { ProxyDto } from '../dto/proxy.dto'; -import { proxyController } from '../server.module'; import { HttpStatus } from './index.router'; -const logger = new Logger('ProxyRouter'); - export class ProxyRouter extends RouterBroker { constructor(...guards: RequestHandler[]) { super(); this.router .post(this.routerPath('set'), ...guards, async (req, res) => { - logger.verbose('request received in setProxy'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); const response = await this.dataValidate({ request: req, schema: proxySchema, @@ -31,15 +22,9 @@ export class ProxyRouter extends RouterBroker { res.status(HttpStatus.CREATED).json(response); }) .get(this.routerPath('find'), ...guards, async (req, res) => { - logger.verbose('request received in findProxy'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); const response = await this.dataValidate({ request: req, - schema: instanceNameSchema, + schema: instanceSchema, ClassRef: InstanceDto, execute: (instance) => proxyController.findProxy(instance), }); @@ -48,5 +33,5 @@ export class ProxyRouter extends RouterBroker { }); } - public readonly router = Router(); + public readonly router: Router = Router(); } diff --git a/src/api/routes/sendMessage.router.ts b/src/api/routes/sendMessage.router.ts index 908a1a58..cd073dba 100644 --- a/src/api/routes/sendMessage.router.ts +++ b/src/api/routes/sendMessage.router.ts @@ -1,99 +1,47 @@ -import { RequestHandler, Router } from 'express'; - -import { Logger } from '../../config/logger.config'; -import { - audioMessageSchema, - buttonMessageSchema, - contactMessageSchema, - listMessageSchema, - locationMessageSchema, - mediaMessageSchema, - pollMessageSchema, - reactionMessageSchema, - statusMessageSchema, - stickerMessageSchema, - templateMessageSchema, - textMessageSchema, -} from '../../validate/validate.schema'; -import { RouterBroker } from '../abstract/abstract.router'; +import { RouterBroker } from '@api/abstract/abstract.router'; import { SendAudioDto, - SendButtonDto, + SendButtonsDto, SendContactDto, SendListDto, SendLocationDto, SendMediaDto, SendPollDto, + SendPtvDto, SendReactionDto, SendStatusDto, SendStickerDto, SendTemplateDto, SendTextDto, -} from '../dto/sendMessage.dto'; -import { sendMessageController } from '../server.module'; +} from '@api/dto/sendMessage.dto'; +import { sendMessageController } from '@api/server.module'; +import { + audioMessageSchema, + buttonsMessageSchema, + contactMessageSchema, + listMessageSchema, + locationMessageSchema, + mediaMessageSchema, + pollMessageSchema, + ptvMessageSchema, + reactionMessageSchema, + statusMessageSchema, + stickerMessageSchema, + templateMessageSchema, + textMessageSchema, +} from '@validate/validate.schema'; +import { RequestHandler, Router } from 'express'; +import multer from 'multer'; + import { HttpStatus } from './index.router'; -const logger = new Logger('MessageRouter'); +const upload = multer({ storage: multer.memoryStorage() }); export class MessageRouter extends RouterBroker { constructor(...guards: RequestHandler[]) { super(); this.router - .post(this.routerPath('sendText'), ...guards, async (req, res) => { - logger.verbose('request received in sendText'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - const response = await this.dataValidate({ - request: req, - schema: textMessageSchema, - ClassRef: SendTextDto, - execute: (instance, data) => sendMessageController.sendText(instance, data), - }); - - return res.status(HttpStatus.CREATED).json(response); - }) - .post(this.routerPath('sendMedia'), ...guards, async (req, res) => { - logger.verbose('request received in sendMedia'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - const response = await this.dataValidate({ - request: req, - schema: mediaMessageSchema, - ClassRef: SendMediaDto, - execute: (instance, data) => sendMessageController.sendMedia(instance, data), - }); - - return res.status(HttpStatus.CREATED).json(response); - }) - .post(this.routerPath('sendWhatsAppAudio'), ...guards, async (req, res) => { - logger.verbose('request received in sendWhatsAppAudio'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - const response = await this.dataValidate({ - request: req, - schema: audioMessageSchema, - ClassRef: SendMediaDto, - execute: (instance, data) => sendMessageController.sendWhatsAppAudio(instance, data), - }); - - return res.status(HttpStatus.CREATED).json(response); - }) .post(this.routerPath('sendTemplate'), ...guards, async (req, res) => { - logger.verbose('request received in sendTemplate'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); const response = await this.dataValidate({ request: req, schema: templateMessageSchema, @@ -103,29 +51,78 @@ export class MessageRouter extends RouterBroker { return res.status(HttpStatus.CREATED).json(response); }) - .post(this.routerPath('sendButtons'), ...guards, async (req, res) => { - logger.verbose('request received in sendButtons'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - const response = await this.dataValidate({ + .post(this.routerPath('sendText'), ...guards, async (req, res) => { + const response = await this.dataValidate({ request: req, - schema: buttonMessageSchema, - ClassRef: SendButtonDto, - execute: (instance, data) => sendMessageController.sendButtons(instance, data), + schema: textMessageSchema, + ClassRef: SendTextDto, + execute: (instance, data) => sendMessageController.sendText(instance, data), + }); + + return res.status(HttpStatus.CREATED).json(response); + }) + .post(this.routerPath('sendMedia'), ...guards, upload.single('file'), async (req, res) => { + const bodyData = req.body; + + const response = await this.dataValidate({ + request: req, + schema: mediaMessageSchema, + ClassRef: SendMediaDto, + execute: (instance) => sendMessageController.sendMedia(instance, bodyData, req.file as any), + }); + + return res.status(HttpStatus.CREATED).json(response); + }) + .post(this.routerPath('sendPtv'), ...guards, upload.single('file'), async (req, res) => { + const bodyData = req.body; + + const response = await this.dataValidate({ + request: req, + schema: ptvMessageSchema, + ClassRef: SendPtvDto, + execute: (instance) => sendMessageController.sendPtv(instance, bodyData, req.file as any), + }); + + return res.status(HttpStatus.CREATED).json(response); + }) + .post(this.routerPath('sendWhatsAppAudio'), ...guards, upload.single('file'), async (req, res) => { + const bodyData = req.body; + + const response = await this.dataValidate({ + request: req, + schema: audioMessageSchema, + ClassRef: SendMediaDto, + execute: (instance) => sendMessageController.sendWhatsAppAudio(instance, bodyData, req.file as any), + }); + + return res.status(HttpStatus.CREATED).json(response); + }) + // TODO: Revisar funcionamento do envio de Status + .post(this.routerPath('sendStatus'), ...guards, upload.single('file'), async (req, res) => { + const bodyData = req.body; + + const response = await this.dataValidate({ + request: req, + schema: statusMessageSchema, + ClassRef: SendStatusDto, + execute: (instance) => sendMessageController.sendStatus(instance, bodyData, req.file as any), + }); + + return res.status(HttpStatus.CREATED).json(response); + }) + .post(this.routerPath('sendSticker'), ...guards, upload.single('file'), async (req, res) => { + const bodyData = req.body; + + const response = await this.dataValidate({ + request: req, + schema: stickerMessageSchema, + ClassRef: SendStickerDto, + execute: (instance) => sendMessageController.sendSticker(instance, bodyData, req.file as any), }); return res.status(HttpStatus.CREATED).json(response); }) .post(this.routerPath('sendLocation'), ...guards, async (req, res) => { - logger.verbose('request received in sendLocation'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); const response = await this.dataValidate({ request: req, schema: locationMessageSchema, @@ -135,29 +132,7 @@ export class MessageRouter extends RouterBroker { return res.status(HttpStatus.CREATED).json(response); }) - .post(this.routerPath('sendList'), ...guards, async (req, res) => { - logger.verbose('request received in sendList'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - const response = await this.dataValidate({ - request: req, - schema: listMessageSchema, - ClassRef: SendListDto, - execute: (instance, data) => sendMessageController.sendList(instance, data), - }); - - return res.status(HttpStatus.CREATED).json(response); - }) .post(this.routerPath('sendContact'), ...guards, async (req, res) => { - logger.verbose('request received in sendContact'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); const response = await this.dataValidate({ request: req, schema: contactMessageSchema, @@ -168,12 +143,6 @@ export class MessageRouter extends RouterBroker { return res.status(HttpStatus.CREATED).json(response); }) .post(this.routerPath('sendReaction'), ...guards, async (req, res) => { - logger.verbose('request received in sendReaction'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); const response = await this.dataValidate({ request: req, schema: reactionMessageSchema, @@ -184,12 +153,6 @@ export class MessageRouter extends RouterBroker { return res.status(HttpStatus.CREATED).json(response); }) .post(this.routerPath('sendPoll'), ...guards, async (req, res) => { - logger.verbose('request received in sendPoll'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); const response = await this.dataValidate({ request: req, schema: pollMessageSchema, @@ -199,39 +162,27 @@ export class MessageRouter extends RouterBroker { return res.status(HttpStatus.CREATED).json(response); }) - .post(this.routerPath('sendStatus'), ...guards, async (req, res) => { - logger.verbose('request received in sendStatus'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - const response = await this.dataValidate({ + .post(this.routerPath('sendList'), ...guards, async (req, res) => { + const response = await this.dataValidate({ request: req, - schema: statusMessageSchema, - ClassRef: SendStatusDto, - execute: (instance, data) => sendMessageController.sendStatus(instance, data), + schema: listMessageSchema, + ClassRef: SendListDto, + execute: (instance, data) => sendMessageController.sendList(instance, data), }); return res.status(HttpStatus.CREATED).json(response); }) - .post(this.routerPath('sendSticker'), ...guards, async (req, res) => { - logger.verbose('request received in sendSticker'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - const response = await this.dataValidate({ + .post(this.routerPath('sendButtons'), ...guards, async (req, res) => { + const response = await this.dataValidate({ request: req, - schema: stickerMessageSchema, - ClassRef: SendStickerDto, - execute: (instance, data) => sendMessageController.sendSticker(instance, data), + schema: buttonsMessageSchema, + ClassRef: SendButtonsDto, + execute: (instance, data) => sendMessageController.sendButtons(instance, data), }); return res.status(HttpStatus.CREATED).json(response); }); } - public readonly router = Router(); + public readonly router: Router = Router(); } diff --git a/src/api/routes/settings.router.ts b/src/api/routes/settings.router.ts index c2d3bad9..214d5fd7 100644 --- a/src/api/routes/settings.router.ts +++ b/src/api/routes/settings.router.ts @@ -1,26 +1,17 @@ +import { RouterBroker } from '@api/abstract/abstract.router'; +import { InstanceDto } from '@api/dto/instance.dto'; +import { SettingsDto } from '@api/dto/settings.dto'; +import { settingsController } from '@api/server.module'; +import { settingsSchema } from '@validate/validate.schema'; import { RequestHandler, Router } from 'express'; -import { Logger } from '../../config/logger.config'; -import { instanceNameSchema, settingsSchema } from '../../validate/validate.schema'; -import { RouterBroker } from '../abstract/abstract.router'; -import { InstanceDto } from '../dto/instance.dto'; -import { SettingsDto } from '../dto/settings.dto'; -import { settingsController } from '../server.module'; import { HttpStatus } from './index.router'; -const logger = new Logger('SettingsRouter'); - export class SettingsRouter extends RouterBroker { constructor(...guards: RequestHandler[]) { super(); this.router .post(this.routerPath('set'), ...guards, async (req, res) => { - logger.verbose('request received in setSettings'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); const response = await this.dataValidate({ request: req, schema: settingsSchema, @@ -31,15 +22,9 @@ export class SettingsRouter extends RouterBroker { res.status(HttpStatus.CREATED).json(response); }) .get(this.routerPath('find'), ...guards, async (req, res) => { - logger.verbose('request received in findSettings'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); const response = await this.dataValidate({ request: req, - schema: instanceNameSchema, + schema: null, ClassRef: InstanceDto, execute: (instance) => settingsController.findSettings(instance), }); @@ -48,5 +33,5 @@ export class SettingsRouter extends RouterBroker { }); } - public readonly router = Router(); + public readonly router: Router = Router(); } diff --git a/src/api/routes/template.router.ts b/src/api/routes/template.router.ts new file mode 100644 index 00000000..b77b7d83 --- /dev/null +++ b/src/api/routes/template.router.ts @@ -0,0 +1,41 @@ +import { RouterBroker } from '@api/abstract/abstract.router'; +import { InstanceDto } from '@api/dto/instance.dto'; +import { TemplateDto } from '@api/dto/template.dto'; +import { templateController } from '@api/server.module'; +import { ConfigService } from '@config/env.config'; +import { instanceSchema, templateSchema } from '@validate/validate.schema'; +import { RequestHandler, Router } from 'express'; + +import { HttpStatus } from './index.router'; + +export class TemplateRouter extends RouterBroker { + constructor( + readonly configService: ConfigService, + ...guards: RequestHandler[] + ) { + super(); + this.router + .post(this.routerPath('create'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: templateSchema, + ClassRef: TemplateDto, + execute: (instance, data) => templateController.createTemplate(instance, data), + }); + + res.status(HttpStatus.CREATED).json(response); + }) + .get(this.routerPath('find'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: instanceSchema, + ClassRef: InstanceDto, + execute: (instance) => templateController.findTemplate(instance), + }); + + res.status(HttpStatus.OK).json(response); + }); + } + + public readonly router: Router = Router(); +} diff --git a/src/api/routes/view.router.ts b/src/api/routes/view.router.ts index ecfe64c1..64b4b5ea 100644 --- a/src/api/routes/view.router.ts +++ b/src/api/routes/view.router.ts @@ -1,34 +1,21 @@ -import { Router } from 'express'; -import fs from 'fs'; -import mime from 'mime-types'; - -import { RouterBroker } from '../abstract/abstract.router'; +import { RouterBroker } from '@api/abstract/abstract.router'; +import express, { Router } from 'express'; +import path from 'path'; export class ViewsRouter extends RouterBroker { + public readonly router: Router; + constructor() { super(); + this.router = Router(); - const basePath = 'evolution-manager/dist'; + const basePath = path.join(process.cwd(), 'manager', 'dist'); + const indexPath = path.join(basePath, 'index.html'); - const indexPath = require.resolve(`${basePath}/index.html`); + this.router.use(express.static(basePath)); - this.router.get('/*', (req, res) => { - try { - const pathname = req.url.split('?')[0]; - - // verify if url is a file in dist folder - if (pathname === '/') throw {}; - const filePath = require.resolve(`${basePath}${pathname}`); - - const contentType = mime.lookup(filePath) || 'text/plain'; - res.set('Content-Type', contentType); - res.end(fs.readFileSync(filePath)); - } catch { - res.set('Content-Type', 'text/html'); - res.send(fs.readFileSync(indexPath)); - } + this.router.get('*', (req, res) => { + res.sendFile(indexPath); }); } - - public readonly router = Router(); } diff --git a/src/api/routes/webhook.router.ts b/src/api/routes/webhook.router.ts deleted file mode 100644 index 1e4ddcac..00000000 --- a/src/api/routes/webhook.router.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { RequestHandler, Router } from 'express'; - -import { ConfigService, WaBusiness } from '../../config/env.config'; -import { Logger } from '../../config/logger.config'; -import { instanceNameSchema, webhookSchema } from '../../validate/validate.schema'; -import { RouterBroker } from '../abstract/abstract.router'; -import { InstanceDto } from '../dto/instance.dto'; -import { WebhookDto } from '../dto/webhook.dto'; -import { webhookController } from '../server.module'; -import { HttpStatus } from './index.router'; - -const logger = new Logger('WebhookRouter'); - -export class WebhookRouter extends RouterBroker { - constructor(readonly configService: ConfigService, ...guards: RequestHandler[]) { - super(); - this.router - .post(this.routerPath('set'), ...guards, async (req, res) => { - logger.verbose('request received in setWebhook'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - const response = await this.dataValidate({ - request: req, - schema: webhookSchema, - ClassRef: WebhookDto, - execute: (instance, data) => webhookController.createWebhook(instance, data), - }); - - res.status(HttpStatus.CREATED).json(response); - }) - .get(this.routerPath('find'), ...guards, async (req, res) => { - logger.verbose('request received in findWebhook'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - const response = await this.dataValidate({ - request: req, - schema: instanceNameSchema, - ClassRef: InstanceDto, - execute: (instance) => webhookController.findWebhook(instance), - }); - - res.status(HttpStatus.OK).json(response); - }) - .post(this.routerPath('whatsapp'), async (req, res) => { - logger.verbose('request received in webhook'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - const response = await this.dataValidate({ - request: req, - schema: instanceNameSchema, - ClassRef: InstanceDto, - execute: (instance, data) => webhookController.receiveWebhook(instance, data), - }); - - res.status(HttpStatus.OK).json(response); - }) - .get(this.routerPath('whatsapp'), async (req, res) => { - logger.verbose('request received in webhook'); - logger.verbose('request query: '); - logger.verbose(req.query); - if (req.query['hub.verify_token'] === this.configService.get('WA_BUSINESS').TOKEN_WEBHOOK) - res.send(req.query['hub.challenge']); - else res.send('Error, wrong validation token'); - logger.verbose('Error, wrong validation token'); - }); - } - - public readonly router = Router(); -} diff --git a/src/api/server.module.ts b/src/api/server.module.ts index 97df81a3..49fc5695 100644 --- a/src/api/server.module.ts +++ b/src/api/server.module.ts @@ -1,8 +1,9 @@ -import { CacheEngine } from '../cache/cacheengine'; -import { configService } from '../config/env.config'; -import { eventEmitter } from '../config/event.config'; -import { Logger } from '../config/logger.config'; -import { dbserver } from '../libs/db.connect'; +import { CacheEngine } from '@cache/cacheengine'; +import { Chatwoot, configService, ProviderSession } from '@config/env.config'; +import { eventEmitter } from '@config/event.config'; +import { Logger } from '@config/logger.config'; + +import { CallController } from './controllers/call.controller'; import { ChatController } from './controllers/chat.controller'; import { GroupController } from './controllers/group.controller'; import { InstanceController } from './controllers/instance.controller'; @@ -10,142 +11,73 @@ import { LabelController } from './controllers/label.controller'; import { ProxyController } from './controllers/proxy.controller'; import { SendMessageController } from './controllers/sendMessage.controller'; import { SettingsController } from './controllers/settings.controller'; -import { WebhookController } from './controllers/webhook.controller'; -import { ChamaaiController } from './integrations/chamaai/controllers/chamaai.controller'; -import { ChamaaiRepository } from './integrations/chamaai/repository/chamaai.repository'; -import { ChamaaiService } from './integrations/chamaai/services/chamaai.service'; -import { ChatwootController } from './integrations/chatwoot/controllers/chatwoot.controller'; -import { ChatwootRepository } from './integrations/chatwoot/repository/chatwoot.repository'; -import { ChatwootService } from './integrations/chatwoot/services/chatwoot.service'; -import { RabbitmqController } from './integrations/rabbitmq/controllers/rabbitmq.controller'; -import { RabbitmqRepository } from './integrations/rabbitmq/repository/rabbitmq.repository'; -import { RabbitmqService } from './integrations/rabbitmq/services/rabbitmq.service'; -import { SqsController } from './integrations/sqs/controllers/sqs.controller'; -import { SqsRepository } from './integrations/sqs/repository/sqs.repository'; -import { SqsService } from './integrations/sqs/services/sqs.service'; -import { TypebotController } from './integrations/typebot/controllers/typebot.controller'; -import { TypebotRepository } from './integrations/typebot/repository/typebot.repository'; -import { TypebotService } from './integrations/typebot/services/typebot.service'; -import { WebsocketController } from './integrations/websocket/controllers/websocket.controller'; -import { WebsocketRepository } from './integrations/websocket/repository/websocket.repository'; -import { WebsocketService } from './integrations/websocket/services/websocket.service'; -import { - AuthModel, - ChamaaiModel, - ChatModel, - ChatwootModel, - ContactModel, - IntegrationModel, - MessageModel, - MessageUpModel, - ProxyModel, - RabbitmqModel, - SettingsModel, - SqsModel, - TypebotModel, - WebhookModel, - WebsocketModel, -} from './models'; -import { LabelModel } from './models/label.model'; -import { AuthRepository } from './repository/auth.repository'; -import { ChatRepository } from './repository/chat.repository'; -import { ContactRepository } from './repository/contact.repository'; -import { IntegrationRepository } from './repository/integration.repository'; -import { LabelRepository } from './repository/label.repository'; -import { MessageRepository } from './repository/message.repository'; -import { MessageUpRepository } from './repository/messageUp.repository'; -import { ProxyRepository } from './repository/proxy.repository'; -import { RepositoryBroker } from './repository/repository.manager'; -import { SettingsRepository } from './repository/settings.repository'; -import { WebhookRepository } from './repository/webhook.repository'; -import { AuthService } from './services/auth.service'; +import { TemplateController } from './controllers/template.controller'; +import { ChannelController } from './integrations/channel/channel.controller'; +import { EvolutionController } from './integrations/channel/evolution/evolution.controller'; +import { MetaController } from './integrations/channel/meta/meta.controller'; +import { BaileysController } from './integrations/channel/whatsapp/baileys.controller'; +import { ChatbotController } from './integrations/chatbot/chatbot.controller'; +import { ChatwootController } from './integrations/chatbot/chatwoot/controllers/chatwoot.controller'; +import { ChatwootService } from './integrations/chatbot/chatwoot/services/chatwoot.service'; +import { DifyController } from './integrations/chatbot/dify/controllers/dify.controller'; +import { DifyService } from './integrations/chatbot/dify/services/dify.service'; +import { EvolutionBotController } from './integrations/chatbot/evolutionBot/controllers/evolutionBot.controller'; +import { EvolutionBotService } from './integrations/chatbot/evolutionBot/services/evolutionBot.service'; +import { FlowiseController } from './integrations/chatbot/flowise/controllers/flowise.controller'; +import { FlowiseService } from './integrations/chatbot/flowise/services/flowise.service'; +import { OpenaiController } from './integrations/chatbot/openai/controllers/openai.controller'; +import { OpenaiService } from './integrations/chatbot/openai/services/openai.service'; +import { TypebotController } from './integrations/chatbot/typebot/controllers/typebot.controller'; +import { TypebotService } from './integrations/chatbot/typebot/services/typebot.service'; +import { EventManager } from './integrations/event/event.manager'; +import { S3Controller } from './integrations/storage/s3/controllers/s3.controller'; +import { S3Service } from './integrations/storage/s3/services/s3.service'; +import { ProviderFiles } from './provider/sessions'; +import { PrismaRepository } from './repository/repository.service'; import { CacheService } from './services/cache.service'; -import { IntegrationService } from './services/integration.service'; import { WAMonitoringService } from './services/monitor.service'; import { ProxyService } from './services/proxy.service'; import { SettingsService } from './services/settings.service'; -import { WebhookService } from './services/webhook.service'; +import { TemplateService } from './services/template.service'; const logger = new Logger('WA MODULE'); -const messageRepository = new MessageRepository(MessageModel, configService); -const chatRepository = new ChatRepository(ChatModel, configService); -const contactRepository = new ContactRepository(ContactModel, configService); -const messageUpdateRepository = new MessageUpRepository(MessageUpModel, configService); -const typebotRepository = new TypebotRepository(TypebotModel, configService); -const webhookRepository = new WebhookRepository(WebhookModel, configService); -const websocketRepository = new WebsocketRepository(WebsocketModel, configService); -const proxyRepository = new ProxyRepository(ProxyModel, configService); -const chamaaiRepository = new ChamaaiRepository(ChamaaiModel, configService); -const rabbitmqRepository = new RabbitmqRepository(RabbitmqModel, configService); -const sqsRepository = new SqsRepository(SqsModel, configService); -const integrationRepository = new IntegrationRepository(IntegrationModel, configService); -const chatwootRepository = new ChatwootRepository(ChatwootModel, configService); -const settingsRepository = new SettingsRepository(SettingsModel, configService); -const authRepository = new AuthRepository(AuthModel, IntegrationModel, configService); -const labelRepository = new LabelRepository(LabelModel, configService); - -export const repository = new RepositoryBroker( - messageRepository, - chatRepository, - contactRepository, - messageUpdateRepository, - webhookRepository, - chatwootRepository, - settingsRepository, - websocketRepository, - rabbitmqRepository, - sqsRepository, - typebotRepository, - proxyRepository, - chamaaiRepository, - integrationRepository, - authRepository, - labelRepository, - configService, - dbserver?.getClient(), -); +let chatwootCache: CacheService = null; +if (configService.get('CHATWOOT').ENABLED) { + chatwootCache = new CacheService(new CacheEngine(configService, ChatwootService.name).getEngine()); +} export const cache = new CacheService(new CacheEngine(configService, 'instance').getEngine()); -const chatwootCache = new CacheService(new CacheEngine(configService, ChatwootService.name).getEngine()); -const messagesLostCache = new CacheService(new CacheEngine(configService, 'baileys').getEngine()); +const baileysCache = new CacheService(new CacheEngine(configService, 'baileys').getEngine()); + +let providerFiles: ProviderFiles = null; +if (configService.get('PROVIDER').ENABLED) { + providerFiles = new ProviderFiles(configService); +} + +export const prismaRepository = new PrismaRepository(configService); export const waMonitor = new WAMonitoringService( eventEmitter, configService, - repository, + prismaRepository, + providerFiles, cache, chatwootCache, - messagesLostCache, + baileysCache, ); -const authService = new AuthService(configService, waMonitor, repository); +const s3Service = new S3Service(prismaRepository); +export const s3Controller = new S3Controller(s3Service); -const typebotService = new TypebotService(waMonitor, configService, eventEmitter); -export const typebotController = new TypebotController(typebotService); - -const webhookService = new WebhookService(waMonitor); -export const webhookController = new WebhookController(webhookService, waMonitor); - -const websocketService = new WebsocketService(waMonitor); -export const websocketController = new WebsocketController(websocketService); +const templateService = new TemplateService(waMonitor, prismaRepository, configService); +export const templateController = new TemplateController(templateService); const proxyService = new ProxyService(waMonitor); export const proxyController = new ProxyController(proxyService, waMonitor); -const chamaaiService = new ChamaaiService(waMonitor, configService); -export const chamaaiController = new ChamaaiController(chamaaiService); - -const rabbitmqService = new RabbitmqService(waMonitor); -export const rabbitmqController = new RabbitmqController(rabbitmqService); - -const sqsService = new SqsService(waMonitor); -export const sqsController = new SqsController(sqsService); - -const integrationService = new IntegrationService(waMonitor); - -const chatwootService = new ChatwootService(waMonitor, configService, repository, chatwootCache); -export const chatwootController = new ChatwootController(chatwootService, configService, repository); +const chatwootService = new ChatwootService(waMonitor, configService, prismaRepository, chatwootCache); +export const chatwootController = new ChatwootController(chatwootService, configService, prismaRepository); const settingsService = new SettingsService(waMonitor); export const settingsController = new SettingsController(settingsService); @@ -153,25 +85,44 @@ export const settingsController = new SettingsController(settingsService); export const instanceController = new InstanceController( waMonitor, configService, - repository, + prismaRepository, eventEmitter, - authService, - webhookService, chatwootService, settingsService, - websocketService, - rabbitmqService, - sqsService, - typebotService, - integrationService, proxyController, cache, chatwootCache, - messagesLostCache, + baileysCache, + providerFiles, ); export const sendMessageController = new SendMessageController(waMonitor); +export const callController = new CallController(waMonitor); export const chatController = new ChatController(waMonitor); export const groupController = new GroupController(waMonitor); export const labelController = new LabelController(waMonitor); +export const eventManager = new EventManager(prismaRepository, waMonitor); +export const chatbotController = new ChatbotController(prismaRepository, waMonitor); +export const channelController = new ChannelController(prismaRepository, waMonitor); + +// channels +export const evolutionController = new EvolutionController(prismaRepository, waMonitor); +export const metaController = new MetaController(prismaRepository, waMonitor); +export const baileysController = new BaileysController(waMonitor); +// chatbots +const typebotService = new TypebotService(waMonitor, configService, prismaRepository); +export const typebotController = new TypebotController(typebotService, prismaRepository, waMonitor); + +const openaiService = new OpenaiService(waMonitor, configService, prismaRepository); +export const openaiController = new OpenaiController(openaiService, prismaRepository, waMonitor); + +const difyService = new DifyService(waMonitor, configService, prismaRepository); +export const difyController = new DifyController(difyService, prismaRepository, waMonitor); + +const evolutionBotService = new EvolutionBotService(waMonitor, configService, prismaRepository); +export const evolutionBotController = new EvolutionBotController(evolutionBotService, prismaRepository, waMonitor); + +const flowiseService = new FlowiseService(waMonitor, configService, prismaRepository); +export const flowiseController = new FlowiseController(flowiseService, prismaRepository, waMonitor); + logger.info('Module - ON'); diff --git a/src/api/services/auth.service.ts b/src/api/services/auth.service.ts index 45a43551..3a7825f8 100644 --- a/src/api/services/auth.service.ts +++ b/src/api/services/auth.service.ts @@ -1,180 +1,22 @@ -import axios from 'axios'; -import { isJWT } from 'class-validator'; -import { sign, verify } from 'jsonwebtoken'; -import { v4 } from 'uuid'; - -import { name as apiName } from '../../../package.json'; -import { Auth, ConfigService, Webhook } from '../../config/env.config'; -import { Logger } from '../../config/logger.config'; -import { BadRequestException } from '../../exceptions'; -import { InstanceDto } from '../dto/instance.dto'; -import { RepositoryBroker } from '../repository/repository.manager'; -import { WAMonitoringService } from './monitor.service'; - -export type JwtPayload = { - instanceName: string; - apiName: string; - jwt?: string; - apikey?: string; - tokenId: string; -}; - -export class OldToken { - oldToken: string; -} +import { PrismaRepository } from '@api/repository/repository.service'; +import { BadRequestException } from '@exceptions'; export class AuthService { - constructor( - private readonly configService: ConfigService, - private readonly waMonitor: WAMonitoringService, - private readonly repository: RepositoryBroker, - ) {} - - private readonly logger = new Logger(AuthService.name); - - private async jwt(instance: InstanceDto) { - const jwtOpts = this.configService.get('AUTHENTICATION').JWT; - const token = sign( - { - instanceName: instance.instanceName, - apiName, - tokenId: v4(), - }, - jwtOpts.SECRET, - { expiresIn: jwtOpts.EXPIRIN_IN, encoding: 'utf8', subject: 'g-t' }, - ); - - this.logger.verbose('JWT token created: ' + token); - - const auth = await this.repository.auth.create( - { jwt: token, instanceId: instance.instanceId }, - instance.instanceName, - ); - - this.logger.verbose('JWT token saved in database'); - - if (auth['error']) { - this.logger.error({ - localError: AuthService.name + '.jwt', - error: auth['error'], - }); - throw new BadRequestException('Authentication error', auth['error']?.toString()); - } - - return { jwt: token }; - } - - private async apikey(instance: InstanceDto, token?: string) { - const apikey = token ? token : v4().toUpperCase(); - - this.logger.verbose(token ? 'APIKEY defined: ' + apikey : 'APIKEY created: ' + apikey); - - const auth = await this.repository.auth.create({ apikey, instanceId: instance.instanceId }, instance.instanceName); - - this.logger.verbose('APIKEY saved in database'); - - if (auth['error']) { - this.logger.error({ - localError: AuthService.name + '.apikey', - error: auth['error'], - }); - throw new BadRequestException('Authentication error', auth['error']?.toString()); - } - - return { apikey }; - } + constructor(private readonly prismaRepository: PrismaRepository) {} public async checkDuplicateToken(token: string) { - const instances = await this.waMonitor.instanceInfo(); + if (!token) { + return true; + } - this.logger.verbose('checking duplicate token'); + const instances = await this.prismaRepository.instance.findMany({ + where: { token }, + }); - const instance = instances.find((instance) => instance.instance.apikey === token); - - if (instance) { + if (instances.length > 0) { throw new BadRequestException('Token already exists'); } - this.logger.verbose('available token'); - return true; } - - public async generateHash(instance: InstanceDto, token?: string) { - const options = this.configService.get('AUTHENTICATION'); - - this.logger.verbose('generating hash ' + options.TYPE + ' to instance: ' + instance.instanceName); - - return (await this[options.TYPE](instance, token)) as { jwt: string } | { apikey: string }; - } - - public async refreshToken({ oldToken }: OldToken) { - this.logger.verbose('refreshing token'); - - if (!isJWT(oldToken)) { - throw new BadRequestException('Invalid "oldToken"'); - } - - try { - const jwtOpts = this.configService.get('AUTHENTICATION').JWT; - - this.logger.verbose('checking oldToken'); - - const decode = verify(oldToken, jwtOpts.SECRET, { - ignoreExpiration: true, - }) as Pick; - - this.logger.verbose('checking token in database'); - - const tokenStore = await this.repository.auth.find(decode.instanceName); - - const decodeTokenStore = verify(tokenStore.jwt, jwtOpts.SECRET, { - ignoreExpiration: true, - }) as Pick; - - this.logger.verbose('checking tokenId'); - - if (decode.tokenId !== decodeTokenStore.tokenId) { - throw new BadRequestException('Invalid "oldToken"'); - } - - this.logger.verbose('generating new token'); - - const token = { - jwt: (await this.jwt({ instanceName: decode.instanceName })).jwt, - instanceName: decode.instanceName, - }; - - try { - this.logger.verbose('checking webhook'); - const webhook = await this.repository.webhook.find(decode.instanceName); - if (webhook?.enabled && this.configService.get('WEBHOOK').EVENTS.NEW_JWT_TOKEN) { - this.logger.verbose('sending webhook'); - - const httpService = axios.create({ baseURL: webhook.url }); - await httpService.post( - '', - { - event: 'new.jwt', - instance: decode.instanceName, - data: token, - }, - { params: { owner: this.waMonitor.waInstances[decode.instanceName].wuid } }, - ); - } - } catch (error) { - this.logger.error(error); - } - - this.logger.verbose('token refreshed'); - - return token; - } catch (error) { - this.logger.error({ - localError: AuthService.name + '.refreshToken', - error, - }); - throw new BadRequestException('Invalid "oldToken"'); - } - } } diff --git a/src/api/services/cache.service.ts b/src/api/services/cache.service.ts index caf3dbfa..e2f96d4b 100644 --- a/src/api/services/cache.service.ts +++ b/src/api/services/cache.service.ts @@ -1,10 +1,9 @@ -import { BufferJSON } from '@whiskeysockets/baileys'; - -import { Logger } from '../../config/logger.config'; -import { ICache } from '../abstract/abstract.cache'; +import { ICache } from '@api/abstract/abstract.cache'; +import { Logger } from '@config/logger.config'; +import { BufferJSON } from 'baileys'; export class CacheService { - private readonly logger = new Logger(CacheService.name); + private readonly logger = new Logger('CacheService'); constructor(private readonly cache: ICache) { if (cache) { @@ -18,11 +17,13 @@ export class CacheService { if (!this.cache) { return; } - this.logger.verbose(`cacheservice getting key: ${key}`); return this.cache.get(key); } public async hGet(key: string, field: string) { + if (!this.cache) { + return null; + } try { const data = await this.cache.hGet(key, field); @@ -37,15 +38,17 @@ export class CacheService { } } - async set(key: string, value: any) { + async set(key: string, value: any, ttl?: number) { if (!this.cache) { return; } - this.logger.verbose(`cacheservice setting key: ${key}`); - this.cache.set(key, value); + this.cache.set(key, value, ttl); } public async hSet(key: string, field: string, value: any) { + if (!this.cache) { + return; + } try { const json = JSON.stringify(value, BufferJSON.replacer); @@ -59,7 +62,6 @@ export class CacheService { if (!this.cache) { return; } - this.logger.verbose(`cacheservice has key: ${key}`); return this.cache.has(key); } @@ -67,11 +69,13 @@ export class CacheService { if (!this.cache) { return; } - this.logger.verbose(`cacheservice deleting key: ${key}`); return this.cache.delete(key); } async hDelete(key: string, field: string) { + if (!this.cache) { + return false; + } try { await this.cache.hDelete(key, field); return true; @@ -85,7 +89,6 @@ export class CacheService { if (!this.cache) { return; } - this.logger.verbose(`cacheservice deleting all keys`); return this.cache.deleteAll(appendCriteria); } @@ -93,7 +96,6 @@ export class CacheService { if (!this.cache) { return; } - this.logger.verbose(`cacheservice getting all keys`); return this.cache.keys(appendCriteria); } } diff --git a/src/api/services/channel.service.ts b/src/api/services/channel.service.ts index ac4eae90..0f30f0c9 100644 --- a/src/api/services/channel.service.ts +++ b/src/api/services/channel.service.ts @@ -1,94 +1,67 @@ -import { WASocket } from '@whiskeysockets/baileys'; -import axios from 'axios'; -import { execSync } from 'child_process'; -import { isURL } from 'class-validator'; +import { InstanceDto } from '@api/dto/instance.dto'; +import { ProxyDto } from '@api/dto/proxy.dto'; +import { SettingsDto } from '@api/dto/settings.dto'; +import { ChatwootDto } from '@api/integrations/chatbot/chatwoot/dto/chatwoot.dto'; +import { ChatwootService } from '@api/integrations/chatbot/chatwoot/services/chatwoot.service'; +import { DifyService } from '@api/integrations/chatbot/dify/services/dify.service'; +import { OpenaiService } from '@api/integrations/chatbot/openai/services/openai.service'; +import { TypebotService } from '@api/integrations/chatbot/typebot/services/typebot.service'; +import { PrismaRepository, Query } from '@api/repository/repository.service'; +import { eventManager, waMonitor } from '@api/server.module'; +import { Events, wa } from '@api/types/wa.types'; +import { Auth, Chatwoot, ConfigService, HttpServer } from '@config/env.config'; +import { Logger } from '@config/logger.config'; +import { NotFoundException } from '@exceptions'; +import { Contact, Message, Prisma } from '@prisma/client'; +import { createJid } from '@utils/createJid'; +import { WASocket } from 'baileys'; +import { isArray } from 'class-validator'; import EventEmitter2 from 'eventemitter2'; -import { join } from 'path'; import { v4 } from 'uuid'; -import { - Auth, - CleanStoreConf, - ConfigService, - Database, - HttpServer, - Log, - Rabbitmq, - Sqs, - Webhook, - Websocket, -} from '../../config/env.config'; -import { Logger } from '../../config/logger.config'; -import { ROOT_DIR } from '../../config/path.config'; -import { NotFoundException } from '../../exceptions'; -import { ChamaaiService } from '../integrations/chamaai/services/chamaai.service'; -import { ChatwootRaw } from '../integrations/chatwoot/models/chatwoot.model'; -import { ChatwootService } from '../integrations/chatwoot/services/chatwoot.service'; -import { getAMQP, removeQueues } from '../integrations/rabbitmq/libs/amqp.server'; -import { getSQS, removeQueues as removeQueuesSQS } from '../integrations/sqs/libs/sqs.server'; -import { TypebotService } from '../integrations/typebot/services/typebot.service'; -import { getIO } from '../integrations/websocket/libs/socket.server'; -import { WebsocketRaw } from '../integrations/websocket/models/websocket.model'; -import { ChamaaiRaw, IntegrationRaw, ProxyRaw, RabbitmqRaw, SettingsRaw, SqsRaw, TypebotRaw } from '../models'; -import { WebhookRaw } from '../models/webhook.model'; -import { ContactQuery } from '../repository/contact.repository'; -import { MessageQuery } from '../repository/message.repository'; -import { MessageUpQuery } from '../repository/messageUp.repository'; -import { RepositoryBroker } from '../repository/repository.manager'; -import { waMonitor } from '../server.module'; -import { Events, wa } from '../types/wa.types'; import { CacheService } from './cache.service'; export class ChannelStartupService { constructor( public readonly configService: ConfigService, public readonly eventEmitter: EventEmitter2, - public readonly repository: RepositoryBroker, + public readonly prismaRepository: PrismaRepository, public readonly chatwootCache: CacheService, - ) { - this.logger.verbose('ChannelStartupService initialized'); - } + ) {} - public readonly logger = new Logger(ChannelStartupService.name); + public readonly logger = new Logger('ChannelStartupService'); public client: WASocket; public readonly instance: wa.Instance = {}; - public readonly localWebhook: wa.LocalWebHook = {}; public readonly localChatwoot: wa.LocalChatwoot = {}; - public readonly localWebsocket: wa.LocalWebsocket = {}; - public readonly localRabbitmq: wa.LocalRabbitmq = {}; - public readonly localSqs: wa.LocalSqs = {}; - public readonly localTypebot: wa.LocalTypebot = {}; public readonly localProxy: wa.LocalProxy = {}; - public readonly localChamaai: wa.LocalChamaai = {}; - public readonly localIntegration: wa.LocalIntegration = {}; public readonly localSettings: wa.LocalSettings = {}; - public readonly storePath = join(ROOT_DIR, 'store'); + public readonly localWebhook: wa.LocalWebHook = {}; - public chatwootService = new ChatwootService(waMonitor, this.configService, this.repository, this.chatwootCache); + public chatwootService = new ChatwootService( + waMonitor, + this.configService, + this.prismaRepository, + this.chatwootCache, + ); - public typebotService = new TypebotService(waMonitor, this.configService, this.eventEmitter); + public typebotService = new TypebotService(waMonitor, this.configService, this.prismaRepository); - public chamaaiService = new ChamaaiService(waMonitor, this.configService); + public openaiService = new OpenaiService(waMonitor, this.configService, this.prismaRepository); - public set instanceName(name: string) { - this.logger.setInstance(name); + public difyService = new DifyService(waMonitor, this.configService, this.prismaRepository); - this.logger.verbose(`Initializing instance '${name}'`); - if (!name) { - this.logger.verbose('Instance name not found, generating random name with uuid'); - this.instance.name = v4(); - return; - } - this.instance.name = name; - this.logger.verbose(`Instance '${this.instance.name}' initialized`); - this.logger.verbose('Sending instance status to webhook'); - this.sendDataWebhook(Events.STATUS_INSTANCE, { - instance: this.instance.name, - status: 'created', - }); + public setInstance(instance: InstanceDto) { + this.logger.setInstance(instance.instanceName); - if (this.localChatwoot.enabled) { + this.instance.name = instance.instanceName; + this.instance.id = instance.instanceId; + this.instance.integration = instance.integration; + this.instance.number = instance.number; + this.instance.token = instance.token; + this.instance.businessId = instance.businessId; + + if (this.configService.get('CHATWOOT').ENABLED && this.localChatwoot?.enabled) { this.chatwootService.eventWhatsapp( Events.STATUS_INSTANCE, { instanceName: this.instance.name }, @@ -100,1051 +73,385 @@ export class ChannelStartupService { } } + public set instanceName(name: string) { + this.logger.setInstance(name); + + if (!name) { + this.instance.name = v4(); + return; + } + this.instance.name = name; + } + public get instanceName() { - this.logger.verbose('Getting instance name'); return this.instance.name; } + public set instanceId(id: string) { + if (!id) { + this.instance.id = v4(); + return; + } + this.instance.id = id; + } + + public get instanceId() { + return this.instance.id; + } + + public set integration(integration: string) { + this.instance.integration = integration; + } + + public get integration() { + return this.instance.integration; + } + + public set number(number: string) { + this.instance.number = number; + } + + public get number() { + return this.instance.number; + } + + public set token(token: string) { + this.instance.token = token; + } + + public get token() { + return this.instance.token; + } + public get wuid() { - this.logger.verbose('Getting remoteJid of instance'); return this.instance.wuid; } - public async loadIntegration() { - this.logger.verbose('Loading webhook'); - const data = await this.repository.integration.find(this.instanceName); - this.localIntegration.integration = data?.integration; - this.logger.verbose(`Integration: ${this.localIntegration.integration}`); + public async loadWebhook() { + const data = await this.prismaRepository.webhook.findUnique({ + where: { + instanceId: this.instanceId, + }, + }); - this.localIntegration.number = data?.number; - this.logger.verbose(`Integration number: ${this.localIntegration.number}`); - - this.localIntegration.token = data?.token; - this.logger.verbose(`Integration token: ${this.localIntegration.token}`); - - this.logger.verbose('Integration loaded'); - } - - public async setIntegration(data: IntegrationRaw) { - this.logger.verbose('Setting integration'); - await this.repository.integration.create(data, this.instanceName); - this.logger.verbose(`Integration: ${data.integration}`); - this.logger.verbose(`Integration number: ${data.number}`); - this.logger.verbose(`Integration token: ${data.token}`); - Object.assign(this.localIntegration, data); - this.logger.verbose('Integration set'); - } - - public async findIntegration() { - this.logger.verbose('Finding integration'); - let data: any; - - data = await this.repository.integration.find(this.instanceName); - - if (!data) { - this.repository.integration.create({ integration: 'WHATSAPP-BAILEYS', number: '', token: '' }, this.instanceName); - data = { integration: 'WHATSAPP-BAILEYS', number: '', token: '' }; - } - - this.logger.verbose(`Integration: ${data.integration}`); - this.logger.verbose(`Integration number: ${data.number}`); - this.logger.verbose(`Integration token: ${data.token}`); - - return { - integration: data.integration, - number: data.number, - token: data.token, - }; + this.localWebhook.enabled = data?.enabled; + this.localWebhook.webhookBase64 = data?.webhookBase64; } public async loadSettings() { - this.logger.verbose('Loading settings'); - const data = await this.repository.settings.find(this.instanceName); - this.localSettings.reject_call = data?.reject_call; - this.logger.verbose(`Settings reject_call: ${this.localSettings.reject_call}`); + const data = await this.prismaRepository.setting.findUnique({ + where: { + instanceId: this.instanceId, + }, + }); - this.localSettings.msg_call = data?.msg_call; - this.logger.verbose(`Settings msg_call: ${this.localSettings.msg_call}`); - - this.localSettings.groups_ignore = data?.groups_ignore; - this.logger.verbose(`Settings groups_ignore: ${this.localSettings.groups_ignore}`); - - this.localSettings.always_online = data?.always_online; - this.logger.verbose(`Settings always_online: ${this.localSettings.always_online}`); - - this.localSettings.read_messages = data?.read_messages; - this.logger.verbose(`Settings read_messages: ${this.localSettings.read_messages}`); - - this.localSettings.read_status = data?.read_status; - this.logger.verbose(`Settings read_status: ${this.localSettings.read_status}`); - - this.localSettings.sync_full_history = data?.sync_full_history; - this.logger.verbose(`Settings sync_full_history: ${this.localSettings.sync_full_history}`); - - this.logger.verbose('Settings loaded'); + this.localSettings.rejectCall = data?.rejectCall; + this.localSettings.msgCall = data?.msgCall; + this.localSettings.groupsIgnore = data?.groupsIgnore; + this.localSettings.alwaysOnline = data?.alwaysOnline; + this.localSettings.readMessages = data?.readMessages; + this.localSettings.readStatus = data?.readStatus; + this.localSettings.syncFullHistory = data?.syncFullHistory; + this.localSettings.wavoipToken = data?.wavoipToken; } - public async setSettings(data: SettingsRaw) { - this.logger.verbose('Setting settings'); - await this.repository.settings.create(data, this.instanceName); - this.logger.verbose(`Settings reject_call: ${data.reject_call}`); - this.logger.verbose(`Settings msg_call: ${data.msg_call}`); - this.logger.verbose(`Settings groups_ignore: ${data.groups_ignore}`); - this.logger.verbose(`Settings always_online: ${data.always_online}`); - this.logger.verbose(`Settings read_messages: ${data.read_messages}`); - this.logger.verbose(`Settings read_status: ${data.read_status}`); - this.logger.verbose(`Settings sync_full_history: ${data.sync_full_history}`); - Object.assign(this.localSettings, data); - this.logger.verbose('Settings set'); + public async setSettings(data: SettingsDto) { + await this.prismaRepository.setting.upsert({ + where: { + instanceId: this.instanceId, + }, + update: { + rejectCall: data.rejectCall, + msgCall: data.msgCall, + groupsIgnore: data.groupsIgnore, + alwaysOnline: data.alwaysOnline, + readMessages: data.readMessages, + readStatus: data.readStatus, + syncFullHistory: data.syncFullHistory, + wavoipToken: data.wavoipToken, + }, + create: { + rejectCall: data.rejectCall, + msgCall: data.msgCall, + groupsIgnore: data.groupsIgnore, + alwaysOnline: data.alwaysOnline, + readMessages: data.readMessages, + readStatus: data.readStatus, + syncFullHistory: data.syncFullHistory, + wavoipToken: data.wavoipToken, + instanceId: this.instanceId, + }, + }); + + this.localSettings.rejectCall = data?.rejectCall; + this.localSettings.msgCall = data?.msgCall; + this.localSettings.groupsIgnore = data?.groupsIgnore; + this.localSettings.alwaysOnline = data?.alwaysOnline; + this.localSettings.readMessages = data?.readMessages; + this.localSettings.readStatus = data?.readStatus; + this.localSettings.syncFullHistory = data?.syncFullHistory; + this.localSettings.wavoipToken = data?.wavoipToken; + + if (this.localSettings.wavoipToken && this.localSettings.wavoipToken.length > 0) { + this.client.ws.close(); + this.client.ws.connect(); + } } public async findSettings() { - this.logger.verbose('Finding settings'); - const data = await this.repository.settings.find(this.instanceName); + const data = await this.prismaRepository.setting.findUnique({ + where: { + instanceId: this.instanceId, + }, + }); if (!data) { - this.logger.verbose('Settings not found'); return null; } - this.logger.verbose(`Settings url: ${data.reject_call}`); - this.logger.verbose(`Settings msg_call: ${data.msg_call}`); - this.logger.verbose(`Settings groups_ignore: ${data.groups_ignore}`); - this.logger.verbose(`Settings always_online: ${data.always_online}`); - this.logger.verbose(`Settings read_messages: ${data.read_messages}`); - this.logger.verbose(`Settings read_status: ${data.read_status}`); - this.logger.verbose(`Settings sync_full_history: ${data.sync_full_history}`); return { - reject_call: data.reject_call, - msg_call: data.msg_call, - groups_ignore: data.groups_ignore, - always_online: data.always_online, - read_messages: data.read_messages, - read_status: data.read_status, - sync_full_history: data.sync_full_history, - }; - } - - public async loadWebhook() { - this.logger.verbose('Loading webhook'); - const data = await this.repository.webhook.find(this.instanceName); - this.localWebhook.url = data?.url; - this.logger.verbose(`Webhook url: ${this.localWebhook.url}`); - - this.localWebhook.enabled = data?.enabled; - this.logger.verbose(`Webhook enabled: ${this.localWebhook.enabled}`); - - this.localWebhook.events = data?.events; - this.logger.verbose(`Webhook events: ${this.localWebhook.events}`); - - this.localWebhook.webhook_by_events = data?.webhook_by_events; - this.logger.verbose(`Webhook by events: ${this.localWebhook.webhook_by_events}`); - - this.localWebhook.webhook_base64 = data?.webhook_base64; - this.logger.verbose(`Webhook by webhook_base64: ${this.localWebhook.webhook_base64}`); - - this.logger.verbose('Webhook loaded'); - } - - public async setWebhook(data: WebhookRaw) { - this.logger.verbose('Setting webhook'); - await this.repository.webhook.create(data, this.instanceName); - this.logger.verbose(`Webhook url: ${data.url}`); - this.logger.verbose(`Webhook events: ${data.events}`); - Object.assign(this.localWebhook, data); - this.logger.verbose('Webhook set'); - } - - public async findWebhook() { - this.logger.verbose('Finding webhook'); - const data = await this.repository.webhook.find(this.instanceName); - - if (!data) { - this.logger.verbose('Webhook not found'); - throw new NotFoundException('Webhook not found'); - } - - this.logger.verbose(`Webhook url: ${data.url}`); - this.logger.verbose(`Webhook events: ${data.events}`); - - return { - enabled: data.enabled, - url: data.url, - events: data.events, - webhook_by_events: data.webhook_by_events, - webhook_base64: data.webhook_base64, + rejectCall: data.rejectCall, + msgCall: data.msgCall, + groupsIgnore: data.groupsIgnore, + alwaysOnline: data.alwaysOnline, + readMessages: data.readMessages, + readStatus: data.readStatus, + syncFullHistory: data.syncFullHistory, + wavoipToken: data.wavoipToken, }; } public async loadChatwoot() { - this.logger.verbose('Loading chatwoot'); - const data = await this.repository.chatwoot.find(this.instanceName); + if (!this.configService.get('CHATWOOT').ENABLED) { + return; + } + + const data = await this.prismaRepository.chatwoot.findUnique({ + where: { + instanceId: this.instanceId, + }, + }); + this.localChatwoot.enabled = data?.enabled; - this.logger.verbose(`Chatwoot enabled: ${this.localChatwoot.enabled}`); - - this.localChatwoot.account_id = data?.account_id; - this.logger.verbose(`Chatwoot account id: ${this.localChatwoot.account_id}`); - + this.localChatwoot.accountId = data?.accountId; this.localChatwoot.token = data?.token; - this.logger.verbose(`Chatwoot token: ${this.localChatwoot.token}`); - this.localChatwoot.url = data?.url; - this.logger.verbose(`Chatwoot url: ${this.localChatwoot.url}`); - - this.localChatwoot.name_inbox = data?.name_inbox; - this.logger.verbose(`Chatwoot inbox name: ${this.localChatwoot.name_inbox}`); - - this.localChatwoot.sign_msg = data?.sign_msg; - this.logger.verbose(`Chatwoot sign msg: ${this.localChatwoot.sign_msg}`); - + this.localChatwoot.nameInbox = data?.nameInbox; + this.localChatwoot.signMsg = data?.signMsg; + this.localChatwoot.signDelimiter = data?.signDelimiter; this.localChatwoot.number = data?.number; - this.logger.verbose(`Chatwoot number: ${this.localChatwoot.number}`); - - this.localChatwoot.reopen_conversation = data?.reopen_conversation; - this.logger.verbose(`Chatwoot reopen conversation: ${this.localChatwoot.reopen_conversation}`); - - this.localChatwoot.conversation_pending = data?.conversation_pending; - this.logger.verbose(`Chatwoot conversation pending: ${this.localChatwoot.conversation_pending}`); - - this.localChatwoot.merge_brazil_contacts = data?.merge_brazil_contacts; - this.logger.verbose(`Chatwoot merge brazil contacts: ${this.localChatwoot.merge_brazil_contacts}`); - - this.localChatwoot.import_contacts = data?.import_contacts; - this.logger.verbose(`Chatwoot import contacts: ${this.localChatwoot.import_contacts}`); - - this.localChatwoot.import_messages = data?.import_messages; - this.logger.verbose(`Chatwoot import messages: ${this.localChatwoot.import_messages}`); - - this.localChatwoot.days_limit_import_messages = data?.days_limit_import_messages; - this.logger.verbose(`Chatwoot days limit import messages: ${this.localChatwoot.days_limit_import_messages}`); - - this.logger.verbose('Chatwoot loaded'); + this.localChatwoot.reopenConversation = data?.reopenConversation; + this.localChatwoot.conversationPending = data?.conversationPending; + this.localChatwoot.mergeBrazilContacts = data?.mergeBrazilContacts; + this.localChatwoot.importContacts = data?.importContacts; + this.localChatwoot.importMessages = data?.importMessages; + this.localChatwoot.daysLimitImportMessages = data?.daysLimitImportMessages; } - public async setChatwoot(data: ChatwootRaw) { - this.logger.verbose('Setting chatwoot'); - await this.repository.chatwoot.create(data, this.instanceName); - this.logger.verbose(`Chatwoot account id: ${data.account_id}`); - this.logger.verbose(`Chatwoot token: ${data.token}`); - this.logger.verbose(`Chatwoot url: ${data.url}`); - this.logger.verbose(`Chatwoot inbox name: ${data.name_inbox}`); - this.logger.verbose(`Chatwoot sign msg: ${data.sign_msg}`); - this.logger.verbose(`Chatwoot sign delimiter: ${data.sign_delimiter}`); - this.logger.verbose(`Chatwoot reopen conversation: ${data.reopen_conversation}`); - this.logger.verbose(`Chatwoot conversation pending: ${data.conversation_pending}`); - this.logger.verbose(`Chatwoot merge brazil contacts: ${data.merge_brazil_contacts}`); - this.logger.verbose(`Chatwoot import contacts: ${data.import_contacts}`); - this.logger.verbose(`Chatwoot import messages: ${data.import_messages}`); - this.logger.verbose(`Chatwoot days limit import messages: ${data.days_limit_import_messages}`); + public async setChatwoot(data: ChatwootDto) { + if (!this.configService.get('CHATWOOT').ENABLED) { + return; + } - Object.assign(this.localChatwoot, { ...data, sign_delimiter: data.sign_msg ? data.sign_delimiter : null }); + const chatwoot = await this.prismaRepository.chatwoot.findUnique({ + where: { + instanceId: this.instanceId, + }, + }); + + if (chatwoot) { + await this.prismaRepository.chatwoot.update({ + where: { + instanceId: this.instanceId, + }, + data: { + enabled: data?.enabled, + accountId: data.accountId, + token: data.token, + url: data.url, + nameInbox: data.nameInbox, + signMsg: data.signMsg, + signDelimiter: data.signMsg ? data.signDelimiter : null, + number: data.number, + reopenConversation: data.reopenConversation, + conversationPending: data.conversationPending, + mergeBrazilContacts: data.mergeBrazilContacts, + importContacts: data.importContacts, + importMessages: data.importMessages, + daysLimitImportMessages: data.daysLimitImportMessages, + organization: data.organization, + logo: data.logo, + ignoreJids: data.ignoreJids, + }, + }); + + Object.assign(this.localChatwoot, { ...data, signDelimiter: data.signMsg ? data.signDelimiter : null }); + + this.clearCacheChatwoot(); + return; + } + + await this.prismaRepository.chatwoot.create({ + data: { + enabled: data?.enabled, + accountId: data.accountId, + token: data.token, + url: data.url, + nameInbox: data.nameInbox, + signMsg: data.signMsg, + number: data.number, + reopenConversation: data.reopenConversation, + conversationPending: data.conversationPending, + mergeBrazilContacts: data.mergeBrazilContacts, + importContacts: data.importContacts, + importMessages: data.importMessages, + daysLimitImportMessages: data.daysLimitImportMessages, + organization: data.organization, + logo: data.logo, + ignoreJids: data.ignoreJids, + instanceId: this.instanceId, + }, + }); + + Object.assign(this.localChatwoot, { ...data, signDelimiter: data.signMsg ? data.signDelimiter : null }); this.clearCacheChatwoot(); - - this.logger.verbose('Chatwoot set'); } - public async findChatwoot() { - this.logger.verbose('Finding chatwoot'); - const data = await this.repository.chatwoot.find(this.instanceName); - - if (!data) { - this.logger.verbose('Chatwoot not found'); + public async findChatwoot(): Promise { + if (!this.configService.get('CHATWOOT').ENABLED) { return null; } - this.logger.verbose(`Chatwoot account id: ${data.account_id}`); - this.logger.verbose(`Chatwoot token: ${data.token}`); - this.logger.verbose(`Chatwoot url: ${data.url}`); - this.logger.verbose(`Chatwoot inbox name: ${data.name_inbox}`); - this.logger.verbose(`Chatwoot sign msg: ${data.sign_msg}`); - this.logger.verbose(`Chatwoot sign delimiter: ${data.sign_delimiter}`); - this.logger.verbose(`Chatwoot reopen conversation: ${data.reopen_conversation}`); - this.logger.verbose(`Chatwoot conversation pending: ${data.conversation_pending}`); - this.logger.verbose(`Chatwoot merge brazilian contacts: ${data.merge_brazil_contacts}`); - this.logger.verbose(`Chatwoot import contacts: ${data.import_contacts}`); - this.logger.verbose(`Chatwoot import messages: ${data.import_messages}`); - this.logger.verbose(`Chatwoot days limit import messages: ${data.days_limit_import_messages}`); + const data = await this.prismaRepository.chatwoot.findUnique({ + where: { + instanceId: this.instanceId, + }, + }); + + if (!data) { + return null; + } + + const ignoreJidsArray = Array.isArray(data.ignoreJids) ? data.ignoreJids.map((event) => String(event)) : []; return { - enabled: data.enabled, - account_id: data.account_id, + enabled: data?.enabled, + accountId: data.accountId, token: data.token, url: data.url, - name_inbox: data.name_inbox, - sign_msg: data.sign_msg, - sign_delimiter: data.sign_delimiter || null, - reopen_conversation: data.reopen_conversation, - conversation_pending: data.conversation_pending, - merge_brazil_contacts: data.merge_brazil_contacts, - import_contacts: data.import_contacts, - import_messages: data.import_messages, - days_limit_import_messages: data.days_limit_import_messages, + nameInbox: data.nameInbox, + signMsg: data.signMsg, + signDelimiter: data.signDelimiter || null, + reopenConversation: data.reopenConversation, + conversationPending: data.conversationPending, + mergeBrazilContacts: data.mergeBrazilContacts, + importContacts: data.importContacts, + importMessages: data.importMessages, + daysLimitImportMessages: data.daysLimitImportMessages, + organization: data.organization, + logo: data.logo, + ignoreJids: ignoreJidsArray, }; } public clearCacheChatwoot() { - this.logger.verbose('Removing cache from chatwoot'); - - if (this.localChatwoot.enabled) { + if (this.localChatwoot?.enabled) { this.chatwootService.getCache()?.deleteAll(this.instanceName); } } - public async loadWebsocket() { - this.logger.verbose('Loading websocket'); - const data = await this.repository.websocket.find(this.instanceName); - - this.localWebsocket.enabled = data?.enabled; - this.logger.verbose(`Websocket enabled: ${this.localWebsocket.enabled}`); - - this.localWebsocket.events = data?.events; - this.logger.verbose(`Websocket events: ${this.localWebsocket.events}`); - - this.logger.verbose('Websocket loaded'); - } - - public async setWebsocket(data: WebsocketRaw) { - this.logger.verbose('Setting websocket'); - await this.repository.websocket.create(data, this.instanceName); - this.logger.verbose(`Websocket events: ${data.events}`); - Object.assign(this.localWebsocket, data); - this.logger.verbose('Websocket set'); - } - - public async findWebsocket() { - this.logger.verbose('Finding websocket'); - const data = await this.repository.websocket.find(this.instanceName); - - if (!data) { - this.logger.verbose('Websocket not found'); - throw new NotFoundException('Websocket not found'); - } - - this.logger.verbose(`Websocket events: ${data.events}`); - return { - enabled: data.enabled, - events: data.events, - }; - } - - public async loadRabbitmq() { - this.logger.verbose('Loading rabbitmq'); - const data = await this.repository.rabbitmq.find(this.instanceName); - - this.localRabbitmq.enabled = data?.enabled; - this.logger.verbose(`Rabbitmq enabled: ${this.localRabbitmq.enabled}`); - - this.localRabbitmq.events = data?.events; - this.logger.verbose(`Rabbitmq events: ${this.localRabbitmq.events}`); - - this.logger.verbose('Rabbitmq loaded'); - } - - public async setRabbitmq(data: RabbitmqRaw) { - this.logger.verbose('Setting rabbitmq'); - await this.repository.rabbitmq.create(data, this.instanceName); - this.logger.verbose(`Rabbitmq events: ${data.events}`); - Object.assign(this.localRabbitmq, data); - this.logger.verbose('Rabbitmq set'); - } - - public async findRabbitmq() { - this.logger.verbose('Finding rabbitmq'); - const data = await this.repository.rabbitmq.find(this.instanceName); - - if (!data) { - this.logger.verbose('Rabbitmq not found'); - throw new NotFoundException('Rabbitmq not found'); - } - - this.logger.verbose(`Rabbitmq events: ${data.events}`); - return { - enabled: data.enabled, - events: data.events, - }; - } - - public async removeRabbitmqQueues() { - this.logger.verbose('Removing rabbitmq'); - - if (this.localRabbitmq.enabled) { - removeQueues(this.instanceName, this.localRabbitmq.events); - } - } - - public async loadSqs() { - this.logger.verbose('Loading sqs'); - const data = await this.repository.sqs.find(this.instanceName); - - this.localSqs.enabled = data?.enabled; - this.logger.verbose(`Sqs enabled: ${this.localSqs.enabled}`); - - this.localSqs.events = data?.events; - this.logger.verbose(`Sqs events: ${this.localSqs.events}`); - - this.logger.verbose('Sqs loaded'); - } - - public async setSqs(data: SqsRaw) { - this.logger.verbose('Setting sqs'); - await this.repository.sqs.create(data, this.instanceName); - this.logger.verbose(`Sqs events: ${data.events}`); - Object.assign(this.localSqs, data); - this.logger.verbose('Sqs set'); - } - - public async findSqs() { - this.logger.verbose('Finding sqs'); - const data = await this.repository.sqs.find(this.instanceName); - - if (!data) { - this.logger.verbose('Sqs not found'); - throw new NotFoundException('Sqs not found'); - } - - this.logger.verbose(`Sqs events: ${data.events}`); - return { - enabled: data.enabled, - events: data.events, - }; - } - - public async removeSqsQueues() { - this.logger.verbose('Removing sqs'); - - if (this.localSqs.enabled) { - removeQueuesSQS(this.instanceName, this.localSqs.events); - } - } - - public async loadTypebot() { - this.logger.verbose('Loading typebot'); - const data = await this.repository.typebot.find(this.instanceName); - - this.localTypebot.enabled = data?.enabled; - this.logger.verbose(`Typebot enabled: ${this.localTypebot.enabled}`); - - this.localTypebot.url = data?.url; - this.logger.verbose(`Typebot url: ${this.localTypebot.url}`); - - this.localTypebot.typebot = data?.typebot; - this.logger.verbose(`Typebot typebot: ${this.localTypebot.typebot}`); - - this.localTypebot.expire = data?.expire; - this.logger.verbose(`Typebot expire: ${this.localTypebot.expire}`); - - this.localTypebot.keyword_finish = data?.keyword_finish; - this.logger.verbose(`Typebot keyword_finish: ${this.localTypebot.keyword_finish}`); - - this.localTypebot.delay_message = data?.delay_message; - this.logger.verbose(`Typebot delay_message: ${this.localTypebot.delay_message}`); - - this.localTypebot.unknown_message = data?.unknown_message; - this.logger.verbose(`Typebot unknown_message: ${this.localTypebot.unknown_message}`); - - this.localTypebot.listening_from_me = data?.listening_from_me; - this.logger.verbose(`Typebot listening_from_me: ${this.localTypebot.listening_from_me}`); - - this.localTypebot.sessions = data?.sessions; - - this.logger.verbose('Typebot loaded'); - } - - public async setTypebot(data: TypebotRaw) { - this.logger.verbose('Setting typebot'); - await this.repository.typebot.create(data, this.instanceName); - this.logger.verbose(`Typebot typebot: ${data.typebot}`); - this.logger.verbose(`Typebot expire: ${data.expire}`); - this.logger.verbose(`Typebot keyword_finish: ${data.keyword_finish}`); - this.logger.verbose(`Typebot delay_message: ${data.delay_message}`); - this.logger.verbose(`Typebot unknown_message: ${data.unknown_message}`); - this.logger.verbose(`Typebot listening_from_me: ${data.listening_from_me}`); - Object.assign(this.localTypebot, data); - this.logger.verbose('Typebot set'); - } - - public async findTypebot() { - this.logger.verbose('Finding typebot'); - const data = await this.repository.typebot.find(this.instanceName); - - if (!data) { - this.logger.verbose('Typebot not found'); - throw new NotFoundException('Typebot not found'); - } - - return { - enabled: data.enabled, - url: data.url, - typebot: data.typebot, - expire: data.expire, - keyword_finish: data.keyword_finish, - delay_message: data.delay_message, - unknown_message: data.unknown_message, - listening_from_me: data.listening_from_me, - sessions: data.sessions, - }; - } - public async loadProxy() { - this.logger.verbose('Loading proxy'); - const data = await this.repository.proxy.find(this.instanceName); + this.localProxy.enabled = false; - this.localProxy.enabled = data?.enabled; - this.logger.verbose(`Proxy enabled: ${this.localProxy.enabled}`); + if (process.env.PROXY_HOST) { + this.localProxy.enabled = true; + this.localProxy.host = process.env.PROXY_HOST; + this.localProxy.port = process.env.PROXY_PORT || '80'; + this.localProxy.protocol = process.env.PROXY_PROTOCOL || 'http'; + this.localProxy.username = process.env.PROXY_USERNAME; + this.localProxy.password = process.env.PROXY_PASSWORD; + } - this.localProxy.proxy = data?.proxy; - this.logger.verbose(`Proxy proxy: ${this.localProxy.proxy?.host}`); + const data = await this.prismaRepository.proxy.findUnique({ + where: { + instanceId: this.instanceId, + }, + }); - this.logger.verbose('Proxy loaded'); + if (data?.enabled) { + this.localProxy.enabled = true; + this.localProxy.host = data?.host; + this.localProxy.port = data?.port; + this.localProxy.protocol = data?.protocol; + this.localProxy.username = data?.username; + this.localProxy.password = data?.password; + } } - public async setProxy(data: ProxyRaw) { - this.logger.verbose('Setting proxy'); - await this.repository.proxy.create(data, this.instanceName); - this.logger.verbose(`Proxy proxy: ${data.proxy}`); + public async setProxy(data: ProxyDto) { + await this.prismaRepository.proxy.upsert({ + where: { + instanceId: this.instanceId, + }, + update: { + enabled: data?.enabled, + host: data.host, + port: data.port, + protocol: data.protocol, + username: data.username, + password: data.password, + }, + create: { + enabled: data?.enabled, + host: data.host, + port: data.port, + protocol: data.protocol, + username: data.username, + password: data.password, + instanceId: this.instanceId, + }, + }); + Object.assign(this.localProxy, data); - this.logger.verbose('Proxy set'); } public async findProxy() { - this.logger.verbose('Finding proxy'); - const data = await this.repository.proxy.find(this.instanceName); + const data = await this.prismaRepository.proxy.findUnique({ + where: { + instanceId: this.instanceId, + }, + }); if (!data) { - this.logger.verbose('Proxy not found'); throw new NotFoundException('Proxy not found'); } - return { - enabled: data.enabled, - proxy: data.proxy, - }; + return data; } - public async loadChamaai() { - this.logger.verbose('Loading chamaai'); - const data = await this.repository.chamaai.find(this.instanceName); - - this.localChamaai.enabled = data?.enabled; - this.logger.verbose(`Chamaai enabled: ${this.localChamaai.enabled}`); - - this.localChamaai.url = data?.url; - this.logger.verbose(`Chamaai url: ${this.localChamaai.url}`); - - this.localChamaai.token = data?.token; - this.logger.verbose(`Chamaai token: ${this.localChamaai.token}`); - - this.localChamaai.waNumber = data?.waNumber; - this.logger.verbose(`Chamaai waNumber: ${this.localChamaai.waNumber}`); - - this.localChamaai.answerByAudio = data?.answerByAudio; - this.logger.verbose(`Chamaai answerByAudio: ${this.localChamaai.answerByAudio}`); - - this.logger.verbose('Chamaai loaded'); - } - - public async setChamaai(data: ChamaaiRaw) { - this.logger.verbose('Setting chamaai'); - await this.repository.chamaai.create(data, this.instanceName); - this.logger.verbose(`Chamaai url: ${data.url}`); - this.logger.verbose(`Chamaai token: ${data.token}`); - this.logger.verbose(`Chamaai waNumber: ${data.waNumber}`); - this.logger.verbose(`Chamaai answerByAudio: ${data.answerByAudio}`); - - Object.assign(this.localChamaai, data); - this.logger.verbose('Chamaai set'); - } - - public async findChamaai() { - this.logger.verbose('Finding chamaai'); - const data = await this.repository.chamaai.find(this.instanceName); - - if (!data) { - this.logger.verbose('Chamaai not found'); - throw new NotFoundException('Chamaai not found'); - } - - return { - enabled: data.enabled, - url: data.url, - token: data.token, - waNumber: data.waNumber, - answerByAudio: data.answerByAudio, - }; - } - - private assertExchangeAsync = (channel, exchangeName, exchangeType, options) => { - return new Promise((resolve, reject) => { - channel.assertExchange(exchangeName, exchangeType, options, (error, ok) => { - if (error) { - reject(error); - } else { - resolve(ok); - } - }); - }); - }; - - public async sendDataWebhook(event: Events, data: T, local = true) { - const webhookGlobal = this.configService.get('WEBHOOK'); - const webhookLocal = this.localWebhook.events; - const websocketLocal = this.localWebsocket.events; - const rabbitmqLocal = this.localRabbitmq.events; - const sqsLocal = this.localSqs.events; + public async sendDataWebhook(event: Events, data: T, local = true, integration?: string[]) { const serverUrl = this.configService.get('SERVER').URL; - const rabbitmqEnabled = this.configService.get('RABBITMQ').ENABLED; - const rabbitmqGlobal = this.configService.get('RABBITMQ').GLOBAL_ENABLED; - const rabbitmqEvents = this.configService.get('RABBITMQ').EVENTS; - const we = event.replace(/[.-]/gm, '_').toUpperCase(); - const transformedWe = we.replace(/_/gm, '-').toLowerCase(); const tzoffset = new Date().getTimezoneOffset() * 60000; //offset in milliseconds const localISOTime = new Date(Date.now() - tzoffset).toISOString(); const now = localISOTime; const expose = this.configService.get('AUTHENTICATION').EXPOSE_IN_FETCH_INSTANCES; - const tokenStore = await this.repository.auth.find(this.instanceName); - const instanceApikey = tokenStore?.apikey || 'Apikey not found'; - if (rabbitmqEnabled) { - const amqp = getAMQP(); - if (this.localRabbitmq.enabled && amqp) { - if (Array.isArray(rabbitmqLocal) && rabbitmqLocal.includes(we)) { - const exchangeName = this.instanceName ?? 'evolution_exchange'; - - let retry = 0; - - while (retry < 3) { - try { - await amqp.assertExchange(exchangeName, 'topic', { - durable: true, - autoDelete: false, - }); - - const queueName = `${this.instanceName}.${event}`; - - await amqp.assertQueue(queueName, { - durable: true, - autoDelete: false, - arguments: { - 'x-queue-type': 'quorum', - }, - }); - - await amqp.bindQueue(queueName, exchangeName, event); - - const message = { - event, - instance: this.instance.name, - data, - server_url: serverUrl, - date_time: now, - sender: this.wuid, - }; - - if (expose && instanceApikey) { - message['apikey'] = instanceApikey; - } - - await amqp.publish(exchangeName, event, Buffer.from(JSON.stringify(message))); - - if (this.configService.get('LOG').LEVEL.includes('WEBHOOKS')) { - const logData = { - local: ChannelStartupService.name + '.sendData-RabbitMQ', - event, - instance: this.instance.name, - data, - server_url: serverUrl, - apikey: (expose && instanceApikey) || null, - date_time: now, - sender: this.wuid, - }; - - if (expose && instanceApikey) { - logData['apikey'] = instanceApikey; - } - - this.logger.log(logData); - } - break; - } catch (error) { - retry++; - } - } - } - } - - if (rabbitmqGlobal && rabbitmqEvents[we] && amqp) { - const exchangeName = 'evolution_exchange'; - - let retry = 0; - - while (retry < 3) { - try { - await amqp.assertExchange(exchangeName, 'topic', { - durable: true, - autoDelete: false, - }); - - const queueName = transformedWe; - - await amqp.assertQueue(queueName, { - durable: true, - autoDelete: false, - arguments: { - 'x-queue-type': 'quorum', - }, - }); - - await amqp.bindQueue(queueName, exchangeName, event); - - const message = { - event, - instance: this.instance.name, - data, - server_url: serverUrl, - date_time: now, - sender: this.wuid, - }; - - if (expose && instanceApikey) { - message['apikey'] = instanceApikey; - } - await amqp.publish(exchangeName, event, Buffer.from(JSON.stringify(message))); - - if (this.configService.get('LOG').LEVEL.includes('WEBHOOKS')) { - const logData = { - local: ChannelStartupService.name + '.sendData-RabbitMQ-Global', - event, - instance: this.instance.name, - data, - server_url: serverUrl, - apikey: (expose && instanceApikey) || null, - date_time: now, - sender: this.wuid, - }; - - if (expose && instanceApikey) { - logData['apikey'] = instanceApikey; - } - - this.logger.log(logData); - } - - break; - } catch (error) { - retry++; - } - } - } - } - - if (this.localSqs.enabled) { - const sqs = getSQS(); - - if (sqs) { - if (Array.isArray(sqsLocal) && sqsLocal.includes(we)) { - const eventFormatted = `${event.replace('.', '_').toLowerCase()}`; - - const queueName = `${this.instanceName}_${eventFormatted}.fifo`; - - const sqsConfig = this.configService.get('SQS'); - - const sqsUrl = `https://sqs.${sqsConfig.REGION}.amazonaws.com/${sqsConfig.ACCOUNT_ID}/${queueName}`; - - const message = { - event, - instance: this.instance.name, - data, - server_url: serverUrl, - date_time: now, - sender: this.wuid, - }; - - if (expose && instanceApikey) { - message['apikey'] = instanceApikey; - } - - const params = { - MessageBody: JSON.stringify(message), - MessageGroupId: 'evolution', - MessageDeduplicationId: `${this.instanceName}_${eventFormatted}_${Date.now()}`, - QueueUrl: sqsUrl, - }; - - sqs.sendMessage(params, (err, data) => { - if (err) { - this.logger.error({ - local: ChannelStartupService.name + '.sendData-SQS', - message: err?.message, - hostName: err?.hostname, - code: err?.code, - stack: err?.stack, - name: err?.name, - url: queueName, - server_url: serverUrl, - }); - } else { - if (this.configService.get('LOG').LEVEL.includes('WEBHOOKS')) { - const logData = { - local: ChannelStartupService.name + '.sendData-SQS', - event, - instance: this.instance.name, - data, - server_url: serverUrl, - apikey: (expose && instanceApikey) || null, - date_time: now, - sender: this.wuid, - }; - - if (expose && instanceApikey) { - logData['apikey'] = instanceApikey; - } - - this.logger.log(logData); - } - } - }); - } - } - } - - if (this.configService.get('WEBSOCKET')?.ENABLED) { - this.logger.verbose('Sending data to websocket on channel: ' + this.instance.name); - const io = getIO(); - - const message = { - event, - instance: this.instance.name, - data, - server_url: serverUrl, - date_time: now, - sender: this.wuid, - }; - - if (expose && instanceApikey) { - message['apikey'] = instanceApikey; - } - - if (this.configService.get('WEBSOCKET')?.GLOBAL_EVENTS) { - io.emit(event, message); - - if (this.configService.get('LOG').LEVEL.includes('WEBHOOKS')) { - const logData = { - local: ChannelStartupService.name + '.sendData-WebsocketGlobal', - event, - instance: this.instance.name, - data, - server_url: serverUrl, - apikey: (expose && instanceApikey) || null, - date_time: now, - sender: this.wuid, - }; - - if (expose && instanceApikey) { - logData['apikey'] = instanceApikey; - } - - this.logger.log(logData); - } - } - - if (this.localWebsocket.enabled && Array.isArray(websocketLocal) && websocketLocal.includes(we)) { - this.logger.verbose('Sending data to websocket on event: ' + event); - - this.logger.verbose('Sending data to socket.io in channel: ' + this.instance.name); - io.of(`/${this.instance.name}`).emit(event, message); - - if (this.configService.get('WEBSOCKET')?.GLOBAL_EVENTS) { - io.emit(event, message); - } - - if (this.configService.get('LOG').LEVEL.includes('WEBHOOKS')) { - const logData = { - local: ChannelStartupService.name + '.sendData-Websocket', - event, - instance: this.instance.name, - data, - server_url: serverUrl, - apikey: (expose && instanceApikey) || null, - date_time: now, - sender: this.wuid, - }; - - if (expose && instanceApikey) { - logData['apikey'] = instanceApikey; - } - - this.logger.log(logData); - } - } - } - - const globalApiKey = this.configService.get('AUTHENTICATION').API_KEY.KEY; - - if (local) { - if (Array.isArray(webhookLocal) && webhookLocal.includes(we)) { - this.logger.verbose('Sending data to webhook local'); - let baseURL: string; - - if (this.localWebhook.webhook_by_events) { - baseURL = `${this.localWebhook.url}/${transformedWe}`; - } else { - baseURL = this.localWebhook.url; - } - - if (this.configService.get('LOG').LEVEL.includes('WEBHOOKS')) { - const logData = { - local: ChannelStartupService.name + '.sendDataWebhook-local', - url: baseURL, - event, - instance: this.instance.name, - data, - destination: this.localWebhook.url, - date_time: now, - sender: this.wuid, - server_url: serverUrl, - apikey: (expose && instanceApikey) || null, - }; - - if (expose && instanceApikey) { - logData['apikey'] = instanceApikey; - } - - this.logger.log(logData); - } - - try { - if (this.localWebhook.enabled && isURL(this.localWebhook.url, { require_tld: false })) { - const httpService = axios.create({ baseURL }); - const postData = { - event, - instance: this.instance.name, - data, - destination: this.localWebhook.url, - date_time: now, - sender: this.wuid, - server_url: serverUrl, - }; - - if (expose && instanceApikey) { - postData['apikey'] = instanceApikey; - } - - await httpService.post('', postData); - } - } catch (error) { - this.logger.error({ - local: ChannelStartupService.name + '.sendDataWebhook-local', - message: error?.message, - hostName: error?.hostname, - syscall: error?.syscall, - code: error?.code, - error: error?.errno, - stack: error?.stack, - name: error?.name, - url: baseURL, - server_url: serverUrl, - }); - } - } - } - - if (webhookGlobal.GLOBAL?.ENABLED) { - if (webhookGlobal.EVENTS[we]) { - this.logger.verbose('Sending data to webhook global'); - const globalWebhook = this.configService.get('WEBHOOK').GLOBAL; - - let globalURL; - - if (webhookGlobal.GLOBAL.WEBHOOK_BY_EVENTS) { - globalURL = `${globalWebhook.URL}/${transformedWe}`; - } else { - globalURL = globalWebhook.URL; - } - - const localUrl = this.localWebhook.url; - - if (this.configService.get('LOG').LEVEL.includes('WEBHOOKS')) { - const logData = { - local: ChannelStartupService.name + '.sendDataWebhook-global', - url: globalURL, - event, - instance: this.instance.name, - data, - destination: localUrl, - date_time: now, - sender: this.wuid, - server_url: serverUrl, - }; - - if (expose && globalApiKey) { - logData['apikey'] = globalApiKey; - } - - this.logger.log(logData); - } - - try { - if (globalWebhook && globalWebhook?.ENABLED && isURL(globalURL)) { - const httpService = axios.create({ baseURL: globalURL }); - const postData = { - event, - instance: this.instance.name, - data, - destination: localUrl, - date_time: now, - sender: this.wuid, - server_url: serverUrl, - }; - - if (expose && globalApiKey) { - postData['apikey'] = globalApiKey; - } - - await httpService.post('', postData); - } - } catch (error) { - this.logger.error({ - local: ChannelStartupService.name + '.sendDataWebhook-global', - message: error?.message, - hostName: error?.hostname, - syscall: error?.syscall, - code: error?.code, - error: error?.errno, - stack: error?.stack, - name: error?.name, - url: globalURL, - server_url: serverUrl, - }); - } - } - } - } - - public cleanStore() { - this.logger.verbose('Cronjob to clean store initialized'); - const cleanStore = this.configService.get('CLEAN_STORE'); - const database = this.configService.get('DATABASE'); - if (cleanStore?.CLEANING_INTERVAL && !database.ENABLED) { - this.logger.verbose('Cronjob to clean store enabled'); - setInterval(() => { - try { - for (const [key, value] of Object.entries(cleanStore)) { - if (value === true) { - execSync( - `rm -rf ${join(this.storePath, key.toLowerCase().replace('_', '-'), this.instance.name)}/*.json`, - ); - this.logger.verbose( - `Cleaned ${join(this.storePath, key.toLowerCase().replace('_', '-'), this.instance.name)}/*.json`, - ); - } - } - } catch (error) { - this.logger.error(error); - } - }, (cleanStore?.CLEANING_INTERVAL ?? 3600) * 1000); - } + const instanceApikey = this.token || 'Apikey not found'; + + await eventManager.emit({ + instanceName: this.instance.name, + origin: ChannelStartupService.name, + event, + data, + serverUrl, + dateTime: now, + sender: this.wuid, + apiKey: expose && instanceApikey ? instanceApikey : null, + local, + integration, + }); } // Check if the number is MX or AR @@ -1181,104 +488,288 @@ export class ChannelStartupService { } } - public createJid(number: string): string { - this.logger.verbose('Creating jid with number: ' + number); + public async fetchContacts(query: Query) { + const remoteJid = query?.where?.remoteJid + ? query?.where?.remoteJid.includes('@') + ? query.where?.remoteJid + : createJid(query.where?.remoteJid) + : null; - if (number.includes('@g.us') || number.includes('@s.whatsapp.net') || number.includes('@lid')) { - this.logger.verbose('Number already contains @g.us or @s.whatsapp.net or @lid'); - return number; + const where = { + instanceId: this.instanceId, + }; + + if (remoteJid) { + where['remoteJid'] = remoteJid; } - if (number.includes('@broadcast')) { - this.logger.verbose('Number already contains @broadcast'); - return number; - } - - number = number - ?.replace(/\s/g, '') - .replace(/\+/g, '') - .replace(/\(/g, '') - .replace(/\)/g, '') - .split(':')[0] - .split('@')[0]; - - if (number.includes('-') && number.length >= 24) { - this.logger.verbose('Jid created is group: ' + `${number}@g.us`); - number = number.replace(/[^\d-]/g, ''); - return `${number}@g.us`; - } - - number = number.replace(/\D/g, ''); - - if (number.length >= 18) { - this.logger.verbose('Jid created is group: ' + `${number}@g.us`); - number = number.replace(/[^\d-]/g, ''); - return `${number}@g.us`; - } - - number = this.formatMXOrARNumber(number); - - number = this.formatBRNumber(number); - - this.logger.verbose('Jid created is whatsapp: ' + `${number}@s.whatsapp.net`); - return `${number}@s.whatsapp.net`; + return await this.prismaRepository.contact.findMany({ + where, + }); } - public async fetchContacts(query: ContactQuery) { - this.logger.verbose('Fetching contacts'); - if (query?.where) { - query.where.owner = this.instance.name; - if (query.where?.id) { - query.where.id = this.createJid(query.where.id); + public cleanMessageData(message: any) { + if (!message) return message; + + const cleanedMessage = { ...message }; + + const mediaUrl = cleanedMessage.message.mediaUrl; + + delete cleanedMessage.message.base64; + + if (cleanedMessage.message) { + // Limpa imageMessage + if (cleanedMessage.message.imageMessage) { + cleanedMessage.message.imageMessage = { + caption: cleanedMessage.message.imageMessage.caption, + }; } - } else { - query = { - where: { - owner: this.instance.name, - }, - }; - } - return await this.repository.contact.find(query); - } - public async fetchMessages(query: MessageQuery) { - this.logger.verbose('Fetching messages'); - if (query?.where) { - if (query.where?.key?.remoteJid) { - query.where.key.remoteJid = this.createJid(query.where.key.remoteJid); + // Limpa videoMessage + if (cleanedMessage.message.videoMessage) { + cleanedMessage.message.videoMessage = { + caption: cleanedMessage.message.videoMessage.caption, + }; } - query.where.owner = this.instance.name; - } else { - query = { - where: { - owner: this.instance.name, - }, - limit: query?.limit, - }; - } - return await this.repository.message.find(query); - } - public async fetchStatusMessage(query: MessageUpQuery) { - this.logger.verbose('Fetching status messages'); - if (query?.where) { - if (query.where?.remoteJid) { - query.where.remoteJid = this.createJid(query.where.remoteJid); + // Limpa audioMessage + if (cleanedMessage.message.audioMessage) { + cleanedMessage.message.audioMessage = { + seconds: cleanedMessage.message.audioMessage.seconds, + }; + } + + // Limpa stickerMessage + if (cleanedMessage.message.stickerMessage) { + cleanedMessage.message.stickerMessage = {}; + } + + // Limpa documentMessage + if (cleanedMessage.message.documentMessage) { + cleanedMessage.message.documentMessage = { + caption: cleanedMessage.message.documentMessage.caption, + name: cleanedMessage.message.documentMessage.name, + }; + } + + // Limpa documentWithCaptionMessage + if (cleanedMessage.message.documentWithCaptionMessage) { + cleanedMessage.message.documentWithCaptionMessage = { + caption: cleanedMessage.message.documentWithCaptionMessage.caption, + name: cleanedMessage.message.documentWithCaptionMessage.name, + }; } - query.where.owner = this.instance.name; - } else { - query = { - where: { - owner: this.instance.name, - }, - limit: query?.limit, - }; } - return await this.repository.messageUpdate.find(query); + + if (mediaUrl) cleanedMessage.message.mediaUrl = mediaUrl; + + return cleanedMessage; } - public async fetchChats() { - this.logger.verbose('Fetching chats'); - return await this.repository.chat.find({ where: { owner: this.instance.name } }); + public async fetchMessages(query: Query) { + const keyFilters = query?.where?.key as { + id?: string; + fromMe?: boolean; + remoteJid?: string; + participants?: string; + }; + + const timestampFilter = {}; + if (query?.where?.messageTimestamp) { + if (query.where.messageTimestamp['gte'] && query.where.messageTimestamp['lte']) { + timestampFilter['messageTimestamp'] = { + gte: Math.floor(new Date(query.where.messageTimestamp['gte']).getTime() / 1000), + lte: Math.floor(new Date(query.where.messageTimestamp['lte']).getTime() / 1000), + }; + } + } + + const count = await this.prismaRepository.message.count({ + where: { + instanceId: this.instanceId, + id: query?.where?.id, + source: query?.where?.source, + messageType: query?.where?.messageType, + ...timestampFilter, + AND: [ + keyFilters?.id ? { key: { path: ['id'], equals: keyFilters?.id } } : {}, + keyFilters?.fromMe ? { key: { path: ['fromMe'], equals: keyFilters?.fromMe } } : {}, + keyFilters?.remoteJid ? { key: { path: ['remoteJid'], equals: keyFilters?.remoteJid } } : {}, + keyFilters?.participants ? { key: { path: ['participants'], equals: keyFilters?.participants } } : {}, + ], + }, + }); + + if (!query?.offset) { + query.offset = 50; + } + + if (!query?.page) { + query.page = 1; + } + + const messages = await this.prismaRepository.message.findMany({ + where: { + instanceId: this.instanceId, + id: query?.where?.id, + source: query?.where?.source, + messageType: query?.where?.messageType, + ...timestampFilter, + AND: [ + keyFilters?.id ? { key: { path: ['id'], equals: keyFilters?.id } } : {}, + keyFilters?.fromMe ? { key: { path: ['fromMe'], equals: keyFilters?.fromMe } } : {}, + keyFilters?.remoteJid ? { key: { path: ['remoteJid'], equals: keyFilters?.remoteJid } } : {}, + keyFilters?.participants ? { key: { path: ['participants'], equals: keyFilters?.participants } } : {}, + ], + }, + orderBy: { + messageTimestamp: 'desc', + }, + skip: query.offset * (query?.page === 1 ? 0 : (query?.page as number) - 1), + take: query.offset, + select: { + id: true, + key: true, + pushName: true, + messageType: true, + message: true, + messageTimestamp: true, + instanceId: true, + source: true, + contextInfo: true, + MessageUpdate: { + select: { + status: true, + }, + }, + }, + }); + + return { + messages: { + total: count, + pages: Math.ceil(count / query.offset), + currentPage: query.page, + records: messages, + }, + }; + } + + public async fetchStatusMessage(query: any) { + return await this.prismaRepository.messageUpdate.findMany({ + where: { + instanceId: this.instanceId, + remoteJid: query.where?.remoteJid, + keyId: query.where?.id, + }, + skip: query.offset * (query?.page === 1 ? 0 : (query?.page as number) - 1), + take: query.offset, + }); + } + + public async fetchChats(query: any) { + const remoteJid = query?.where?.remoteJid + ? query?.where?.remoteJid.includes('@') + ? query.where?.remoteJid + : createJid(query.where?.remoteJid) + : null; + + const where = { + instanceId: this.instanceId, + }; + + if (remoteJid) { + where['remoteJid'] = remoteJid; + } + + const timestampFilter = + query?.where?.messageTimestamp?.gte && query?.where?.messageTimestamp?.lte + ? Prisma.sql` + AND "Message"."messageTimestamp" >= ${Math.floor(new Date(query.where.messageTimestamp.gte).getTime() / 1000)} + AND "Message"."messageTimestamp" <= ${Math.floor(new Date(query.where.messageTimestamp.lte).getTime() / 1000)}` + : Prisma.sql``; + + const results = await this.prismaRepository.$queryRaw` + WITH rankedMessages AS ( + SELECT DISTINCT ON ("Contact"."remoteJid") + "Contact"."id", + "Contact"."remoteJid", + "Contact"."pushName", + "Contact"."profilePicUrl", + COALESCE( + to_timestamp("Message"."messageTimestamp"::double precision), + "Contact"."updatedAt" + ) as "updatedAt", + "Chat"."createdAt" as "windowStart", + "Chat"."createdAt" + INTERVAL '24 hours' as "windowExpires", + CASE + WHEN "Chat"."createdAt" + INTERVAL '24 hours' > NOW() THEN true + ELSE false + END as "windowActive", + "Message"."id" AS lastMessageId, + "Message"."key" AS lastMessage_key, + "Message"."pushName" AS lastMessagePushName, + "Message"."participant" AS lastMessageParticipant, + "Message"."messageType" AS lastMessageMessageType, + "Message"."message" AS lastMessageMessage, + "Message"."contextInfo" AS lastMessageContextInfo, + "Message"."source" AS lastMessageSource, + "Message"."messageTimestamp" AS lastMessageMessageTimestamp, + "Message"."instanceId" AS lastMessageInstanceId, + "Message"."sessionId" AS lastMessageSessionId, + "Message"."status" AS lastMessageStatus + FROM "Contact" + INNER JOIN "Message" ON "Message"."key"->>'remoteJid' = "Contact"."remoteJid" + LEFT JOIN "Chat" ON "Chat"."remoteJid" = "Contact"."remoteJid" + AND "Chat"."instanceId" = "Contact"."instanceId" + WHERE + "Contact"."instanceId" = ${this.instanceId} + AND "Message"."instanceId" = ${this.instanceId} + ${remoteJid ? Prisma.sql`AND "Contact"."remoteJid" = ${remoteJid}` : Prisma.sql``} + ${timestampFilter} + ORDER BY + "Contact"."remoteJid", + "Message"."messageTimestamp" DESC + ) + SELECT * FROM rankedMessages + ORDER BY "updatedAt" DESC NULLS LAST; + `; + + if (results && isArray(results) && results.length > 0) { + const mappedResults = results.map((contact) => { + const lastMessage = contact.lastMessageId + ? { + id: contact.lastMessageId, + key: contact.lastMessageKey, + pushName: contact.lastMessagePushName, + participant: contact.lastMessageParticipant, + messageType: contact.lastMessageMessageType, + message: contact.lastMessageMessage, + contextInfo: contact.lastMessageContextInfo, + source: contact.lastMessageSource, + messageTimestamp: contact.lastMessageMessageTimestamp, + instanceId: contact.lastMessageInstanceId, + sessionId: contact.lastMessageSessionId, + status: contact.lastMessageStatus, + } + : undefined; + + return { + id: contact.id, + remoteJid: contact.remoteJid, + pushName: contact.pushName, + profilePicUrl: contact.profilePicUrl, + updatedAt: contact.updatedAt, + windowStart: contact.windowStart, + windowExpires: contact.windowExpires, + windowActive: contact.windowActive, + lastMessage: lastMessage ? this.cleanMessageData(lastMessage) : undefined, + }; + }); + + return mappedResults; + } + + return []; } } diff --git a/src/api/services/channels/whatsapp.baileys.service.ts b/src/api/services/channels/whatsapp.baileys.service.ts deleted file mode 100644 index 2840d9a7..00000000 --- a/src/api/services/channels/whatsapp.baileys.service.ts +++ /dev/null @@ -1,3447 +0,0 @@ -import ffmpegPath from '@ffmpeg-installer/ffmpeg'; -import { Boom } from '@hapi/boom'; -import makeWASocket, { - AnyMessageContent, - BufferedEventData, - BufferJSON, - CacheStore, - Chat, - ConnectionState, - Contact, - delay, - DisconnectReason, - downloadMediaMessage, - fetchLatestBaileysVersion, - generateWAMessageFromContent, - getAggregateVotesInPollMessage, - getContentType, - getDevice, - GroupMetadata, - isJidBroadcast, - isJidGroup, - isJidUser, - makeCacheableSignalKeyStore, - MessageUpsertType, - MiscMessageGenerationOptions, - ParticipantAction, - PHONENUMBER_MCC, - prepareWAMessageMedia, - proto, - useMultiFileAuthState, - UserFacingSocketConfig, - WABrowserDescription, - WAMediaUpload, - WAMessage, - WAMessageUpdate, - WAPresence, - WASocket, -} from '@whiskeysockets/baileys'; -import { Label } from '@whiskeysockets/baileys/lib/Types/Label'; -import { LabelAssociation } from '@whiskeysockets/baileys/lib/Types/LabelAssociation'; -import axios from 'axios'; -import { exec } from 'child_process'; -import { isBase64, isURL } from 'class-validator'; -import EventEmitter2 from 'eventemitter2'; -// import ffmpeg from 'fluent-ffmpeg'; -import fs, { existsSync, readFileSync } from 'fs'; -import { parsePhoneNumber } from 'libphonenumber-js'; -import Long from 'long'; -import NodeCache from 'node-cache'; -import { getMIMEType } from 'node-mime-types'; -import { release } from 'os'; -import { join } from 'path'; -import P from 'pino'; -import qrcode, { QRCodeToDataURLOptions } from 'qrcode'; -import qrcodeTerminal from 'qrcode-terminal'; -import sharp from 'sharp'; - -import { CacheConf, ConfigService, ConfigSessionPhone, Database, Log, QrCode } from '../../../config/env.config'; -import { INSTANCE_DIR } from '../../../config/path.config'; -import { BadRequestException, InternalServerErrorException, NotFoundException } from '../../../exceptions'; -import { dbserver } from '../../../libs/db.connect'; -import { makeProxyAgent } from '../../../utils/makeProxyAgent'; -import { useMultiFileAuthStateDb } from '../../../utils/use-multi-file-auth-state-db'; -import { useMultiFileAuthStateRedisDb } from '../../../utils/use-multi-file-auth-state-redis-db'; -import { - ArchiveChatDto, - BlockUserDto, - DeleteMessage, - getBase64FromMediaMessageDto, - LastMessage, - MarkChatUnreadDto, - NumberBusiness, - OnWhatsAppDto, - PrivacySettingDto, - ReadMessageDto, - SendPresenceDto, - UpdateMessageDto, - WhatsAppNumberDto, -} from '../../dto/chat.dto'; -import { - AcceptGroupInvite, - CreateGroupDto, - GetParticipant, - GroupDescriptionDto, - GroupInvite, - GroupJid, - GroupPictureDto, - GroupSendInvite, - GroupSubjectDto, - GroupToggleEphemeralDto, - GroupUpdateParticipantDto, - GroupUpdateSettingDto, -} from '../../dto/group.dto'; -import { InstanceDto, SetPresenceDto } from '../../dto/instance.dto'; -import { HandleLabelDto, LabelDto } from '../../dto/label.dto'; -import { - ContactMessage, - MediaMessage, - Options, - SendAudioDto, - SendContactDto, - SendListDto, - SendLocationDto, - SendMediaDto, - SendPollDto, - SendReactionDto, - SendStatusDto, - SendStickerDto, - SendTextDto, - StatusMessage, -} from '../../dto/sendMessage.dto'; -import { chatwootImport } from '../../integrations/chatwoot/utils/chatwoot-import-helper'; -import { SettingsRaw } from '../../models'; -import { ChatRaw } from '../../models/chat.model'; -import { ContactRaw } from '../../models/contact.model'; -import { MessageRaw, MessageUpdateRaw } from '../../models/message.model'; -import { RepositoryBroker } from '../../repository/repository.manager'; -import { waMonitor } from '../../server.module'; -import { Events, MessageSubtype, TypeMediaMessage, wa } from '../../types/wa.types'; -import { CacheService } from './../cache.service'; -import { ChannelStartupService } from './../channel.service'; - -export class BaileysStartupService extends ChannelStartupService { - constructor( - public readonly configService: ConfigService, - public readonly eventEmitter: EventEmitter2, - public readonly repository: RepositoryBroker, - public readonly cache: CacheService, - public readonly chatwootCache: CacheService, - public readonly messagesLostCache: CacheService, - ) { - super(configService, eventEmitter, repository, chatwootCache); - this.logger.verbose('BaileysStartupService initialized'); - this.cleanStore(); - this.instance.qrcode = { count: 0 }; - this.mobile = false; - this.recoveringMessages(); - } - - private readonly msgRetryCounterCache: CacheStore = new NodeCache(); - private readonly userDevicesCache: CacheStore = new NodeCache(); - private endSession = false; - private logBaileys = this.configService.get('LOG').BAILEYS; - - public stateConnection: wa.StateConnection = { state: 'close' }; - - public phoneNumber: string; - public mobile: boolean; - - private async recoveringMessages() { - this.logger.info('Recovering messages lost'); - const cacheConf = this.configService.get('CACHE'); - - if ((cacheConf?.REDIS?.ENABLED && cacheConf?.REDIS?.URI !== '') || cacheConf?.LOCAL?.ENABLED) { - setInterval(async () => { - this.messagesLostCache.keys().then((keys) => { - keys.forEach(async (key) => { - const message = await this.messagesLostCache.get(key.split(':')[2]); - - if (message.messageStubParameters && message.messageStubParameters[0] === 'Message absent from node') { - this.logger.info('Message absent from node, retrying to send, key: ' + key.split(':')[2]); - await this.client.sendMessageAck(JSON.parse(message.messageStubParameters[1], BufferJSON.reviver)); - } - }); - }); - }, 30000); - } - } - - public get connectionStatus() { - this.logger.verbose('Getting connection status'); - return this.stateConnection; - } - - public async logoutInstance() { - this.logger.verbose('logging out instance: ' + this.instanceName); - await this.client?.logout('Log out instance: ' + this.instanceName); - - this.logger.verbose('close connection instance: ' + this.instanceName); - this.client?.ws?.close(); - } - - public async getProfileName() { - this.logger.verbose('Getting profile name'); - - let profileName = this.client.user?.name ?? this.client.user?.verifiedName; - if (!profileName) { - this.logger.verbose('Profile name not found, trying to get from database'); - if (this.configService.get('DATABASE').ENABLED) { - this.logger.verbose('Database enabled, trying to get from database'); - const collection = dbserver - .getClient() - .db(this.configService.get('DATABASE').CONNECTION.DB_PREFIX_NAME + '-instances') - .collection(this.instanceName); - const data = await collection.findOne({ _id: 'creds' }); - if (data) { - this.logger.verbose('Profile name found in database'); - const creds = JSON.parse(JSON.stringify(data), BufferJSON.reviver); - profileName = creds.me?.name || creds.me?.verifiedName; - } - } else if (existsSync(join(INSTANCE_DIR, this.instanceName, 'creds.json'))) { - this.logger.verbose('Profile name found in file'); - const creds = JSON.parse( - readFileSync(join(INSTANCE_DIR, this.instanceName, 'creds.json'), { - encoding: 'utf-8', - }), - ); - profileName = creds.me?.name || creds.me?.verifiedName; - } - } - - this.logger.verbose(`Profile name: ${profileName}`); - return profileName; - } - - public async getProfileStatus() { - this.logger.verbose('Getting profile status'); - const status = await this.client.fetchStatus(this.instance.wuid); - - this.logger.verbose(`Profile status: ${status.status}`); - return status.status; - } - - public get profilePictureUrl() { - this.logger.verbose('Getting profile picture url'); - return this.instance.profilePictureUrl; - } - - public get qrCode(): wa.QrCode { - this.logger.verbose('Getting qrcode'); - - return { - pairingCode: this.instance.qrcode?.pairingCode, - code: this.instance.qrcode?.code, - base64: this.instance.qrcode?.base64, - count: this.instance.qrcode?.count, - }; - } - - private async connectionUpdate({ qr, connection, lastDisconnect }: Partial) { - this.logger.verbose('Connection update'); - if (qr) { - this.logger.verbose('QR code found'); - if (this.instance.qrcode.count === this.configService.get('QRCODE').LIMIT) { - this.logger.verbose('QR code limit reached'); - - this.logger.verbose('Sending data to webhook in event QRCODE_UPDATED'); - this.sendDataWebhook(Events.QRCODE_UPDATED, { - message: 'QR code limit reached, please login again', - statusCode: DisconnectReason.badSession, - }); - - if (this.localChatwoot.enabled) { - this.chatwootService.eventWhatsapp( - Events.QRCODE_UPDATED, - { instanceName: this.instance.name }, - { - message: 'QR code limit reached, please login again', - statusCode: DisconnectReason.badSession, - }, - ); - } - - this.logger.verbose('Sending data to webhook in event CONNECTION_UPDATE'); - this.sendDataWebhook(Events.CONNECTION_UPDATE, { - instance: this.instance.name, - state: 'refused', - statusReason: DisconnectReason.connectionClosed, - }); - - this.logger.verbose('endSession defined as true'); - this.endSession = true; - - this.logger.verbose('Emmiting event logout.instance'); - return this.eventEmitter.emit('no.connection', this.instance.name); - } - - this.logger.verbose('Incrementing QR code count'); - this.instance.qrcode.count++; - - const color = this.configService.get('QRCODE').COLOR; - - const optsQrcode: QRCodeToDataURLOptions = { - margin: 3, - scale: 4, - errorCorrectionLevel: 'H', - color: { light: '#ffffff', dark: color }, - }; - - if (this.phoneNumber) { - await delay(2000); - this.instance.qrcode.pairingCode = await this.client.requestPairingCode(this.phoneNumber); - } else { - this.instance.qrcode.pairingCode = null; - } - - this.logger.verbose('Generating QR code'); - qrcode.toDataURL(qr, optsQrcode, (error, base64) => { - if (error) { - this.logger.error('Qrcode generate failed:' + error.toString()); - return; - } - - this.instance.qrcode.base64 = base64; - this.instance.qrcode.code = qr; - - this.sendDataWebhook(Events.QRCODE_UPDATED, { - qrcode: { - instance: this.instance.name, - pairingCode: this.instance.qrcode.pairingCode, - code: qr, - base64, - }, - }); - - if (this.localChatwoot.enabled) { - this.chatwootService.eventWhatsapp( - Events.QRCODE_UPDATED, - { instanceName: this.instance.name }, - { - qrcode: { - instance: this.instance.name, - pairingCode: this.instance.qrcode.pairingCode, - code: qr, - base64, - }, - }, - ); - } - }); - - this.logger.verbose('Generating QR code in terminal'); - qrcodeTerminal.generate(qr, { small: true }, (qrcode) => - this.logger.log( - `\n{ instance: ${this.instance.name} pairingCode: ${this.instance.qrcode.pairingCode}, qrcodeCount: ${this.instance.qrcode.count} }\n` + - qrcode, - ), - ); - } - - if (connection) { - this.logger.verbose('Connection found'); - this.stateConnection = { - state: connection, - statusReason: (lastDisconnect?.error as Boom)?.output?.statusCode ?? 200, - }; - - this.logger.verbose('Sending data to webhook in event CONNECTION_UPDATE'); - this.sendDataWebhook(Events.CONNECTION_UPDATE, { - instance: this.instance.name, - ...this.stateConnection, - }); - } - - if (connection === 'close') { - this.logger.verbose('Connection closed'); - const shouldReconnect = (lastDisconnect.error as Boom)?.output?.statusCode !== DisconnectReason.loggedOut; - if (shouldReconnect) { - this.logger.verbose('Reconnecting to whatsapp'); - await this.connectToWhatsapp(); - } else { - this.logger.verbose('Do not reconnect to whatsapp'); - this.logger.verbose('Sending data to webhook in event STATUS_INSTANCE'); - this.sendDataWebhook(Events.STATUS_INSTANCE, { - instance: this.instance.name, - status: 'closed', - }); - - if (this.localChatwoot.enabled) { - this.chatwootService.eventWhatsapp( - Events.STATUS_INSTANCE, - { instanceName: this.instance.name }, - { - instance: this.instance.name, - status: 'closed', - }, - ); - } - - this.logger.verbose('Emittin event logout.instance'); - this.eventEmitter.emit('logout.instance', this.instance.name, 'inner'); - this.client?.ws?.close(); - this.client.end(new Error('Close connection')); - this.logger.verbose('Connection closed'); - } - } - - if (connection === 'open') { - this.logger.verbose('Connection opened'); - this.instance.wuid = this.client.user.id.replace(/:\d+/, ''); - this.instance.profilePictureUrl = (await this.profilePicture(this.instance.wuid)).profilePictureUrl; - const formattedWuid = this.instance.wuid.split('@')[0].padEnd(30, ' '); - const formattedName = this.instance.name; - this.logger.info( - ` - ┌──────────────────────────────┐ - │ CONNECTED TO WHATSAPP │ - └──────────────────────────────┘`.replace(/^ +/gm, ' '), - ); - this.logger.info( - ` - wuid: ${formattedWuid} - name: ${formattedName} - `, - ); - - if (this.localChatwoot.enabled) { - this.chatwootService.eventWhatsapp( - Events.CONNECTION_UPDATE, - { instanceName: this.instance.name }, - { - instance: this.instance.name, - status: 'open', - }, - ); - } - } - - if (connection === 'connecting') { - if (this.mobile) this.sendMobileCode(); - } - } - - private async getMessage(key: proto.IMessageKey, full = false) { - this.logger.verbose('Getting message with key: ' + JSON.stringify(key)); - try { - const webMessageInfo = (await this.repository.message.find({ - where: { owner: this.instance.name, key: { id: key.id } }, - })) as unknown as proto.IWebMessageInfo[]; - if (full) { - this.logger.verbose('Returning full message'); - return webMessageInfo[0]; - } - if (webMessageInfo[0].message?.pollCreationMessage) { - this.logger.verbose('Returning poll message'); - const messageSecretBase64 = webMessageInfo[0].message?.messageContextInfo?.messageSecret; - - if (typeof messageSecretBase64 === 'string') { - const messageSecret = Buffer.from(messageSecretBase64, 'base64'); - - const msg = { - messageContextInfo: { - messageSecret, - }, - pollCreationMessage: webMessageInfo[0].message?.pollCreationMessage, - }; - - return msg; - } - } - - this.logger.verbose('Returning message'); - return webMessageInfo[0].message; - } catch (error) { - return { conversation: '' }; - } - } - - private async defineAuthState() { - this.logger.verbose('Defining auth state'); - const db = this.configService.get('DATABASE'); - const cache = this.configService.get('CACHE'); - - if (cache?.REDIS.ENABLED && cache?.REDIS.SAVE_INSTANCES) { - this.logger.info('Redis enabled'); - return await useMultiFileAuthStateRedisDb(this.instance.name, this.cache); - } - - if (db.SAVE_DATA.INSTANCE && db.ENABLED) { - this.logger.verbose('Database enabled'); - return await useMultiFileAuthStateDb(this.instance.name); - } - - this.logger.verbose('Store file enabled'); - return await useMultiFileAuthState(join(INSTANCE_DIR, this.instance.name)); - } - - public async connectToWhatsapp(number?: string, mobile?: boolean): Promise { - this.logger.verbose('Connecting to whatsapp'); - try { - this.loadWebhook(); - this.loadChatwoot(); - this.loadSettings(); - this.loadWebsocket(); - this.loadRabbitmq(); - this.loadSqs(); - this.loadTypebot(); - this.loadProxy(); - this.loadChamaai(); - - this.instance.authState = await this.defineAuthState(); - - if (!mobile) { - this.mobile = false; - } else { - this.mobile = mobile; - } - - const session = this.configService.get('CONFIG_SESSION_PHONE'); - const browser: WABrowserDescription = [session.CLIENT, session.NAME, release()]; - this.logger.verbose('Browser: ' + JSON.stringify(browser)); - - let version; - let log; - - if (session.VERSION) { - version = session.VERSION.split(','); - log = `Baileys version env: ${version}`; - } else { - const baileysVersion = await fetchLatestBaileysVersion(); - version = baileysVersion.version; - log = `Baileys version: ${version}`; - } - - this.logger.info(log); - - let options; - - if (this.localProxy.enabled) { - this.logger.info('Proxy enabled: ' + this.localProxy.proxy?.host); - - if (this.localProxy?.proxy?.host?.includes('proxyscrape')) { - try { - const response = await axios.get(this.localProxy.proxy?.host); - const text = response.data; - const proxyUrls = text.split('\r\n'); - const rand = Math.floor(Math.random() * Math.floor(proxyUrls.length)); - const proxyUrl = 'http://' + proxyUrls[rand]; - options = { - agent: makeProxyAgent(proxyUrl), - fetchAgent: makeProxyAgent(proxyUrl), - }; - } catch (error) { - this.localProxy.enabled = false; - } - } else { - options = { - agent: makeProxyAgent(this.localProxy.proxy), - fetchAgent: makeProxyAgent(this.localProxy.proxy), - }; - } - } - - const socketConfig: UserFacingSocketConfig = { - ...options, - auth: { - creds: this.instance.authState.state.creds, - keys: makeCacheableSignalKeyStore(this.instance.authState.state.keys, P({ level: 'error' }) as any), - }, - logger: P({ level: this.logBaileys }), - printQRInTerminal: false, - mobile, - browser: number ? ['Chrome (Linux)', session.NAME, release()] : browser, - version, - markOnlineOnConnect: this.localSettings.always_online, - retryRequestDelayMs: 10, - connectTimeoutMs: 60_000, - qrTimeout: 40_000, - defaultQueryTimeoutMs: undefined, - emitOwnEvents: false, - shouldIgnoreJid: (jid) => { - const isGroupJid = this.localSettings.groups_ignore && isJidGroup(jid); - const isBroadcast = !this.localSettings.read_status && isJidBroadcast(jid); - - return isGroupJid || isBroadcast; - }, - msgRetryCounterCache: this.msgRetryCounterCache, - getMessage: async (key) => (await this.getMessage(key)) as Promise, - generateHighQualityLinkPreview: true, - syncFullHistory: this.localSettings.sync_full_history, - shouldSyncHistoryMessage: (msg: proto.Message.IHistorySyncNotification) => { - return this.historySyncNotification(msg); - }, - userDevicesCache: this.userDevicesCache, - transactionOpts: { maxCommitRetries: 10, delayBetweenTriesMs: 10 }, - patchMessageBeforeSending(message) { - if ( - message.deviceSentMessage?.message?.listMessage?.listType === - proto.Message.ListMessage.ListType.PRODUCT_LIST - ) { - message = JSON.parse(JSON.stringify(message)); - - message.deviceSentMessage.message.listMessage.listType = proto.Message.ListMessage.ListType.SINGLE_SELECT; - } - - if (message.listMessage?.listType == proto.Message.ListMessage.ListType.PRODUCT_LIST) { - message = JSON.parse(JSON.stringify(message)); - - message.listMessage.listType = proto.Message.ListMessage.ListType.SINGLE_SELECT; - } - - return message; - }, - }; - - this.endSession = false; - - this.logger.verbose('Creating socket'); - - this.client = makeWASocket(socketConfig); - - this.logger.verbose('Socket created'); - - this.eventHandler(); - - this.logger.verbose('Socket event handler initialized'); - - this.phoneNumber = number; - - return this.client; - } catch (error) { - this.logger.error(error); - throw new InternalServerErrorException(error?.toString()); - } - } - - private async sendMobileCode() { - const { registration } = this.client.authState.creds || null; - - let phoneNumber = registration.phoneNumber || this.phoneNumber; - - if (!phoneNumber.startsWith('+')) { - phoneNumber = '+' + phoneNumber; - } - - if (!phoneNumber) { - this.logger.error('Phone number not found'); - return; - } - - console.log('phoneNumber', phoneNumber); - - const parsedPhoneNumber = parsePhoneNumber(phoneNumber); - - console.log('parsedPhoneNumber', parsedPhoneNumber); - - if (!parsedPhoneNumber?.isValid()) { - this.logger.error('Phone number invalid'); - return; - } - - registration.phoneNumber = parsedPhoneNumber.format('E.164'); - registration.phoneNumberCountryCode = parsedPhoneNumber.countryCallingCode; - registration.phoneNumberNationalNumber = parsedPhoneNumber.nationalNumber; - - const mcc = await PHONENUMBER_MCC[parsedPhoneNumber.countryCallingCode]; - if (!mcc) { - this.logger.error('MCC not found'); - return; - } - - registration.phoneNumberMobileCountryCode = mcc; - registration.method = 'sms'; - - try { - const response = await this.client.requestRegistrationCode(registration); - - console.log('response', response); - if (['ok', 'sent'].includes(response?.status)) { - this.logger.verbose('Registration code sent successfully'); - - return response; - } - } catch (error) { - this.logger.error(error); - } - } - - public async receiveMobileCode(code: string) { - await this.client - .register(code.replace(/["']/g, '').trim().toLowerCase()) - .then(async (response) => { - this.logger.verbose('Registration code received successfully'); - console.log(response); - }) - .catch((error) => { - this.logger.error(error); - }); - } - - public async reloadConnection(): Promise { - try { - this.instance.authState = await this.defineAuthState(); - - const session = this.configService.get('CONFIG_SESSION_PHONE'); - const browser: WABrowserDescription = [session.CLIENT, session.NAME, release()]; - - let version; - let log; - - if (session.VERSION) { - version = session.VERSION.split(','); - log = `Baileys version env: ${version}`; - } else { - const baileysVersion = await fetchLatestBaileysVersion(); - version = baileysVersion.version; - log = `Baileys version: ${version}`; - } - - this.logger.info(log); - - let options; - - if (this.localProxy.enabled) { - this.logger.info('Proxy enabled: ' + this.localProxy.proxy?.host); - - if (this.localProxy?.proxy?.host?.includes('proxyscrape')) { - try { - const response = await axios.get(this.localProxy.proxy?.host); - const text = response.data; - const proxyUrls = text.split('\r\n'); - const rand = Math.floor(Math.random() * Math.floor(proxyUrls.length)); - const proxyUrl = 'http://' + proxyUrls[rand]; - options = { - agent: makeProxyAgent(proxyUrl), - fetchAgent: makeProxyAgent(proxyUrl), - }; - } catch (error) { - this.localProxy.enabled = false; - } - } else { - options = { - agent: makeProxyAgent(this.localProxy.proxy), - fetchAgent: makeProxyAgent(this.localProxy.proxy), - }; - } - } - - const socketConfig: UserFacingSocketConfig = { - ...options, - auth: { - creds: this.instance.authState.state.creds, - keys: makeCacheableSignalKeyStore(this.instance.authState.state.keys, P({ level: 'error' }) as any), - }, - logger: P({ level: this.logBaileys }), - printQRInTerminal: false, - browser: this.phoneNumber ? ['Chrome (Linux)', session.NAME, release()] : browser, - version, - markOnlineOnConnect: this.localSettings.always_online, - retryRequestDelayMs: 10, - connectTimeoutMs: 60_000, - qrTimeout: 40_000, - defaultQueryTimeoutMs: undefined, - emitOwnEvents: false, - shouldIgnoreJid: (jid) => { - const isGroupJid = this.localSettings.groups_ignore && isJidGroup(jid); - const isBroadcast = !this.localSettings.read_status && isJidBroadcast(jid); - - return isGroupJid || isBroadcast; - }, - msgRetryCounterCache: this.msgRetryCounterCache, - getMessage: async (key) => (await this.getMessage(key)) as Promise, - generateHighQualityLinkPreview: true, - syncFullHistory: this.localSettings.sync_full_history, - shouldSyncHistoryMessage: (msg: proto.Message.IHistorySyncNotification) => { - return this.historySyncNotification(msg); - }, - userDevicesCache: this.userDevicesCache, - transactionOpts: { maxCommitRetries: 10, delayBetweenTriesMs: 10 }, - patchMessageBeforeSending(message) { - if ( - message.deviceSentMessage?.message?.listMessage?.listType === - proto.Message.ListMessage.ListType.PRODUCT_LIST - ) { - message = JSON.parse(JSON.stringify(message)); - - message.deviceSentMessage.message.listMessage.listType = proto.Message.ListMessage.ListType.SINGLE_SELECT; - } - - if (message.listMessage?.listType == proto.Message.ListMessage.ListType.PRODUCT_LIST) { - message = JSON.parse(JSON.stringify(message)); - - message.listMessage.listType = proto.Message.ListMessage.ListType.SINGLE_SELECT; - } - - return message; - }, - }; - - this.client = makeWASocket(socketConfig); - - return this.client; - } catch (error) { - this.logger.error(error); - throw new InternalServerErrorException(error?.toString()); - } - } - - private readonly chatHandle = { - 'chats.upsert': async (chats: Chat[], database: Database) => { - this.logger.verbose('Event received: chats.upsert'); - - this.logger.verbose('Finding chats in database'); - const chatsRepository = await this.repository.chat.find({ - where: { owner: this.instance.name }, - }); - - this.logger.verbose('Verifying if chats exists in database to insert'); - const chatsRaw: ChatRaw[] = []; - for await (const chat of chats) { - if (chatsRepository.find((cr) => cr.id === chat.id)) { - continue; - } - - chatsRaw.push({ id: chat.id, owner: this.instance.wuid }); - } - - this.logger.verbose('Sending data to webhook in event CHATS_UPSERT'); - this.sendDataWebhook(Events.CHATS_UPSERT, chatsRaw); - - this.logger.verbose('Inserting chats in database'); - this.repository.chat.insert(chatsRaw, this.instance.name, database.SAVE_DATA.CHATS); - }, - - 'chats.update': async ( - chats: Partial< - proto.IConversation & { - lastMessageRecvTimestamp?: number; - } & { - conditional: (bufferedData: BufferedEventData) => boolean; - } - >[], - ) => { - this.logger.verbose('Event received: chats.update'); - const chatsRaw: ChatRaw[] = chats.map((chat) => { - return { id: chat.id, owner: this.instance.wuid }; - }); - - this.logger.verbose('Sending data to webhook in event CHATS_UPDATE'); - this.sendDataWebhook(Events.CHATS_UPDATE, chatsRaw); - }, - - 'chats.delete': async (chats: string[]) => { - this.logger.verbose('Event received: chats.delete'); - - this.logger.verbose('Deleting chats in database'); - chats.forEach( - async (chat) => - await this.repository.chat.delete({ - where: { owner: this.instance.name, id: chat }, - }), - ); - - this.logger.verbose('Sending data to webhook in event CHATS_DELETE'); - this.sendDataWebhook(Events.CHATS_DELETE, [...chats]); - }, - }; - - private readonly contactHandle = { - 'contacts.upsert': async (contacts: Contact[], database: Database) => { - try { - this.logger.verbose('Event received: contacts.upsert'); - - this.logger.verbose('Finding contacts in database'); - const contactsRepository = new Set( - ( - await this.repository.contact.find({ - select: { id: 1, _id: 0 }, - where: { owner: this.instance.name }, - }) - ).map((contact) => contact.id), - ); - - this.logger.verbose('Verifying if contacts exists in database to insert'); - let contactsRaw: ContactRaw[] = []; - - for (const contact of contacts) { - if (contactsRepository.has(contact.id)) { - continue; - } - - contactsRaw.push({ - id: contact.id, - pushName: contact?.name || contact?.verifiedName || contact.id.split('@')[0], - profilePictureUrl: null, - owner: this.instance.name, - }); - } - - this.logger.verbose('Sending data to webhook in event CONTACTS_UPSERT'); - if (contactsRaw.length > 0) this.sendDataWebhook(Events.CONTACTS_UPSERT, contactsRaw); - - this.logger.verbose('Inserting contacts in database'); - this.repository.contact.insert(contactsRaw, this.instance.name, database.SAVE_DATA.CONTACTS); - - if (this.localChatwoot.enabled && this.localChatwoot.import_contacts && contactsRaw.length) { - this.chatwootService.addHistoryContacts({ instanceName: this.instance.name }, contactsRaw); - chatwootImport.importHistoryContacts({ instanceName: this.instance.name }, this.localChatwoot); - } - - // Update profile pictures - contactsRaw = []; - for await (const contact of contacts) { - contactsRaw.push({ - id: contact.id, - pushName: contact?.name || contact?.verifiedName || contact.id.split('@')[0], - profilePictureUrl: (await this.profilePicture(contact.id)).profilePictureUrl, - owner: this.instance.name, - }); - } - - this.logger.verbose('Sending data to webhook in event CONTACTS_UPDATE'); - if (contactsRaw.length > 0) this.sendDataWebhook(Events.CONTACTS_UPSERT, contactsRaw); - - this.logger.verbose('Updating contacts in database'); - this.repository.contact.update(contactsRaw, this.instance.name, database.SAVE_DATA.CONTACTS); - } catch (error) { - this.logger.error(error); - } - }, - - 'contacts.update': async (contacts: Partial[], database: Database) => { - this.logger.verbose('Event received: contacts.update'); - - this.logger.verbose('Verifying if contacts exists in database to update'); - const contactsRaw: ContactRaw[] = []; - for await (const contact of contacts) { - contactsRaw.push({ - id: contact.id, - pushName: contact?.name ?? contact?.verifiedName, - profilePictureUrl: (await this.profilePicture(contact.id)).profilePictureUrl, - owner: this.instance.name, - }); - } - - this.logger.verbose('Sending data to webhook in event CONTACTS_UPDATE'); - this.sendDataWebhook(Events.CONTACTS_UPDATE, contactsRaw); - - this.logger.verbose('Updating contacts in database'); - this.repository.contact.update(contactsRaw, this.instance.name, database.SAVE_DATA.CONTACTS); - }, - }; - - private readonly messageHandle = { - 'messaging-history.set': async ( - { - messages, - chats, - contacts, - }: { - chats: Chat[]; - contacts: Contact[]; - messages: proto.IWebMessageInfo[]; - isLatest: boolean; - }, - database: Database, - ) => { - try { - this.logger.verbose('Event received: messaging-history.set'); - - const instance: InstanceDto = { instanceName: this.instance.name }; - - const daysLimitToImport = this.localChatwoot.enabled ? this.localChatwoot.days_limit_import_messages : 1000; - this.logger.verbose(`Param days limit import messages is: ${daysLimitToImport}`); - - const date = new Date(); - const timestampLimitToImport = new Date(date.setDate(date.getDate() - daysLimitToImport)).getTime() / 1000; - - const maxBatchTimestamp = Math.max(...messages.map((message) => message.messageTimestamp as number)); - - const processBatch = maxBatchTimestamp >= timestampLimitToImport; - - if (!processBatch) { - this.logger.verbose('Batch ignored by maxTimestamp in this batch'); - return; - } - - const chatsRaw: ChatRaw[] = []; - const chatsRepository = new Set( - ( - await this.repository.chat.find({ - select: { id: 1, _id: 0 }, - where: { owner: this.instance.name }, - }) - ).map((chat) => chat.id), - ); - - for (const chat of chats) { - if (chatsRepository.has(chat.id)) { - continue; - } - - chatsRaw.push({ - id: chat.id, - owner: this.instance.name, - lastMsgTimestamp: chat.lastMessageRecvTimestamp, - }); - } - - this.logger.verbose('Sending data to webhook in event CHATS_SET'); - this.sendDataWebhook(Events.CHATS_SET, chatsRaw); - - this.logger.verbose('Inserting chats in database'); - this.repository.chat.insert(chatsRaw, this.instance.name, database.SAVE_DATA.CHATS); - - const messagesRaw: MessageRaw[] = []; - const messagesRepository = new Set( - chatwootImport.getRepositoryMessagesCache(instance) ?? - ( - await this.repository.message.find({ - select: { key: { id: 1 }, _id: 0 }, - where: { owner: this.instance.name }, - }) - ).map((message) => message.key.id), - ); - - if (chatwootImport.getRepositoryMessagesCache(instance) === null) { - chatwootImport.setRepositoryMessagesCache(instance, messagesRepository); - } - - for (const m of messages) { - if (!m.message || !m.key || !m.messageTimestamp) { - continue; - } - - if (Long.isLong(m?.messageTimestamp)) { - m.messageTimestamp = m.messageTimestamp?.toNumber(); - } - - if (m.messageTimestamp <= timestampLimitToImport) { - continue; - } - - if (messagesRepository.has(m.key.id)) { - continue; - } - - const status: Record = { - 0: 'ERROR', - 1: 'PENDING', - 2: 'SERVER_ACK', - 3: 'DELIVERY_ACK', - 4: 'READ', - 5: 'PLAYED', - }; - - messagesRaw.push({ - key: m.key, - pushName: m.pushName || m.key.remoteJid.split('@')[0], - participant: m.participant, - message: { ...m.message }, - messageType: getContentType(m.message), - messageTimestamp: m.messageTimestamp as number, - owner: this.instance.name, - status: m.status ? status[m.status] : null, - }); - } - - this.logger.verbose('Sending data to webhook in event MESSAGES_SET'); - this.sendDataWebhook(Events.MESSAGES_SET, [...messagesRaw]); - - this.logger.verbose('Inserting messages in database'); - await this.repository.message.insert(messagesRaw, this.instance.name, database.SAVE_DATA.NEW_MESSAGE); - - if (this.localChatwoot.enabled && this.localChatwoot.import_messages && messagesRaw.length > 0) { - this.chatwootService.addHistoryMessages( - instance, - messagesRaw.filter((msg) => !chatwootImport.isIgnorePhoneNumber(msg.key?.remoteJid)), - ); - } - - await this.contactHandle['contacts.upsert']( - contacts - .filter((c) => !!c.notify ?? !!c.name) - .map((c) => ({ - id: c.id, - name: c.name ?? c.notify, - })), - database, - ); - - contacts = undefined; - messages = undefined; - chats = undefined; - } catch (error) { - this.logger.error(error); - } - }, - - 'messages.upsert': async ( - { - messages, - type, - }: { - messages: proto.IWebMessageInfo[]; - type: MessageUpsertType; - }, - database: Database, - settings: SettingsRaw, - ) => { - try { - this.logger.verbose('Event received: messages.upsert'); - for (const received of messages) { - if ( - this.localChatwoot.enabled && - (received.message?.protocolMessage?.editedMessage || received.message?.editedMessage?.message) - ) { - const editedMessage = - received.message?.protocolMessage || received.message?.editedMessage?.message?.protocolMessage; - if (editedMessage) { - this.chatwootService.eventWhatsapp('messages.edit', { instanceName: this.instance.name }, editedMessage); - } - } - - if (received.messageStubParameters && received.messageStubParameters[0] === 'Message absent from node') { - this.logger.info('Recovering message lost'); - - await this.messagesLostCache.set(received.key.id, received); - continue; - } - - const retryCache = (await this.messagesLostCache.get(received.key.id)) || null; - - if (retryCache) { - this.logger.info('Recovered message lost'); - await this.messagesLostCache.delete(received.key.id); - } - - if ( - (type !== 'notify' && type !== 'append') || - received.message?.protocolMessage || - received.message?.pollUpdateMessage || - !received?.message - ) { - this.logger.verbose('message rejected'); - return; - } - - if (Long.isLong(received.messageTimestamp)) { - received.messageTimestamp = received.messageTimestamp?.toNumber(); - } - - if (settings?.groups_ignore && received.key.remoteJid.includes('@g.us')) { - this.logger.verbose('group ignored'); - return; - } - - let messageRaw: MessageRaw; - - const isMedia = - received?.message?.imageMessage || - received?.message?.videoMessage || - received?.message?.stickerMessage || - received?.message?.documentMessage || - received?.message?.audioMessage; - - const contentMsg = received?.message[getContentType(received.message)] as any; - - if (this.localWebhook.webhook_base64 === true && isMedia) { - const buffer = await downloadMediaMessage( - { key: received.key, message: received?.message }, - 'buffer', - {}, - { - logger: P({ level: 'error' }) as any, - reuploadRequest: this.client.updateMediaMessage, - }, - ); - messageRaw = { - key: received.key, - pushName: received.pushName, - message: { - ...received.message, - base64: buffer ? buffer.toString('base64') : undefined, - }, - contextInfo: contentMsg?.contextInfo, - messageType: getContentType(received.message), - messageTimestamp: received.messageTimestamp as number, - owner: this.instance.name, - source: getDevice(received.key.id), - }; - } else { - messageRaw = { - key: received.key, - pushName: received.pushName, - message: { ...received.message }, - contextInfo: contentMsg?.contextInfo, - messageType: getContentType(received.message), - messageTimestamp: received.messageTimestamp as number, - owner: this.instance.name, - source: getDevice(received.key.id), - }; - } - - if (this.localSettings.read_messages && received.key.id !== 'status@broadcast') { - await this.client.readMessages([received.key]); - } - - if (this.localSettings.read_status && received.key.id === 'status@broadcast') { - await this.client.readMessages([received.key]); - } - - this.logger.log(messageRaw); - - this.logger.verbose('Sending data to webhook in event MESSAGES_UPSERT'); - this.sendDataWebhook(Events.MESSAGES_UPSERT, messageRaw); - - if (this.localChatwoot.enabled && !received.key.id.includes('@broadcast')) { - const chatwootSentMessage = await this.chatwootService.eventWhatsapp( - Events.MESSAGES_UPSERT, - { instanceName: this.instance.name }, - messageRaw, - ); - - if (chatwootSentMessage?.id) { - messageRaw.chatwoot = { - messageId: chatwootSentMessage.id, - inboxId: chatwootSentMessage.inbox_id, - conversationId: chatwootSentMessage.conversation_id, - }; - } - } - - const typebotSessionRemoteJid = this.localTypebot.sessions?.find( - (session) => session.remoteJid === received.key.remoteJid, - ); - - if ((this.localTypebot.enabled && type === 'notify') || typebotSessionRemoteJid) { - if (!(this.localTypebot.listening_from_me === false && messageRaw.key.fromMe === true)) { - if (messageRaw.messageType !== 'reactionMessage') - await this.typebotService.sendTypebot( - { instanceName: this.instance.name }, - messageRaw.key.remoteJid, - messageRaw, - ); - } - } - - if (this.localChamaai.enabled && messageRaw.key.fromMe === false && type === 'notify') { - await this.chamaaiService.sendChamaai( - { instanceName: this.instance.name }, - messageRaw.key.remoteJid, - messageRaw, - ); - } - - this.logger.verbose('Inserting message in database'); - await this.repository.message.insert([messageRaw], this.instance.name, database.SAVE_DATA.NEW_MESSAGE); - - this.logger.verbose('Verifying contact from message'); - const contact = await this.repository.contact.find({ - where: { owner: this.instance.name, id: received.key.remoteJid }, - }); - - const contactRaw: ContactRaw = { - id: received.key.remoteJid, - pushName: received.pushName, - profilePictureUrl: (await this.profilePicture(received.key.remoteJid)).profilePictureUrl, - owner: this.instance.name, - }; - - if (contactRaw.id === 'status@broadcast') { - this.logger.verbose('Contact is status@broadcast'); - return; - } - - if (contact?.length) { - this.logger.verbose('Contact found in database'); - const contactRaw: ContactRaw = { - id: received.key.remoteJid, - pushName: contact[0].pushName, - profilePictureUrl: (await this.profilePicture(received.key.remoteJid)).profilePictureUrl, - owner: this.instance.name, - }; - - this.logger.verbose('Sending data to webhook in event CONTACTS_UPDATE'); - this.sendDataWebhook(Events.CONTACTS_UPDATE, contactRaw); - - if (this.localChatwoot.enabled) { - await this.chatwootService.eventWhatsapp( - Events.CONTACTS_UPDATE, - { instanceName: this.instance.name }, - contactRaw, - ); - } - - this.logger.verbose('Updating contact in database'); - await this.repository.contact.update([contactRaw], this.instance.name, database.SAVE_DATA.CONTACTS); - return; - } - - this.logger.verbose('Contact not found in database'); - - this.logger.verbose('Sending data to webhook in event CONTACTS_UPSERT'); - this.sendDataWebhook(Events.CONTACTS_UPSERT, contactRaw); - - this.logger.verbose('Inserting contact in database'); - this.repository.contact.insert([contactRaw], this.instance.name, database.SAVE_DATA.CONTACTS); - } - } catch (error) { - this.logger.error(error); - } - }, - - 'messages.update': async (args: WAMessageUpdate[], database: Database, settings: SettingsRaw) => { - this.logger.verbose('Event received: messages.update'); - const status: Record = { - 0: 'ERROR', - 1: 'PENDING', - 2: 'SERVER_ACK', - 3: 'DELIVERY_ACK', - 4: 'READ', - 5: 'PLAYED', - }; - for await (const { key, update } of args) { - if (settings?.groups_ignore && key.remoteJid?.includes('@g.us')) { - this.logger.verbose('group ignored'); - return; - } - - if (status[update.status] === 'READ' && key.fromMe) { - if (this.localChatwoot.enabled) { - this.chatwootService.eventWhatsapp('messages.read', { instanceName: this.instance.name }, { key: key }); - } - } - - if (key.remoteJid !== 'status@broadcast') { - this.logger.verbose('Message update is valid'); - - let pollUpdates: any; - if (update.pollUpdates) { - this.logger.verbose('Poll update found'); - - this.logger.verbose('Getting poll message'); - const pollCreation = await this.getMessage(key); - this.logger.verbose(pollCreation); - - if (pollCreation) { - this.logger.verbose('Getting aggregate votes in poll message'); - pollUpdates = getAggregateVotesInPollMessage({ - message: pollCreation as proto.IMessage, - pollUpdates: update.pollUpdates, - }); - } - } - - if (status[update.status] === 'READ' && !key.fromMe) return; - - if (update.message === null && update.status === undefined) { - this.logger.verbose('Message deleted'); - - this.logger.verbose('Sending data to webhook in event MESSAGE_DELETE'); - this.sendDataWebhook(Events.MESSAGES_DELETE, key); - - const message: MessageUpdateRaw = { - ...key, - status: 'DELETED', - datetime: Date.now(), - owner: this.instance.name, - }; - - this.logger.verbose(message); - - this.logger.verbose('Inserting message in database'); - await this.repository.messageUpdate.insert( - [message], - this.instance.name, - database.SAVE_DATA.MESSAGE_UPDATE, - ); - - if (this.localChatwoot.enabled) { - this.chatwootService.eventWhatsapp( - Events.MESSAGES_DELETE, - { instanceName: this.instance.name }, - { key: key }, - ); - } - - return; - } - - const message: MessageUpdateRaw = { - ...key, - status: status[update.status], - datetime: Date.now(), - owner: this.instance.name, - pollUpdates, - }; - - this.logger.verbose(message); - - this.logger.verbose('Sending data to webhook in event MESSAGES_UPDATE'); - this.sendDataWebhook(Events.MESSAGES_UPDATE, message); - - this.logger.verbose('Inserting message in database'); - this.repository.messageUpdate.insert([message], this.instance.name, database.SAVE_DATA.MESSAGE_UPDATE); - } - } - }, - }; - - private readonly groupHandler = { - 'groups.upsert': (groupMetadata: GroupMetadata[]) => { - this.logger.verbose('Event received: groups.upsert'); - - this.logger.verbose('Sending data to webhook in event GROUPS_UPSERT'); - this.sendDataWebhook(Events.GROUPS_UPSERT, groupMetadata); - }, - - 'groups.update': (groupMetadataUpdate: Partial[]) => { - this.logger.verbose('Event received: groups.update'); - - this.logger.verbose('Sending data to webhook in event GROUPS_UPDATE'); - this.sendDataWebhook(Events.GROUPS_UPDATE, groupMetadataUpdate); - }, - - 'group-participants.update': (participantsUpdate: { - id: string; - participants: string[]; - action: ParticipantAction; - }) => { - this.logger.verbose('Event received: group-participants.update'); - - this.logger.verbose('Sending data to webhook in event GROUP_PARTICIPANTS_UPDATE'); - this.sendDataWebhook(Events.GROUP_PARTICIPANTS_UPDATE, participantsUpdate); - }, - }; - - private readonly labelHandle = { - [Events.LABELS_EDIT]: async (label: Label, database: Database) => { - this.logger.verbose('Event received: labels.edit'); - this.logger.verbose('Finding labels in database'); - const labelsRepository = await this.repository.labels.find({ - where: { owner: this.instance.name }, - }); - - const savedLabel = labelsRepository.find((l) => l.id === label.id); - if (label.deleted && savedLabel) { - this.logger.verbose('Sending data to webhook in event LABELS_EDIT'); - await this.repository.labels.delete({ - where: { owner: this.instance.name, id: label.id }, - }); - this.sendDataWebhook(Events.LABELS_EDIT, { ...label, instance: this.instance.name }); - return; - } - - const labelName = label.name.replace(/[^\x20-\x7E]/g, ''); - if (!savedLabel || savedLabel.color !== label.color || savedLabel.name !== labelName) { - this.logger.verbose('Sending data to webhook in event LABELS_EDIT'); - await this.repository.labels.insert( - { - color: label.color, - name: labelName, - owner: this.instance.name, - id: label.id, - predefinedId: label.predefinedId, - }, - this.instance.name, - database.SAVE_DATA.LABELS, - ); - this.sendDataWebhook(Events.LABELS_EDIT, { ...label, instance: this.instance.name }); - } - }, - - [Events.LABELS_ASSOCIATION]: async ( - data: { association: LabelAssociation; type: 'remove' | 'add' }, - database: Database, - ) => { - this.logger.verbose('Sending data to webhook in event LABELS_ASSOCIATION'); - - // Atualiza labels nos chats - if (database.SAVE_DATA.CHATS) { - const chats = await this.repository.chat.find({ - where: { - owner: this.instance.name, - }, - }); - const chat = chats.find((c) => c.id === data.association.chatId); - if (chat) { - let labels = [...chat.labels]; - if (data.type === 'remove') { - labels = labels.filter((label) => label !== data.association.labelId); - } else if (data.type === 'add') { - labels = [...labels, data.association.labelId]; - } - await this.repository.chat.update( - [{ id: chat.id, owner: this.instance.name, labels }], - this.instance.name, - database.SAVE_DATA.CHATS, - ); - } - } - - // Envia dados para o webhook - this.sendDataWebhook(Events.LABELS_ASSOCIATION, { - instance: this.instance.name, - type: data.type, - chatId: data.association.chatId, - labelId: data.association.labelId, - }); - }, - }; - - private eventHandler() { - this.logger.verbose('Initializing event handler'); - this.client.ev.process(async (events) => { - if (!this.endSession) { - this.logger.verbose(`Event received: ${Object.keys(events).join(', ')}`); - const database = this.configService.get('DATABASE'); - const settings = await this.findSettings(); - - if (events.call) { - this.logger.verbose('Listening event: call'); - const call = events.call[0]; - - if (settings?.reject_call && call.status == 'offer') { - this.logger.verbose('Rejecting call'); - this.client.rejectCall(call.id, call.from); - } - - if (settings?.msg_call?.trim().length > 0 && call.status == 'offer') { - this.logger.verbose('Sending message in call'); - const msg = await this.client.sendMessage(call.from, { - text: settings.msg_call, - }); - - this.logger.verbose('Sending data to event messages.upsert'); - this.client.ev.emit('messages.upsert', { - messages: [msg], - type: 'notify', - }); - } - - this.logger.verbose('Sending data to webhook in event CALL'); - this.sendDataWebhook(Events.CALL, call); - } - - if (events['connection.update']) { - this.logger.verbose('Listening event: connection.update'); - this.connectionUpdate(events['connection.update']); - } - - if (events['creds.update']) { - this.logger.verbose('Listening event: creds.update'); - this.instance.authState.saveCreds(); - } - - if (events['messaging-history.set']) { - this.logger.verbose('Listening event: messaging-history.set'); - const payload = events['messaging-history.set']; - this.messageHandle['messaging-history.set'](payload, database); - } - - if (events['messages.upsert']) { - this.logger.verbose('Listening event: messages.upsert'); - const payload = events['messages.upsert']; - this.messageHandle['messages.upsert'](payload, database, settings); - } - - if (events['messages.update']) { - this.logger.verbose('Listening event: messages.update'); - const payload = events['messages.update']; - this.messageHandle['messages.update'](payload, database, settings); - } - - if (events['presence.update']) { - this.logger.verbose('Listening event: presence.update'); - const payload = events['presence.update']; - - if (settings.groups_ignore && payload.id.includes('@g.us')) { - this.logger.verbose('group ignored'); - return; - } - this.sendDataWebhook(Events.PRESENCE_UPDATE, payload); - } - - if (!settings?.groups_ignore) { - if (events['groups.upsert']) { - this.logger.verbose('Listening event: groups.upsert'); - const payload = events['groups.upsert']; - this.groupHandler['groups.upsert'](payload); - } - - if (events['groups.update']) { - this.logger.verbose('Listening event: groups.update'); - const payload = events['groups.update']; - this.groupHandler['groups.update'](payload); - } - - if (events['group-participants.update']) { - this.logger.verbose('Listening event: group-participants.update'); - const payload = events['group-participants.update']; - this.groupHandler['group-participants.update'](payload); - } - } - - if (events['chats.upsert']) { - this.logger.verbose('Listening event: chats.upsert'); - const payload = events['chats.upsert']; - this.chatHandle['chats.upsert'](payload, database); - } - - if (events['chats.update']) { - this.logger.verbose('Listening event: chats.update'); - const payload = events['chats.update']; - this.chatHandle['chats.update'](payload); - } - - if (events['chats.delete']) { - this.logger.verbose('Listening event: chats.delete'); - const payload = events['chats.delete']; - this.chatHandle['chats.delete'](payload); - } - - if (events['contacts.upsert']) { - this.logger.verbose('Listening event: contacts.upsert'); - const payload = events['contacts.upsert']; - this.contactHandle['contacts.upsert'](payload, database); - } - - if (events['contacts.update']) { - this.logger.verbose('Listening event: contacts.update'); - const payload = events['contacts.update']; - this.contactHandle['contacts.update'](payload, database); - } - - if (events[Events.LABELS_ASSOCIATION]) { - this.logger.verbose('Listening event: labels.association'); - const payload = events[Events.LABELS_ASSOCIATION]; - this.labelHandle[Events.LABELS_ASSOCIATION](payload, database); - return; - } - - if (events[Events.LABELS_EDIT]) { - this.logger.verbose('Listening event: labels.edit'); - const payload = events[Events.LABELS_EDIT]; - this.labelHandle[Events.LABELS_EDIT](payload, database); - return; - } - } - }); - } - - private historySyncNotification(msg: proto.Message.IHistorySyncNotification) { - const instance: InstanceDto = { instanceName: this.instance.name }; - - if ( - this.localChatwoot.enabled && - this.localChatwoot.import_messages && - this.isSyncNotificationFromUsedSyncType(msg) - ) { - if (msg.chunkOrder === 1) { - this.chatwootService.startImportHistoryMessages(instance); - } - - if (msg.progress === 100) { - setTimeout(() => { - this.chatwootService.importHistoryMessages(instance); - }, 10000); - } - } - - return true; - } - - private isSyncNotificationFromUsedSyncType(msg: proto.Message.IHistorySyncNotification) { - return ( - (this.localSettings.sync_full_history && msg?.syncType === 2) || - (!this.localSettings.sync_full_history && msg?.syncType === 3) - ); - } - - public async profilePicture(number: string) { - const jid = this.createJid(number); - - this.logger.verbose('Getting profile picture with jid: ' + jid); - try { - this.logger.verbose('Getting profile picture url'); - return { - wuid: jid, - profilePictureUrl: await this.client.profilePictureUrl(jid, 'image'), - }; - } catch (error) { - this.logger.verbose('Profile picture not found'); - return { - wuid: jid, - profilePictureUrl: null, - }; - } - } - - public async getStatus(number: string) { - const jid = this.createJid(number); - - this.logger.verbose('Getting profile status with jid:' + jid); - try { - this.logger.verbose('Getting status'); - return { - wuid: jid, - status: (await this.client.fetchStatus(jid))?.status, - }; - } catch (error) { - this.logger.verbose('Status not found'); - return { - wuid: jid, - status: null, - }; - } - } - - public async fetchProfile(instanceName: string, number?: string) { - const jid = number ? this.createJid(number) : this.client?.user?.id; - - const onWhatsapp = (await this.whatsappNumber({ numbers: [jid] }))?.shift(); - - if (!onWhatsapp.exists) { - throw new BadRequestException(onWhatsapp); - } - - this.logger.verbose('Getting profile with jid: ' + jid); - try { - this.logger.verbose('Getting profile info'); - - if (number) { - const info = (await this.whatsappNumber({ numbers: [jid] }))?.shift(); - const picture = await this.profilePicture(info?.jid); - const status = await this.getStatus(info?.jid); - const business = await this.fetchBusinessProfile(info?.jid); - - return { - wuid: info?.jid || jid, - name: info?.name, - numberExists: info?.exists, - picture: picture?.profilePictureUrl, - status: status?.status, - isBusiness: business.isBusiness, - email: business?.email, - description: business?.description, - website: business?.website?.shift(), - }; - } else { - const info = await waMonitor.instanceInfo(instanceName); - const business = await this.fetchBusinessProfile(jid); - - return { - wuid: jid, - name: info?.instance?.profileName, - numberExists: true, - picture: info?.instance?.profilePictureUrl, - status: info?.instance?.profileStatus, - isBusiness: business.isBusiness, - email: business?.email, - description: business?.description, - website: business?.website?.shift(), - }; - } - } catch (error) { - this.logger.verbose('Profile not found'); - return { - wuid: jid, - name: null, - picture: null, - status: null, - os: null, - isBusiness: false, - }; - } - } - - private async sendMessageWithTyping( - number: string, - message: T, - options?: Options, - isChatwoot = false, - ) { - this.logger.verbose('Sending message with typing'); - - this.logger.verbose(`Check if number "${number}" is WhatsApp`); - const isWA = (await this.whatsappNumber({ numbers: [number] }))?.shift(); - - this.logger.verbose(`Exists: "${isWA.exists}" | jid: ${isWA.jid}`); - - if (!isWA.exists && !isJidGroup(isWA.jid) && !isWA.jid.includes('@broadcast')) { - if (this.localChatwoot.enabled) { - const body = { - key: { remoteJid: isWA.jid }, - }; - - this.chatwootService.eventWhatsapp('contact.is_not_in_wpp', { instanceName: this.instance.name }, body); - } - throw new BadRequestException(isWA); - } - - const sender = isWA.jid; - - try { - if (options?.delay) { - this.logger.verbose('Delaying message'); - - if (options.delay > 20000) { - let remainingDelay = options.delay; - while (remainingDelay > 20000) { - await this.client.presenceSubscribe(sender); - - await this.client.sendPresenceUpdate((options.presence as WAPresence) ?? 'composing', sender); - - await delay(20000); - - await this.client.sendPresenceUpdate('paused', sender); - - remainingDelay -= 20000; - } - if (remainingDelay > 0) { - await this.client.presenceSubscribe(sender); - - await this.client.sendPresenceUpdate((options.presence as WAPresence) ?? 'composing', sender); - - await delay(remainingDelay); - - await this.client.sendPresenceUpdate('paused', sender); - } - } else { - await this.client.presenceSubscribe(sender); - - await this.client.sendPresenceUpdate((options.presence as WAPresence) ?? 'composing', sender); - - await delay(options.delay); - - await this.client.sendPresenceUpdate('paused', sender); - } - } - - const linkPreview = options?.linkPreview != false ? undefined : false; - - let quoted: WAMessage; - - if (options?.quoted) { - const m = options?.quoted; - - const msg = m?.message ? m : ((await this.getMessage(m.key, true)) as proto.IWebMessageInfo); - - if (msg) { - quoted = msg; - this.logger.verbose('Quoted message'); - } - } - - let mentions: string[]; - if (isJidGroup(sender)) { - try { - const group = await this.findGroup({ groupJid: sender }, 'inner'); - - if (!group) { - throw new NotFoundException('Group not found'); - } - - if (options?.mentions) { - this.logger.verbose('Mentions defined'); - - if (options.mentions?.everyOne) { - this.logger.verbose('Mentions everyone'); - - this.logger.verbose('Getting group metadata'); - mentions = group.participants.map((participant) => participant.id); - this.logger.verbose('Getting group metadata for mentions'); - } else if (options.mentions?.mentioned?.length) { - this.logger.verbose('Mentions manually defined'); - mentions = options.mentions.mentioned.map((mention) => { - const jid = this.createJid(mention); - if (isJidGroup(jid)) { - return null; - } - return jid; - }); - } - } - } catch (error) { - throw new NotFoundException('Group not found'); - } - } - - const messageSent = await (async () => { - const option = { - quoted, - }; - - if ( - !message['audio'] && - !message['poll'] && - !message['sticker'] && - !message['conversation'] && - sender !== 'status@broadcast' - ) { - if (message['reactionMessage']) { - this.logger.verbose('Sending reaction'); - return await this.client.sendMessage( - sender, - { - react: { - text: message['reactionMessage']['text'], - key: message['reactionMessage']['key'], - }, - } as unknown as AnyMessageContent, - option as unknown as MiscMessageGenerationOptions, - ); - } - } - if (message['conversation']) { - this.logger.verbose('Sending message'); - return await this.client.sendMessage( - sender, - { - text: message['conversation'], - mentions, - linkPreview: linkPreview, - } as unknown as AnyMessageContent, - option as unknown as MiscMessageGenerationOptions, - ); - } - - if (!message['audio'] && !message['poll'] && sender != 'status@broadcast') { - this.logger.verbose('Sending message'); - return await this.client.sendMessage( - sender, - { - forward: { - key: { remoteJid: this.instance.wuid, fromMe: true }, - message, - }, - mentions, - }, - option as unknown as MiscMessageGenerationOptions, - ); - } - - if (sender === 'status@broadcast') { - this.logger.verbose('Sending message'); - return await this.client.sendMessage( - sender, - message['status'].content as unknown as AnyMessageContent, - { - backgroundColor: message['status'].option.backgroundColor, - font: message['status'].option.font, - statusJidList: message['status'].option.statusJidList, - } as unknown as MiscMessageGenerationOptions, - ); - } - - this.logger.verbose('Sending message'); - return await this.client.sendMessage( - sender, - message as unknown as AnyMessageContent, - option as unknown as MiscMessageGenerationOptions, - ); - })(); - - const contentMsg = messageSent.message[getContentType(messageSent.message)] as any; - - const messageRaw: MessageRaw = { - key: messageSent.key, - pushName: messageSent.pushName, - message: { ...messageSent.message }, - contextInfo: contentMsg?.contextInfo, - messageType: getContentType(messageSent.message), - messageTimestamp: messageSent.messageTimestamp as number, - owner: this.instance.name, - source: getDevice(messageSent.key.id), - }; - - this.logger.log(messageRaw); - - this.logger.verbose('Sending data to webhook in event SEND_MESSAGE'); - this.sendDataWebhook(Events.SEND_MESSAGE, messageRaw); - - if (this.localChatwoot.enabled && !isChatwoot) { - this.chatwootService.eventWhatsapp(Events.SEND_MESSAGE, { instanceName: this.instance.name }, messageRaw); - } - - this.logger.verbose('Inserting message in database'); - await this.repository.message.insert( - [messageRaw], - this.instance.name, - this.configService.get('DATABASE').SAVE_DATA.NEW_MESSAGE, - ); - - return messageSent; - } catch (error) { - this.logger.error(error); - throw new BadRequestException(error.toString()); - } - } - - // Instance Controller - public async sendPresence(data: SendPresenceDto) { - try { - const { number } = data; - - this.logger.verbose(`Check if number "${number}" is WhatsApp`); - const isWA = (await this.whatsappNumber({ numbers: [number] }))?.shift(); - - this.logger.verbose(`Exists: "${isWA.exists}" | jid: ${isWA.jid}`); - if (!isWA.exists && !isJidGroup(isWA.jid) && !isWA.jid.includes('@broadcast')) { - throw new BadRequestException(isWA); - } - - const sender = isWA.jid; - - if (data?.options?.delay && data?.options?.delay > 20000) { - let remainingDelay = data?.options.delay; - while (remainingDelay > 20000) { - await this.client.presenceSubscribe(sender); - - await this.client.sendPresenceUpdate((data?.options?.presence as WAPresence) ?? 'composing', sender); - - await delay(20000); - - await this.client.sendPresenceUpdate('paused', sender); - - remainingDelay -= 20000; - } - if (remainingDelay > 0) { - await this.client.presenceSubscribe(sender); - - await this.client.sendPresenceUpdate((data?.options?.presence as WAPresence) ?? 'composing', sender); - - await delay(remainingDelay); - - await this.client.sendPresenceUpdate('paused', sender); - } - } else { - await this.client.presenceSubscribe(sender); - - await this.client.sendPresenceUpdate((data?.options?.presence as WAPresence) ?? 'composing', sender); - - await delay(data?.options?.delay); - - await this.client.sendPresenceUpdate('paused', sender); - } - } catch (error) { - this.logger.error(error); - throw new BadRequestException(error.toString()); - } - } - - // Presence Controller - public async setPresence(data: SetPresenceDto) { - try { - await this.client.sendPresenceUpdate(data.presence); - this.logger.verbose('Sending presence update: ' + data.presence); - } catch (error) { - this.logger.error(error); - throw new BadRequestException(error.toString()); - } - } - - // Send Message Controller - public async textMessage(data: SendTextDto, isChatwoot = false) { - this.logger.verbose('Sending text message'); - return await this.sendMessageWithTyping( - data.number, - { - conversation: data.textMessage.text, - }, - data?.options, - isChatwoot, - ); - } - - public async pollMessage(data: SendPollDto) { - this.logger.verbose('Sending poll message'); - return await this.sendMessageWithTyping( - data.number, - { - poll: { - name: data.pollMessage.name, - selectableCount: data.pollMessage.selectableCount, - values: data.pollMessage.values, - }, - }, - data?.options, - ); - } - - private async formatStatusMessage(status: StatusMessage) { - this.logger.verbose('Formatting status message'); - - if (!status.type) { - throw new BadRequestException('Type is required'); - } - - if (!status.content) { - throw new BadRequestException('Content is required'); - } - - if (status.allContacts) { - this.logger.verbose('All contacts defined as true'); - - this.logger.verbose('Getting contacts from database'); - const contacts = await this.repository.contact.find({ - where: { owner: this.instance.name }, - }); - - if (!contacts.length) { - throw new BadRequestException('Contacts not found'); - } - - this.logger.verbose('Getting contacts with push name'); - status.statusJidList = contacts.filter((contact) => contact.pushName).map((contact) => contact.id); - - this.logger.verbose(status.statusJidList); - } - - if (!status.statusJidList?.length && !status.allContacts) { - throw new BadRequestException('StatusJidList is required'); - } - - if (status.type === 'text') { - this.logger.verbose('Type defined as text'); - - if (!status.backgroundColor) { - throw new BadRequestException('Background color is required'); - } - - if (!status.font) { - throw new BadRequestException('Font is required'); - } - - return { - content: { - text: status.content, - }, - option: { - backgroundColor: status.backgroundColor, - font: status.font, - statusJidList: status.statusJidList, - }, - }; - } - if (status.type === 'image') { - this.logger.verbose('Type defined as image'); - - return { - content: { - image: { - url: status.content, - }, - caption: status.caption, - }, - option: { - statusJidList: status.statusJidList, - }, - }; - } - if (status.type === 'video') { - this.logger.verbose('Type defined as video'); - - return { - content: { - video: { - url: status.content, - }, - caption: status.caption, - }, - option: { - statusJidList: status.statusJidList, - }, - }; - } - if (status.type === 'audio') { - this.logger.verbose('Type defined as audio'); - - this.logger.verbose('Processing audio'); - const convert = await this.processAudio(status.content, 'status@broadcast'); - if (typeof convert === 'string') { - this.logger.verbose('Audio processed'); - const audio = fs.readFileSync(convert).toString('base64'); - - const result = { - content: { - audio: Buffer.from(audio, 'base64'), - ptt: true, - mimetype: 'audio/mp4', - }, - option: { - statusJidList: status.statusJidList, - }, - }; - - fs.unlinkSync(convert); - - return result; - } else { - throw new InternalServerErrorException(convert); - } - } - - throw new BadRequestException('Type not found'); - } - - public async statusMessage(data: SendStatusDto) { - this.logger.verbose('Sending status message'); - const status = await this.formatStatusMessage(data.statusMessage); - - return await this.sendMessageWithTyping('status@broadcast', { - status, - }); - } - - private async prepareMediaMessage(mediaMessage: MediaMessage) { - try { - this.logger.verbose('Preparing media message'); - const prepareMedia = await prepareWAMessageMedia( - { - [mediaMessage.mediatype]: isURL(mediaMessage.media) - ? { url: mediaMessage.media } - : Buffer.from(mediaMessage.media, 'base64'), - } as any, - { upload: this.client.waUploadToServer }, - ); - - const mediaType = mediaMessage.mediatype + 'Message'; - this.logger.verbose('Media type: ' + mediaType); - - if (mediaMessage.mediatype === 'document' && !mediaMessage.fileName) { - this.logger.verbose('If media type is document and file name is not defined then'); - const regex = new RegExp(/.*\/(.+?)\./); - const arrayMatch = regex.exec(mediaMessage.media); - mediaMessage.fileName = arrayMatch[1]; - this.logger.verbose('File name: ' + mediaMessage.fileName); - } - - if (mediaMessage.mediatype === 'image' && !mediaMessage.fileName) { - mediaMessage.fileName = 'image.png'; - } - - if (mediaMessage.mediatype === 'video' && !mediaMessage.fileName) { - mediaMessage.fileName = 'video.mp4'; - } - - let mimetype: string; - - if (mediaMessage.mimetype) { - mimetype = mediaMessage.mimetype; - } else { - mimetype = getMIMEType(mediaMessage.fileName); - - if (!mimetype && isURL(mediaMessage.media)) { - let config: any = { - responseType: 'arraybuffer', - }; - - if (this.localProxy.enabled) { - config = { - ...config, - httpsAgent: makeProxyAgent(this.localProxy.proxy), - }; - } - - const response = await axios.get(mediaMessage.media, config); - - mimetype = response.headers['content-type']; - } - } - - this.logger.verbose('Mimetype: ' + mimetype); - - prepareMedia[mediaType].caption = mediaMessage?.caption; - prepareMedia[mediaType].mimetype = mimetype; - prepareMedia[mediaType].fileName = mediaMessage.fileName; - - if (mediaMessage.mediatype === 'video') { - this.logger.verbose('Is media type video then set gif playback as false'); - prepareMedia[mediaType].jpegThumbnail = Uint8Array.from( - readFileSync(join(process.cwd(), 'public', 'images', 'video-cover.png')), - ); - prepareMedia[mediaType].gifPlayback = false; - } - - this.logger.verbose('Generating wa message from content'); - return generateWAMessageFromContent( - '', - { [mediaType]: { ...prepareMedia[mediaType] } }, - { userJid: this.instance.wuid }, - ); - } catch (error) { - this.logger.error(error); - throw new InternalServerErrorException(error?.toString() || error); - } - } - - private async convertToWebP(image: string, number: string) { - try { - this.logger.verbose('Converting image to WebP to sticker'); - - let imagePath: string; - const hash = `${number}-${new Date().getTime()}`; - this.logger.verbose('Hash to image name: ' + hash); - - const outputPath = `${join(this.storePath, 'temp', `${hash}.webp`)}`; - this.logger.verbose('Output path: ' + outputPath); - - if (isBase64(image)) { - this.logger.verbose('Image is base64'); - - const base64Data = image.replace(/^data:image\/(jpeg|png|gif);base64,/, ''); - const imageBuffer = Buffer.from(base64Data, 'base64'); - imagePath = `${join(this.storePath, 'temp', `temp-${hash}.png`)}`; - this.logger.verbose('Image path: ' + imagePath); - - await sharp(imageBuffer).toFile(imagePath); - this.logger.verbose('Image created'); - } else { - this.logger.verbose('Image is url'); - - const timestamp = new Date().getTime(); - const url = `${image}?timestamp=${timestamp}`; - this.logger.verbose('including timestamp in url: ' + url); - - let config: any = { - responseType: 'arraybuffer', - }; - - if (this.localProxy.enabled) { - config = { - ...config, - httpsAgent: makeProxyAgent(this.localProxy.proxy), - }; - } - - const response = await axios.get(url, config); - this.logger.verbose('Getting image from url'); - - const imageBuffer = Buffer.from(response.data, 'binary'); - imagePath = `${join(this.storePath, 'temp', `temp-${hash}.png`)}`; - this.logger.verbose('Image path: ' + imagePath); - - await sharp(imageBuffer).toFile(imagePath); - this.logger.verbose('Image created'); - } - - await sharp(imagePath).webp().toFile(outputPath); - this.logger.verbose('Image converted to WebP'); - - fs.unlinkSync(imagePath); - this.logger.verbose('Temp image deleted'); - - return outputPath; - } catch (error) { - console.error('Erro ao converter a imagem para WebP:', error); - } - } - - public async mediaSticker(data: SendStickerDto) { - this.logger.verbose('Sending media sticker'); - const convert = await this.convertToWebP(data.stickerMessage.image, data.number); - const result = await this.sendMessageWithTyping( - data.number, - { - sticker: { url: convert }, - }, - data?.options, - ); - - fs.unlinkSync(convert); - this.logger.verbose('Converted image deleted'); - - return result; - } - - public async mediaMessage(data: SendMediaDto, isChatwoot = false) { - this.logger.verbose('Sending media message'); - const generate = await this.prepareMediaMessage(data.mediaMessage); - - return await this.sendMessageWithTyping(data.number, { ...generate.message }, data?.options, isChatwoot); - } - - public async processAudio(audio: string, number: string) { - this.logger.verbose('Processing audio'); - let tempAudioPath: string; - let outputAudio: string; - - number = number.replace(/\D/g, ''); - const hash = `${number}-${new Date().getTime()}`; - this.logger.verbose('Hash to audio name: ' + hash); - - if (isURL(audio)) { - this.logger.verbose('Audio is url'); - - outputAudio = `${join(this.storePath, 'temp', `${hash}.mp4`)}`; - tempAudioPath = `${join(this.storePath, 'temp', `temp-${hash}.mp3`)}`; - - this.logger.verbose('Output audio path: ' + outputAudio); - this.logger.verbose('Temp audio path: ' + tempAudioPath); - - const timestamp = new Date().getTime(); - const url = `${audio}?timestamp=${timestamp}`; - - this.logger.verbose('Including timestamp in url: ' + url); - - const response = await axios.get(url, { responseType: 'arraybuffer' }); - this.logger.verbose('Getting audio from url'); - - fs.writeFileSync(tempAudioPath, response.data); - } else { - this.logger.verbose('Audio is base64'); - - outputAudio = `${join(this.storePath, 'temp', `${hash}.mp4`)}`; - tempAudioPath = `${join(this.storePath, 'temp', `temp-${hash}.mp3`)}`; - - this.logger.verbose('Output audio path: ' + outputAudio); - this.logger.verbose('Temp audio path: ' + tempAudioPath); - - const audioBuffer = Buffer.from(audio, 'base64'); - fs.writeFileSync(tempAudioPath, audioBuffer); - this.logger.verbose('Temp audio created'); - } - - this.logger.verbose('Converting audio to mp4'); - return new Promise((resolve, reject) => { - exec(`${ffmpegPath.path} -i ${tempAudioPath} -vn -ab 128k -ar 44100 -f ipod ${outputAudio} -y`, (error) => { - fs.unlinkSync(tempAudioPath); - this.logger.verbose('Temp audio deleted'); - - if (error) reject(error); - - this.logger.verbose('Audio converted to mp4'); - resolve(outputAudio); - }); - }); - } - - public async audioWhatsapp(data: SendAudioDto, isChatwoot = false) { - this.logger.verbose('Sending audio whatsapp'); - - if (!data.options?.encoding && data.options?.encoding !== false) { - data.options.encoding = true; - } - - if (data.options?.encoding) { - const convert = await this.processAudio(data.audioMessage.audio, data.number); - if (typeof convert === 'string') { - const audio = fs.readFileSync(convert).toString('base64'); - const result = this.sendMessageWithTyping( - data.number, - { - audio: Buffer.from(audio, 'base64'), - ptt: true, - mimetype: 'audio/mp4', - }, - { presence: 'recording', delay: data?.options?.delay }, - isChatwoot, - ); - - fs.unlinkSync(convert); - this.logger.verbose('Converted audio deleted'); - - return result; - } else { - throw new InternalServerErrorException(convert); - } - } - - return await this.sendMessageWithTyping( - data.number, - { - audio: isURL(data.audioMessage.audio) - ? { url: data.audioMessage.audio } - : Buffer.from(data.audioMessage.audio, 'base64'), - ptt: true, - mimetype: 'audio/ogg; codecs=opus', - }, - { presence: 'recording', delay: data?.options?.delay }, - isChatwoot, - ); - } - - public async buttonMessage() { - throw new BadRequestException('Method not available on WhatsApp Baileys'); - } - - public async locationMessage(data: SendLocationDto) { - this.logger.verbose('Sending location message'); - return await this.sendMessageWithTyping( - data.number, - { - locationMessage: { - degreesLatitude: data.locationMessage.latitude, - degreesLongitude: data.locationMessage.longitude, - name: data.locationMessage?.name, - address: data.locationMessage?.address, - }, - }, - data?.options, - ); - } - - public async listMessage(data: SendListDto) { - this.logger.verbose('Sending list message'); - return await this.sendMessageWithTyping( - data.number, - { - listMessage: { - title: data.listMessage.title, - description: data.listMessage.description, - buttonText: data.listMessage?.buttonText, - footerText: data.listMessage?.footerText, - sections: data.listMessage.sections, - listType: 2, - }, - }, - data?.options, - ); - } - - public async contactMessage(data: SendContactDto) { - this.logger.verbose('Sending contact message'); - const message: proto.IMessage = {}; - - const vcard = (contact: ContactMessage) => { - this.logger.verbose('Creating vcard'); - let result = 'BEGIN:VCARD\n' + 'VERSION:3.0\n' + `N:${contact.fullName}\n` + `FN:${contact.fullName}\n`; - - if (contact.organization) { - this.logger.verbose('Organization defined'); - result += `ORG:${contact.organization};\n`; - } - - if (contact.email) { - this.logger.verbose('Email defined'); - result += `EMAIL:${contact.email}\n`; - } - - if (contact.url) { - this.logger.verbose('Url defined'); - result += `URL:${contact.url}\n`; - } - - if (!contact.wuid) { - this.logger.verbose('Wuid defined'); - contact.wuid = this.createJid(contact.phoneNumber); - } - - result += `item1.TEL;waid=${contact.wuid}:${contact.phoneNumber}\n` + 'item1.X-ABLabel:Celular\n' + 'END:VCARD'; - - this.logger.verbose('Vcard created'); - return result; - }; - - if (data.contactMessage.length === 1) { - message.contactMessage = { - displayName: data.contactMessage[0].fullName, - vcard: vcard(data.contactMessage[0]), - }; - } else { - message.contactsArrayMessage = { - displayName: `${data.contactMessage.length} contacts`, - contacts: data.contactMessage.map((contact) => { - return { - displayName: contact.fullName, - vcard: vcard(contact), - }; - }), - }; - } - - return await this.sendMessageWithTyping(data.number, { ...message }, data?.options); - } - - public async reactionMessage(data: SendReactionDto) { - this.logger.verbose('Sending reaction message'); - return await this.sendMessageWithTyping(data.reactionMessage.key.remoteJid, { - reactionMessage: { - key: data.reactionMessage.key, - text: data.reactionMessage.reaction, - }, - }); - } - - // Chat Controller - public async whatsappNumber(data: WhatsAppNumberDto) { - this.logger.verbose('Getting whatsapp number'); - - const jids: { - groups: { number: string; jid: string }[]; - broadcast: { number: string; jid: string }[]; - users: { number: string; jid: string; name?: string }[]; - } = { - groups: [], - broadcast: [], - users: [], - }; - - data.numbers.forEach((number) => { - const jid = this.createJid(number); - - if (isJidGroup(jid)) { - jids.groups.push({ number, jid }); - } else if (jid === 'status@broadcast') { - jids.broadcast.push({ number, jid }); - } else { - jids.users.push({ number, jid }); - } - }); - - const onWhatsapp: OnWhatsAppDto[] = []; - - // BROADCAST - onWhatsapp.push(...jids.broadcast.map(({ jid, number }) => new OnWhatsAppDto(jid, false, number))); - - // GROUPS - const groups = await Promise.all( - jids.groups.map(async ({ jid, number }) => { - const group = await this.findGroup({ groupJid: jid }, 'inner'); - - if (!group) { - new OnWhatsAppDto(jid, false, number); - } - - return new OnWhatsAppDto(group.id, !!group?.id, number, group?.subject); - }), - ); - onWhatsapp.push(...groups); - - // USERS - const contacts: ContactRaw[] = await this.repository.contact.findManyById({ - owner: this.instance.name, - ids: jids.users.map(({ jid }) => (jid.startsWith('+') ? jid.substring(1) : jid)), - }); - const numbersToVerify = jids.users.map(({ jid }) => jid.replace('+', '')); - const verify = await this.client.onWhatsApp(...numbersToVerify); - const users: OnWhatsAppDto[] = await Promise.all( - jids.users.map(async (user) => { - let numberVerified: (typeof verify)[0] | null = null; - - // Brazilian numbers - if (user.number.startsWith('55')) { - const numberWithDigit = - user.number.slice(4, 5) === '9' && user.number.length === 13 - ? user.number - : `${user.number.slice(0, 4)}9${user.number.slice(4)}`; - const numberWithoutDigit = - user.number.length === 12 ? user.number : user.number.slice(0, 4) + user.number.slice(5); - - numberVerified = verify.find( - (v) => v.jid === `${numberWithDigit}@s.whatsapp.net` || v.jid === `${numberWithoutDigit}@s.whatsapp.net`, - ); - } - - // Mexican/Argentina numbers - // Ref: https://faq.whatsapp.com/1294841057948784 - if (!numberVerified && (user.number.startsWith('52') || user.number.startsWith('54'))) { - let prefix = ''; - if (user.number.startsWith('52')) { - prefix = '1'; - } - if (user.number.startsWith('54')) { - prefix = '9'; - } - - const numberWithDigit = - user.number.slice(2, 3) === prefix && user.number.length === 13 - ? user.number - : `${user.number.slice(0, 2)}${prefix}${user.number.slice(2)}`; - const numberWithoutDigit = - user.number.length === 12 ? user.number : user.number.slice(0, 2) + user.number.slice(3); - - numberVerified = verify.find( - (v) => v.jid === `${numberWithDigit}@s.whatsapp.net` || v.jid === `${numberWithoutDigit}@s.whatsapp.net`, - ); - } - - if (!numberVerified) { - numberVerified = verify.find((v) => v.jid === user.jid); - } - - const numberJid = numberVerified?.jid || user.jid; - return { - exists: !!numberVerified?.exists, - jid: numberJid, - name: contacts.find((c) => c.id === numberJid)?.pushName, - number: user.number, - }; - }), - ); - - onWhatsapp.push(...users); - - return onWhatsapp; - } - - public async markMessageAsRead(data: ReadMessageDto) { - this.logger.verbose('Marking message as read'); - - try { - const keys: proto.IMessageKey[] = []; - data.read_messages.forEach((read) => { - if (isJidGroup(read.remoteJid) || isJidUser(read.remoteJid)) { - keys.push({ - remoteJid: read.remoteJid, - fromMe: read.fromMe, - id: read.id, - }); - } - }); - await this.client.readMessages(keys); - return { message: 'Read messages', read: 'success' }; - } catch (error) { - throw new InternalServerErrorException('Read messages fail', error.toString()); - } - } - - public async getLastMessage(number: string) { - const messages = await this.fetchMessages({ - where: { - key: { - remoteJid: number, - }, - owner: this.instance.name, - }, - }); - - let lastMessage = messages.pop(); - - for (const message of messages) { - if (message.messageTimestamp >= lastMessage.messageTimestamp) { - lastMessage = message; - } - } - - return lastMessage as unknown as LastMessage; - } - - public async archiveChat(data: ArchiveChatDto) { - this.logger.verbose('Archiving chat'); - try { - let last_message = data.lastMessage; - let number = data.chat; - - if (!last_message && number) { - last_message = await this.getLastMessage(number); - } else { - last_message = data.lastMessage; - last_message.messageTimestamp = last_message?.messageTimestamp ?? Date.now(); - number = last_message?.key?.remoteJid; - } - - if (!last_message || Object.keys(last_message).length === 0) { - throw new NotFoundException('Last message not found'); - } - - await this.client.chatModify( - { - archive: data.archive, - lastMessages: [last_message], - }, - this.createJid(number), - ); - - return { - chatId: number, - archived: true, - }; - } catch (error) { - throw new InternalServerErrorException({ - archived: false, - message: ['An error occurred while archiving the chat. Open a calling.', error.toString()], - }); - } - } - - public async markChatUnread(data: MarkChatUnreadDto) { - this.logger.verbose('Marking chat as unread'); - - try { - let last_message = data.lastMessage; - let number = data.chat; - - if (!last_message && number) { - last_message = await this.getLastMessage(number); - } else { - last_message = data.lastMessage; - last_message.messageTimestamp = last_message?.messageTimestamp ?? Date.now(); - number = last_message?.key?.remoteJid; - } - - if (!last_message || Object.keys(last_message).length === 0) { - throw new NotFoundException('Last message not found'); - } - - await this.client.chatModify( - { - markRead: false, - lastMessages: [last_message], - }, - this.createJid(number), - ); - - return { - chatId: number, - markedChatUnread: true, - }; - } catch (error) { - throw new InternalServerErrorException({ - markedChatUnread: false, - message: ['An error occurred while marked unread the chat. Open a calling.', error.toString()], - }); - } - } - - public async deleteMessage(del: DeleteMessage) { - this.logger.verbose('Deleting message'); - try { - return await this.client.sendMessage(del.remoteJid, { delete: del }); - } catch (error) { - throw new InternalServerErrorException('Error while deleting message for everyone', error?.toString()); - } - } - - public async getBase64FromMediaMessage(data: getBase64FromMediaMessageDto) { - this.logger.verbose('Getting base64 from media message'); - try { - const m = data?.message; - const convertToMp4 = data?.convertToMp4 ?? false; - - const msg = m?.message ? m : ((await this.getMessage(m.key, true)) as proto.IWebMessageInfo); - - if (!msg) { - throw 'Message not found'; - } - - for (const subtype of MessageSubtype) { - if (msg.message[subtype]) { - msg.message = msg.message[subtype].message; - } - } - - let mediaMessage: any; - let mediaType: string; - - for (const type of TypeMediaMessage) { - mediaMessage = msg.message[type]; - if (mediaMessage) { - mediaType = type; - break; - } - } - - if (!mediaMessage) { - throw 'The message is not of the media type'; - } - - if (typeof mediaMessage['mediaKey'] === 'object') { - msg.message = JSON.parse(JSON.stringify(msg.message)); - } - - this.logger.verbose('Downloading media message'); - const buffer = await downloadMediaMessage( - { key: msg?.key, message: msg?.message }, - 'buffer', - {}, - { - logger: P({ level: 'error' }) as any, - reuploadRequest: this.client.updateMediaMessage, - }, - ); - const typeMessage = getContentType(msg.message); - - if (convertToMp4 && typeMessage === 'audioMessage') { - this.logger.verbose('Converting audio to mp4'); - const number = msg.key.remoteJid.split('@')[0]; - const convert = await this.processAudio(buffer.toString('base64'), number); - - if (typeof convert === 'string') { - const audio = fs.readFileSync(convert).toString('base64'); - this.logger.verbose('Audio converted to mp4'); - - const result = { - mediaType, - fileName: mediaMessage['fileName'], - caption: mediaMessage['caption'], - size: { - fileLength: mediaMessage['fileLength'], - height: mediaMessage['height'], - width: mediaMessage['width'], - }, - mimetype: 'audio/mp4', - base64: Buffer.from(audio, 'base64').toString('base64'), - }; - - fs.unlinkSync(convert); - this.logger.verbose('Converted audio deleted'); - - this.logger.verbose('Media message downloaded'); - return result; - } - } - - this.logger.verbose('Media message downloaded'); - return { - mediaType, - fileName: mediaMessage['fileName'], - caption: mediaMessage['caption'], - size: { - fileLength: mediaMessage['fileLength'], - height: mediaMessage['height'], - width: mediaMessage['width'], - }, - mimetype: mediaMessage['mimetype'], - base64: buffer.toString('base64'), - }; - } catch (error) { - this.logger.error(error); - throw new BadRequestException(error.toString()); - } - } - - public async fetchPrivacySettings() { - this.logger.verbose('Fetching privacy settings'); - const privacy = await this.client.fetchPrivacySettings(); - - return { - readreceipts: privacy.readreceipts, - profile: privacy.profile, - status: privacy.status, - online: privacy.online, - last: privacy.last, - groupadd: privacy.groupadd, - }; - } - - public async updatePrivacySettings(settings: PrivacySettingDto) { - this.logger.verbose('Updating privacy settings'); - try { - await this.client.updateReadReceiptsPrivacy(settings.privacySettings.readreceipts); - this.logger.verbose('Read receipts privacy updated'); - - await this.client.updateProfilePicturePrivacy(settings.privacySettings.profile); - this.logger.verbose('Profile picture privacy updated'); - - await this.client.updateStatusPrivacy(settings.privacySettings.status); - this.logger.verbose('Status privacy updated'); - - await this.client.updateOnlinePrivacy(settings.privacySettings.online); - this.logger.verbose('Online privacy updated'); - - await this.client.updateLastSeenPrivacy(settings.privacySettings.last); - this.logger.verbose('Last seen privacy updated'); - - await this.client.updateGroupsAddPrivacy(settings.privacySettings.groupadd); - this.logger.verbose('Groups add privacy updated'); - - this.reloadConnection(); - - return { - update: 'success', - data: { - readreceipts: settings.privacySettings.readreceipts, - profile: settings.privacySettings.profile, - status: settings.privacySettings.status, - online: settings.privacySettings.online, - last: settings.privacySettings.last, - groupadd: settings.privacySettings.groupadd, - }, - }; - } catch (error) { - throw new InternalServerErrorException('Error updating privacy settings', error.toString()); - } - } - - public async fetchBusinessProfile(number: string): Promise { - this.logger.verbose('Fetching business profile'); - try { - const jid = number ? this.createJid(number) : this.instance.wuid; - - const profile = await this.client.getBusinessProfile(jid); - this.logger.verbose('Trying to get business profile'); - - if (!profile) { - const info = await this.whatsappNumber({ numbers: [jid] }); - - return { - isBusiness: false, - message: 'Not is business profile', - ...info?.shift(), - }; - } - - this.logger.verbose('Business profile fetched'); - return { - isBusiness: true, - ...profile, - }; - } catch (error) { - throw new InternalServerErrorException('Error updating profile name', error.toString()); - } - } - - public async updateProfileName(name: string) { - this.logger.verbose('Updating profile name to ' + name); - try { - await this.client.updateProfileName(name); - - return { update: 'success' }; - } catch (error) { - throw new InternalServerErrorException('Error updating profile name', error.toString()); - } - } - - public async updateProfileStatus(status: string) { - this.logger.verbose('Updating profile status to: ' + status); - try { - await this.client.updateProfileStatus(status); - - return { update: 'success' }; - } catch (error) { - throw new InternalServerErrorException('Error updating profile status', error.toString()); - } - } - - public async updateProfilePicture(picture: string) { - this.logger.verbose('Updating profile picture'); - try { - let pic: WAMediaUpload; - if (isURL(picture)) { - this.logger.verbose('Picture is url'); - - const timestamp = new Date().getTime(); - const url = `${picture}?timestamp=${timestamp}`; - this.logger.verbose('Including timestamp in url: ' + url); - - let config: any = { - responseType: 'arraybuffer', - }; - - if (this.localProxy.enabled) { - config = { - ...config, - httpsAgent: makeProxyAgent(this.localProxy.proxy), - }; - } - - pic = (await axios.get(url, config)).data; - this.logger.verbose('Getting picture from url'); - } else if (isBase64(picture)) { - this.logger.verbose('Picture is base64'); - pic = Buffer.from(picture, 'base64'); - this.logger.verbose('Getting picture from base64'); - } else { - throw new BadRequestException('"profilePicture" must be a url or a base64'); - } - - await this.client.updateProfilePicture(this.instance.wuid, pic); - this.logger.verbose('Profile picture updated'); - - this.reloadConnection(); - - return { update: 'success' }; - } catch (error) { - throw new InternalServerErrorException('Error updating profile picture', error.toString()); - } - } - - public async removeProfilePicture() { - this.logger.verbose('Removing profile picture'); - try { - await this.client.removeProfilePicture(this.instance.wuid); - - this.reloadConnection(); - - return { update: 'success' }; - } catch (error) { - throw new InternalServerErrorException('Error removing profile picture', error.toString()); - } - } - - public async blockUser(data: BlockUserDto) { - this.logger.verbose('Blocking user: ' + data.number); - try { - const { number } = data; - - this.logger.verbose(`Check if number "${number}" is WhatsApp`); - const isWA = (await this.whatsappNumber({ numbers: [number] }))?.shift(); - - this.logger.verbose(`Exists: "${isWA.exists}" | jid: ${isWA.jid}`); - if (!isWA.exists && !isJidGroup(isWA.jid) && !isWA.jid.includes('@broadcast')) { - throw new BadRequestException(isWA); - } - - const sender = isWA.jid; - - await this.client.updateBlockStatus(sender, data.status); - - return { block: 'success' }; - } catch (error) { - throw new InternalServerErrorException('Error blocking user', error.toString()); - } - } - - public async updateMessage(data: UpdateMessageDto) { - try { - const jid = this.createJid(data.number); - - this.logger.verbose('Updating message'); - return await this.client.sendMessage(jid, { - text: data.text, - edit: data.key, - }); - } catch (error) { - this.logger.error(error); - throw new BadRequestException(error.toString()); - } - } - - public async fetchLabels(): Promise { - this.logger.verbose('Fetching labels'); - const labels = await this.repository.labels.find({ - where: { - owner: this.instance.name, - }, - }); - - return labels.map((label) => ({ - color: label.color, - name: label.name, - id: label.id, - predefinedId: label.predefinedId, - })); - } - - public async handleLabel(data: HandleLabelDto) { - this.logger.verbose('Adding label'); - const whatsappContact = await this.whatsappNumber({ numbers: [data.number] }); - if (whatsappContact.length === 0) { - throw new NotFoundException('Number not found'); - } - const contact = whatsappContact[0]; - if (!contact.exists) { - throw new NotFoundException('Number is not on WhatsApp'); - } - - try { - if (data.action === 'add') { - await this.client.addChatLabel(contact.jid, data.labelId); - - return { numberJid: contact.jid, labelId: data.labelId, add: true }; - } - if (data.action === 'remove') { - await this.client.removeChatLabel(contact.jid, data.labelId); - - return { numberJid: contact.jid, labelId: data.labelId, remove: true }; - } - } catch (error) { - throw new BadRequestException(`Unable to ${data.action} label to chat`, error.toString()); - } - } - - // Group - public async createGroup(create: CreateGroupDto) { - this.logger.verbose('Creating group: ' + create.subject); - try { - const participants = (await this.whatsappNumber({ numbers: create.participants })) - .filter((participant) => participant.exists) - .map((participant) => participant.jid); - const { id } = await this.client.groupCreate(create.subject, participants); - this.logger.verbose('Group created: ' + id); - - if (create?.description) { - this.logger.verbose('Updating group description: ' + create.description); - await this.client.groupUpdateDescription(id, create.description); - } - - if (create?.promoteParticipants) { - this.logger.verbose('Prometing group participants: ' + participants); - await this.updateGParticipant({ - groupJid: id, - action: 'promote', - participants: participants, - }); - } - - this.logger.verbose('Getting group metadata'); - const group = await this.client.groupMetadata(id); - - return group; - } catch (error) { - this.logger.error(error); - throw new InternalServerErrorException('Error creating group', error.toString()); - } - } - - public async updateGroupPicture(picture: GroupPictureDto) { - this.logger.verbose('Updating group picture'); - try { - let pic: WAMediaUpload; - if (isURL(picture.image)) { - this.logger.verbose('Picture is url'); - - const timestamp = new Date().getTime(); - const url = `${picture.image}?timestamp=${timestamp}`; - this.logger.verbose('Including timestamp in url: ' + url); - - let config: any = { - responseType: 'arraybuffer', - }; - - if (this.localProxy.enabled) { - config = { - ...config, - httpsAgent: makeProxyAgent(this.localProxy.proxy), - }; - } - - pic = (await axios.get(url, config)).data; - this.logger.verbose('Getting picture from url'); - } else if (isBase64(picture.image)) { - this.logger.verbose('Picture is base64'); - pic = Buffer.from(picture.image, 'base64'); - this.logger.verbose('Getting picture from base64'); - } else { - throw new BadRequestException('"profilePicture" must be a url or a base64'); - } - await this.client.updateProfilePicture(picture.groupJid, pic); - this.logger.verbose('Group picture updated'); - - return { update: 'success' }; - } catch (error) { - throw new InternalServerErrorException('Error update group picture', error.toString()); - } - } - - public async updateGroupSubject(data: GroupSubjectDto) { - this.logger.verbose('Updating group subject to: ' + data.subject); - try { - await this.client.groupUpdateSubject(data.groupJid, data.subject); - - return { update: 'success' }; - } catch (error) { - throw new InternalServerErrorException('Error updating group subject', error.toString()); - } - } - - public async updateGroupDescription(data: GroupDescriptionDto) { - this.logger.verbose('Updating group description to: ' + data.description); - try { - await this.client.groupUpdateDescription(data.groupJid, data.description); - - return { update: 'success' }; - } catch (error) { - throw new InternalServerErrorException('Error updating group description', error.toString()); - } - } - - public async findGroup(id: GroupJid, reply: 'inner' | 'out' = 'out') { - this.logger.verbose('Fetching group'); - try { - const group = await this.client.groupMetadata(id.groupJid); - - const picture = await this.profilePicture(group.id); - - return { - id: group.id, - subject: group.subject, - subjectOwner: group.subjectOwner, - subjectTime: group.subjectTime, - pictureUrl: picture.profilePictureUrl, - size: group.participants.length, - creation: group.creation, - owner: group.owner, - desc: group.desc, - descId: group.descId, - restrict: group.restrict, - announce: group.announce, - participants: group.participants, - }; - } catch (error) { - if (reply === 'inner') { - return; - } - throw new NotFoundException('Error fetching group', error.toString()); - } - } - - public async fetchAllGroups(getParticipants: GetParticipant) { - this.logger.verbose('Fetching all groups'); - try { - const fetch = Object.values(await this.client.groupFetchAllParticipating()); - let groups = []; - for (const group of fetch) { - const picture = await this.profilePicture(group.id); - - const result = { - id: group.id, - subject: group.subject, - subjectOwner: group.subjectOwner, - subjectTime: group.subjectTime, - pictureUrl: picture.profilePictureUrl, - size: group.participants.length, - creation: group.creation, - owner: group.owner, - desc: group.desc, - descId: group.descId, - restrict: group.restrict, - announce: group.announce, - }; - - if (getParticipants.getParticipants == 'true') { - result['participants'] = group.participants; - } - - groups = [...groups, result]; - } - - return groups; - } catch (error) { - throw new NotFoundException('Error fetching group', error.toString()); - } - } - - public async inviteCode(id: GroupJid) { - this.logger.verbose('Fetching invite code for group: ' + id.groupJid); - try { - const code = await this.client.groupInviteCode(id.groupJid); - return { inviteUrl: `https://chat.whatsapp.com/${code}`, inviteCode: code }; - } catch (error) { - throw new NotFoundException('No invite code', error.toString()); - } - } - - public async inviteInfo(id: GroupInvite) { - this.logger.verbose('Fetching invite info for code: ' + id.inviteCode); - try { - return await this.client.groupGetInviteInfo(id.inviteCode); - } catch (error) { - throw new NotFoundException('No invite info', id.inviteCode); - } - } - - public async sendInvite(id: GroupSendInvite) { - this.logger.verbose('Sending invite for group: ' + id.groupJid); - try { - const inviteCode = await this.inviteCode({ groupJid: id.groupJid }); - this.logger.verbose('Getting invite code: ' + inviteCode.inviteCode); - - const inviteUrl = inviteCode.inviteUrl; - this.logger.verbose('Invite url: ' + inviteUrl); - - const numbers = id.numbers.map((number) => this.createJid(number)); - const description = id.description ?? ''; - - const msg = `${description}\n\n${inviteUrl}`; - - const message = { - conversation: msg, - }; - - for await (const number of numbers) { - await this.sendMessageWithTyping(number, message); - } - - this.logger.verbose('Invite sent for numbers: ' + numbers.join(', ')); - - return { send: true, inviteUrl }; - } catch (error) { - throw new NotFoundException('No send invite'); - } - } - - public async acceptInviteCode(id: AcceptGroupInvite) { - this.logger.verbose('Joining the group by invitation code: ' + id.inviteCode); - try { - const groupJid = await this.client.groupAcceptInvite(id.inviteCode); - return { accepted: true, groupJid: groupJid }; - } catch (error) { - throw new NotFoundException('Accept invite error', error.toString()); - } - } - - public async revokeInviteCode(id: GroupJid) { - this.logger.verbose('Revoking invite code for group: ' + id.groupJid); - try { - const inviteCode = await this.client.groupRevokeInvite(id.groupJid); - return { revoked: true, inviteCode }; - } catch (error) { - throw new NotFoundException('Revoke error', error.toString()); - } - } - - public async findParticipants(id: GroupJid) { - this.logger.verbose('Fetching participants for group: ' + id.groupJid); - try { - const participants = (await this.client.groupMetadata(id.groupJid)).participants; - const contacts = await this.repository.contact.findManyById({ - owner: this.instance.name, - ids: participants.map((p) => p.id), - }); - const parsedParticipants = participants.map((participant) => { - const contact = contacts.find((c) => c.id === participant.id); - return { - ...participant, - name: participant.name ?? contact?.pushName, - imgUrl: participant.imgUrl ?? contact?.profilePictureUrl, - }; - }); - return { participants: parsedParticipants }; - } catch (error) { - throw new NotFoundException('No participants', error.toString()); - } - } - - public async updateGParticipant(update: GroupUpdateParticipantDto) { - this.logger.verbose('Updating participants'); - try { - const participants = update.participants.map((p) => this.createJid(p)); - const updateParticipants = await this.client.groupParticipantsUpdate( - update.groupJid, - participants, - update.action, - ); - return { updateParticipants: updateParticipants }; - } catch (error) { - throw new BadRequestException('Error updating participants', error.toString()); - } - } - - public async updateGSetting(update: GroupUpdateSettingDto) { - this.logger.verbose('Updating setting for group: ' + update.groupJid); - try { - const updateSetting = await this.client.groupSettingUpdate(update.groupJid, update.action); - return { updateSetting: updateSetting }; - } catch (error) { - throw new BadRequestException('Error updating setting', error.toString()); - } - } - - public async toggleEphemeral(update: GroupToggleEphemeralDto) { - this.logger.verbose('Toggling ephemeral for group: ' + update.groupJid); - try { - await this.client.groupToggleEphemeral(update.groupJid, update.expiration); - return { success: true }; - } catch (error) { - throw new BadRequestException('Error updating setting', error.toString()); - } - } - - public async leaveGroup(id: GroupJid) { - this.logger.verbose('Leaving group: ' + id.groupJid); - try { - await this.client.groupLeave(id.groupJid); - return { groupJid: id.groupJid, leave: true }; - } catch (error) { - throw new BadRequestException('Unable to leave the group', error.toString()); - } - } - public async templateMessage() { - throw new Error('Method not available in the Baileys service'); - } -} diff --git a/src/api/services/integration.service.ts b/src/api/services/integration.service.ts deleted file mode 100644 index c457fa93..00000000 --- a/src/api/services/integration.service.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { Logger } from '../../config/logger.config'; -import { InstanceDto } from '../dto/instance.dto'; -import { IntegrationDto } from '../dto/integration.dto'; -import { IntegrationRaw } from '../models'; -import { WAMonitoringService } from './monitor.service'; - -export class IntegrationService { - constructor(private readonly waMonitor: WAMonitoringService) {} - - private readonly logger = new Logger(IntegrationService.name); - - public create(instance: InstanceDto, data: IntegrationDto) { - this.logger.verbose('create integration: ' + instance.instanceName); - this.waMonitor.waInstances[instance.instanceName].setIntegration(data); - - return { integration: { ...instance, integration: data } }; - } - - public async find(instance: InstanceDto): Promise { - try { - this.logger.verbose('find integration: ' + instance.instanceName); - const result = await this.waMonitor.waInstances[instance.instanceName].findIntegration(); - - if (Object.keys(result).length === 0) { - this.create(instance, { integration: 'WHATSAPP-BAILEYS', number: '', token: '' }); - return { integration: 'WHATSAPP-BAILEYS', number: '', token: '' }; - } - - return result; - } catch (error) { - return { integration: '', number: '', token: '' }; - } - } -} diff --git a/src/api/services/monitor.service.ts b/src/api/services/monitor.service.ts index af93fa74..af775f1f 100644 --- a/src/api/services/monitor.service.ts +++ b/src/api/services/monitor.service.ts @@ -1,192 +1,121 @@ +import { InstanceDto } from '@api/dto/instance.dto'; +import { ProviderFiles } from '@api/provider/sessions'; +import { PrismaRepository } from '@api/repository/repository.service'; +import { channelController } from '@api/server.module'; +import { Events, Integration } from '@api/types/wa.types'; +import { CacheConf, Chatwoot, ConfigService, Database, DelInstance, ProviderSession } from '@config/env.config'; +import { Logger } from '@config/logger.config'; +import { INSTANCE_DIR, STORE_DIR } from '@config/path.config'; +import { NotFoundException } from '@exceptions'; import { execSync } from 'child_process'; import EventEmitter2 from 'eventemitter2'; -import { existsSync, mkdirSync, opendirSync, readdirSync, rmSync, writeFileSync } from 'fs'; -import { Db } from 'mongodb'; -import { Collection } from 'mongoose'; +import { rmSync } from 'fs'; import { join } from 'path'; -import { Auth, CacheConf, ConfigService, Database, DelInstance, HttpServer } from '../../config/env.config'; -import { Logger } from '../../config/logger.config'; -import { INSTANCE_DIR, STORE_DIR } from '../../config/path.config'; -import { NotFoundException } from '../../exceptions'; -import { - AuthModel, - ChamaaiModel, - ChatwootModel, - ContactModel, - LabelModel, - ProxyModel, - RabbitmqModel, - SettingsModel, - TypebotModel, - WebhookModel, - WebsocketModel, -} from '../models'; -import { RepositoryBroker } from '../repository/repository.manager'; -import { Integration } from '../types/wa.types'; import { CacheService } from './cache.service'; -import { BaileysStartupService } from './channels/whatsapp.baileys.service'; -import { BusinessStartupService } from './channels/whatsapp.business.service'; export class WAMonitoringService { constructor( private readonly eventEmitter: EventEmitter2, private readonly configService: ConfigService, - private readonly repository: RepositoryBroker, + private readonly prismaRepository: PrismaRepository, + private readonly providerFiles: ProviderFiles, private readonly cache: CacheService, private readonly chatwootCache: CacheService, - private readonly messagesLostCache: CacheService, + private readonly baileysCache: CacheService, ) { - this.logger.verbose('instance created'); - this.removeInstance(); this.noConnection(); Object.assign(this.db, configService.get('DATABASE')); Object.assign(this.redis, configService.get('CACHE')); - - this.dbInstance = this.db.ENABLED - ? this.repository.dbServer?.db(this.db.CONNECTION.DB_PREFIX_NAME + '-instances') - : undefined; } private readonly db: Partial = {}; private readonly redis: Partial = {}; - private dbInstance: Db; + private readonly logger = new Logger('WAMonitoringService'); + public readonly waInstances: Record = {}; - private readonly logger = new Logger(WAMonitoringService.name); - public readonly waInstances: Record = {}; + private readonly providerSession = Object.freeze(this.configService.get('PROVIDER')); public delInstanceTime(instance: string) { const time = this.configService.get('DEL_INSTANCE'); if (typeof time === 'number' && time > 0) { - this.logger.verbose(`Instance "${instance}" don't have connection, will be removed in ${time} minutes`); - - setTimeout(async () => { - if (this.waInstances[instance]?.connectionStatus?.state !== 'open') { - if (this.waInstances[instance]?.connectionStatus?.state === 'connecting') { - if ((await this.waInstances[instance].findIntegration()).integration === Integration.WHATSAPP_BAILEYS) { - await this.waInstances[instance]?.client?.logout('Log out instance: ' + instance); - this.waInstances[instance]?.client?.ws?.close(); - this.waInstances[instance]?.client?.end(undefined); + setTimeout( + async () => { + if (this.waInstances[instance]?.connectionStatus?.state !== 'open') { + if (this.waInstances[instance]?.connectionStatus?.state === 'connecting') { + if ((await this.waInstances[instance].integration) === Integration.WHATSAPP_BAILEYS) { + await this.waInstances[instance]?.client?.logout('Log out instance: ' + instance); + this.waInstances[instance]?.client?.ws?.close(); + this.waInstances[instance]?.client?.end(undefined); + } + this.eventEmitter.emit('remove.instance', instance, 'inner'); + } else { + this.eventEmitter.emit('remove.instance', instance, 'inner'); } - this.waInstances[instance]?.removeRabbitmqQueues(); - delete this.waInstances[instance]; - } else { - this.waInstances[instance]?.removeRabbitmqQueues(); - delete this.waInstances[instance]; - this.eventEmitter.emit('remove.instance', instance, 'inner'); } - } - }, 1000 * 60 * time); + }, + 1000 * 60 * time, + ); } } - public async instanceInfo(instanceName?: string, arrayReturn = false) { - this.logger.verbose('get instance info'); - if (instanceName && !this.waInstances[instanceName]) { - throw new NotFoundException(`Instance "${instanceName}" not found`); - } + public async instanceInfo(instanceNames?: string[]): Promise { + if (instanceNames && instanceNames.length > 0) { + const inexistentInstances = instanceNames ? instanceNames.filter((instance) => !this.waInstances[instance]) : []; - const instances: any[] = []; - - for await (const [key, value] of Object.entries(this.waInstances)) { - if (value) { - this.logger.verbose('get instance info: ' + key); - let chatwoot: any; - - const urlServer = this.configService.get('SERVER').URL; - - const findChatwoot = await this.waInstances[key].findChatwoot(); - - if (findChatwoot && findChatwoot.enabled) { - chatwoot = { - ...findChatwoot, - webhook_url: `${urlServer}/chatwoot/webhook/${encodeURIComponent(key)}`, - }; - } - - const findIntegration = await this.waInstances[key].findIntegration(); - - let integration: any; - if (findIntegration) { - integration = { - ...findIntegration, - webhook_wa_business: `${urlServer}/webhook/whatsapp/${encodeURIComponent(key)}`, - }; - } - - if (value.connectionStatus.state === 'open') { - this.logger.verbose('instance: ' + key + ' - connectionStatus: open'); - - const instanceData = { - instance: { - instanceName: key, - instanceId: (await this.repository.auth.find(key))?.instanceId, - owner: value.wuid, - profileName: (await value.getProfileName()) || 'not loaded', - profilePictureUrl: value.profilePictureUrl, - profileStatus: (await value.getProfileStatus()) || '', - status: value.connectionStatus.state, - }, - }; - - if (this.configService.get('AUTHENTICATION').EXPOSE_IN_FETCH_INSTANCES) { - instanceData.instance['serverUrl'] = this.configService.get('SERVER').URL; - - instanceData.instance['apikey'] = (await this.repository.auth.find(key))?.apikey; - - instanceData.instance['chatwoot'] = chatwoot; - - instanceData.instance['integration'] = integration; - } - - instances.push(instanceData); - } else { - this.logger.verbose('instance: ' + key + ' - connectionStatus: ' + value.connectionStatus.state); - - const instanceData = { - instance: { - instanceName: key, - instanceId: (await this.repository.auth.find(key))?.instanceId, - status: value.connectionStatus.state, - }, - }; - - if (this.configService.get('AUTHENTICATION').EXPOSE_IN_FETCH_INSTANCES) { - instanceData.instance['serverUrl'] = this.configService.get('SERVER').URL; - - instanceData.instance['apikey'] = (await this.repository.auth.find(key))?.apikey; - - instanceData.instance['chatwoot'] = chatwoot; - - instanceData.instance['integration'] = integration; - } - - instances.push(instanceData); - } + if (inexistentInstances.length > 0) { + throw new NotFoundException( + `Instance${inexistentInstances.length > 1 ? 's' : ''} "${inexistentInstances.join(', ')}" not found`, + ); } } - this.logger.verbose('return instance info: ' + instances.length); + const clientName = this.configService.get('DATABASE').CONNECTION.CLIENT_NAME; - if (arrayReturn) { - return [instances.find((i) => i.instance.instanceName === instanceName) ?? instances]; - } - return instances.find((i) => i.instance.instanceName === instanceName) ?? instances; + const where = + instanceNames && instanceNames.length > 0 + ? { + name: { + in: instanceNames, + }, + clientName, + } + : { clientName }; + + const instances = await this.prismaRepository.instance.findMany({ + where, + include: { + Chatwoot: true, + Proxy: true, + Rabbitmq: true, + Sqs: true, + Websocket: true, + Setting: true, + _count: { + select: { + Message: true, + Contact: true, + Chat: true, + }, + }, + }, + }); + + return instances; } public async instanceInfoById(instanceId?: string, number?: string) { - this.logger.verbose('get instance info'); let instanceName: string; if (instanceId) { - instanceName = await this.repository.auth.findInstanceNameById(instanceId); + instanceName = await this.prismaRepository.instance.findFirst({ where: { id: instanceId } }).then((r) => r?.name); if (!instanceName) { throw new NotFoundException(`Instance "${instanceId}" not found`); } } else if (number) { - instanceName = await this.repository.auth.findInstanceNameByNumber(number); + instanceName = await this.prismaRepository.instance.findFirst({ where: { number } }).then((r) => r?.name); if (!instanceName) { throw new NotFoundException(`Instance "${number}" not found`); } @@ -200,117 +129,85 @@ export class WAMonitoringService { throw new NotFoundException(`Instance "${instanceName}" not found`); } - return this.instanceInfo(instanceName); - } + const instanceNames = instanceName ? [instanceName] : null; - private delInstanceFiles() { - this.logger.verbose('cron to delete instance files started'); - setInterval(async () => { - if (this.db.ENABLED && this.db.SAVE_DATA.INSTANCE) { - const collections = await this.dbInstance.collections(); - collections.forEach(async (collection) => { - const name = collection.namespace.replace(/^[\w-]+./, ''); - await this.dbInstance.collection(name).deleteMany({ - $or: [{ _id: { $regex: /^app.state.*/ } }, { _id: { $regex: /^session-.*/ } }], - }); - this.logger.verbose('instance files deleted: ' + name); - }); - } else if (!this.redis.REDIS.ENABLED && !this.redis.REDIS.SAVE_INSTANCES) { - const dir = opendirSync(INSTANCE_DIR, { encoding: 'utf-8' }); - for await (const dirent of dir) { - if (dirent.isDirectory()) { - const files = readdirSync(join(INSTANCE_DIR, dirent.name), { - encoding: 'utf-8', - }); - files.forEach(async (file) => { - if (file.match(/^app.state.*/) || file.match(/^session-.*/)) { - rmSync(join(INSTANCE_DIR, dirent.name, file), { - recursive: true, - force: true, - }); - } - }); - this.logger.verbose('instance files deleted: ' + dirent.name); - } - } - } - }, 3600 * 1000 * 2); + return this.instanceInfo(instanceNames); } public async cleaningUp(instanceName: string) { - this.logger.verbose('cleaning up instance: ' + instanceName); + let instanceDbId: string; + if (this.db.SAVE_DATA.INSTANCE) { + const findInstance = await this.prismaRepository.instance.findFirst({ + where: { name: instanceName }, + }); - if (this.db.ENABLED && this.db.SAVE_DATA.INSTANCE) { - this.logger.verbose('cleaning up instance in database: ' + instanceName); - await this.repository.dbServer.connect(); - const collections: any[] = await this.dbInstance.collections(); - if (collections.length > 0) { - await this.dbInstance.dropCollection(instanceName); + if (findInstance) { + const instance = await this.prismaRepository.instance.update({ + where: { name: instanceName }, + data: { connectionStatus: 'close' }, + }); + + rmSync(join(INSTANCE_DIR, instance.id), { recursive: true, force: true }); + + instanceDbId = instance.id; + await this.prismaRepository.session.deleteMany({ where: { sessionId: instance.id } }); } - return; } if (this.redis.REDIS.ENABLED && this.redis.REDIS.SAVE_INSTANCES) { - this.logger.verbose('cleaning up instance in redis: ' + instanceName); await this.cache.delete(instanceName); - return; + if (instanceDbId) { + await this.cache.delete(instanceDbId); + } } - this.logger.verbose('cleaning up instance in files: ' + instanceName); - rmSync(join(INSTANCE_DIR, instanceName), { recursive: true, force: true }); + if (this.providerSession?.ENABLED) { + await this.providerFiles.removeSession(instanceName); + } } - public async cleaningStoreFiles(instanceName: string) { - if (!this.db.ENABLED) { - this.logger.verbose('cleaning store files instance: ' + instanceName); - rmSync(join(INSTANCE_DIR, instanceName), { recursive: true, force: true }); - - execSync(`rm -rf ${join(STORE_DIR, 'chats', instanceName)}`); - execSync(`rm -rf ${join(STORE_DIR, 'contacts', instanceName)}`); - execSync(`rm -rf ${join(STORE_DIR, 'message-up', instanceName)}`); - execSync(`rm -rf ${join(STORE_DIR, 'messages', instanceName)}`); - - execSync(`rm -rf ${join(STORE_DIR, 'auth', 'apikey', instanceName + '.json')}`); - execSync(`rm -rf ${join(STORE_DIR, 'webhook', instanceName + '.json')}`); + public async cleaningStoreData(instanceName: string) { + if (this.configService.get('CHATWOOT').ENABLED) { execSync(`rm -rf ${join(STORE_DIR, 'chatwoot', instanceName + '*')}`); - execSync(`rm -rf ${join(STORE_DIR, 'chamaai', instanceName + '*')}`); - execSync(`rm -rf ${join(STORE_DIR, 'proxy', instanceName + '*')}`); - execSync(`rm -rf ${join(STORE_DIR, 'rabbitmq', instanceName + '*')}`); - execSync(`rm -rf ${join(STORE_DIR, 'typebot', instanceName + '*')}`); - execSync(`rm -rf ${join(STORE_DIR, 'websocket', instanceName + '*')}`); - execSync(`rm -rf ${join(STORE_DIR, 'settings', instanceName + '*')}`); - execSync(`rm -rf ${join(STORE_DIR, 'labels', instanceName + '*')}`); - - return; } - this.logger.verbose('cleaning store database instance: ' + instanceName); + const instance = await this.prismaRepository.instance.findFirst({ + where: { name: instanceName }, + }); - await AuthModel.deleteMany({ _id: instanceName }); - await WebhookModel.deleteMany({ _id: instanceName }); - await ChatwootModel.deleteMany({ _id: instanceName }); - await ChamaaiModel.deleteMany({ _id: instanceName }); - await ProxyModel.deleteMany({ _id: instanceName }); - await RabbitmqModel.deleteMany({ _id: instanceName }); - await TypebotModel.deleteMany({ _id: instanceName }); - await WebsocketModel.deleteMany({ _id: instanceName }); - await SettingsModel.deleteMany({ _id: instanceName }); - await LabelModel.deleteMany({ owner: instanceName }); - await ContactModel.deleteMany({ owner: instanceName }); + if (!instance) return; - return; + rmSync(join(INSTANCE_DIR, instance.id), { recursive: true, force: true }); + + await this.prismaRepository.session.deleteMany({ where: { sessionId: instance.id } }); + + await this.prismaRepository.chat.deleteMany({ where: { instanceId: instance.id } }); + await this.prismaRepository.contact.deleteMany({ where: { instanceId: instance.id } }); + await this.prismaRepository.messageUpdate.deleteMany({ where: { instanceId: instance.id } }); + await this.prismaRepository.message.deleteMany({ where: { instanceId: instance.id } }); + + await this.prismaRepository.webhook.deleteMany({ where: { instanceId: instance.id } }); + await this.prismaRepository.chatwoot.deleteMany({ where: { instanceId: instance.id } }); + await this.prismaRepository.proxy.deleteMany({ where: { instanceId: instance.id } }); + await this.prismaRepository.rabbitmq.deleteMany({ where: { instanceId: instance.id } }); + await this.prismaRepository.sqs.deleteMany({ where: { instanceId: instance.id } }); + await this.prismaRepository.integrationSession.deleteMany({ where: { instanceId: instance.id } }); + await this.prismaRepository.typebot.deleteMany({ where: { instanceId: instance.id } }); + await this.prismaRepository.websocket.deleteMany({ where: { instanceId: instance.id } }); + await this.prismaRepository.setting.deleteMany({ where: { instanceId: instance.id } }); + await this.prismaRepository.label.deleteMany({ where: { instanceId: instance.id } }); + + await this.prismaRepository.instance.delete({ where: { name: instanceName } }); } public async loadInstance() { - this.logger.verbose('Loading instances'); - try { - if (this.redis.REDIS.ENABLED && this.redis.REDIS.SAVE_INSTANCES) { + if (this.providerSession?.ENABLED) { + await this.loadInstancesFromProvider(); + } else if (this.db.SAVE_DATA.INSTANCE) { + await this.loadInstancesFromDatabasePostgres(); + } else if (this.redis.REDIS.ENABLED && this.redis.REDIS.SAVE_INSTANCES) { await this.loadInstancesFromRedis(); - } else if (this.db.ENABLED && this.db.SAVE_DATA.INSTANCE) { - await this.loadInstancesFromDatabase(); - } else { - await this.loadInstancesFromFiles(); } } catch (error) { this.logger.error(error); @@ -318,139 +215,167 @@ export class WAMonitoringService { } public async saveInstance(data: any) { - this.logger.verbose('Save instance'); - try { - const msgParsed = JSON.parse(JSON.stringify(data)); - if (this.db.ENABLED && this.db.SAVE_DATA.INSTANCE) { - await this.repository.dbServer.connect(); - await this.dbInstance.collection(data.instanceName).replaceOne({ _id: 'integration' }, msgParsed, { - upsert: true, - }); - } else { - const path = join(INSTANCE_DIR, data.instanceName); - if (!existsSync(path)) mkdirSync(path, { recursive: true }); - writeFileSync(path + '/integration.json', JSON.stringify(msgParsed)); - } + const clientName = await this.configService.get('DATABASE').CONNECTION.CLIENT_NAME; + await this.prismaRepository.instance.create({ + data: { + id: data.instanceId, + name: data.instanceName, + ownerJid: data.ownerJid, + profileName: data.profileName, + profilePicUrl: data.profilePicUrl, + connectionStatus: + data.integration && data.integration === Integration.WHATSAPP_BAILEYS ? 'close' : (data.status ?? 'open'), + number: data.number, + integration: data.integration || Integration.WHATSAPP_BAILEYS, + token: data.hash, + clientName: clientName, + businessId: data.businessId, + }, + }); } catch (error) { this.logger.error(error); } } - private async setInstance(name: string) { - const integration = await this.repository.integration.find(name); - - let instance: BaileysStartupService | BusinessStartupService; - if (integration && integration.integration === Integration.WHATSAPP_BUSINESS) { - instance = new BusinessStartupService( - this.configService, - this.eventEmitter, - this.repository, - this.cache, - this.chatwootCache, - this.messagesLostCache, - ); - - instance.instanceName = name; - } else { - instance = new BaileysStartupService( - this.configService, - this.eventEmitter, - this.repository, - this.cache, - this.chatwootCache, - this.messagesLostCache, - ); - - instance.instanceName = name; - - if (!integration) { - await instance.setIntegration({ integration: Integration.WHATSAPP_BAILEYS }); - } + public deleteInstance(instanceName: string) { + try { + this.eventEmitter.emit('remove.instance', instanceName, 'inner'); + } catch (error) { + this.logger.error(error); } + } + + private async setInstance(instanceData: InstanceDto) { + const instance = channelController.init(instanceData, { + configService: this.configService, + eventEmitter: this.eventEmitter, + prismaRepository: this.prismaRepository, + cache: this.cache, + chatwootCache: this.chatwootCache, + baileysCache: this.baileysCache, + providerFiles: this.providerFiles, + }); + + if (!instance) return; + + instance.setInstance({ + instanceId: instanceData.instanceId, + instanceName: instanceData.instanceName, + integration: instanceData.integration, + token: instanceData.token, + number: instanceData.number, + businessId: instanceData.businessId, + }); - this.logger.verbose('Instance loaded: ' + name); await instance.connectToWhatsapp(); - this.logger.verbose('connectToWhatsapp: ' + name); - this.waInstances[name] = instance; + this.waInstances[instanceData.instanceName] = instance; } private async loadInstancesFromRedis() { - this.logger.verbose('Redis enabled'); const keys = await this.cache.keys(); if (keys?.length > 0) { - this.logger.verbose('Reading instance keys and setting instances'); - await Promise.all(keys.map((k) => this.setInstance(k.split(':')[2]))); - } else { - this.logger.verbose('No instance keys found'); + await Promise.all( + keys.map(async (k) => { + const instanceData = await this.prismaRepository.instance.findUnique({ + where: { id: k.split(':')[1] }, + }); + + if (!instanceData) { + return; + } + + const instance = { + instanceId: k.split(':')[1], + instanceName: k.split(':')[2], + integration: instanceData.integration, + token: instanceData.token, + number: instanceData.number, + businessId: instanceData.businessId, + }; + + this.setInstance(instance); + }), + ); } } - private async loadInstancesFromDatabase() { - this.logger.verbose('Database enabled'); - await this.repository.dbServer.connect(); - const collections: any[] = await this.dbInstance.collections(); - await this.deleteTempInstances(collections); - if (collections.length > 0) { - this.logger.verbose('Reading collections and setting instances'); - await Promise.all(collections.map((coll) => this.setInstance(coll.namespace.replace(/^[\w-]+\./, '')))); - } else { - this.logger.verbose('No collections found'); - } - } + private async loadInstancesFromDatabasePostgres() { + const clientName = await this.configService.get('DATABASE').CONNECTION.CLIENT_NAME; - private async loadInstancesFromFiles() { - this.logger.verbose('Store in files enabled'); - const dir = opendirSync(INSTANCE_DIR, { encoding: 'utf-8' }); - const instanceDirs = []; + const instances = await this.prismaRepository.instance.findMany({ + where: { clientName: clientName }, + }); - for await (const dirent of dir) { - if (dirent.isDirectory()) { - instanceDirs.push(dirent.name); - } else { - this.logger.verbose('No instance files found'); - } + if (instances.length === 0) { + return; } await Promise.all( - instanceDirs.map(async (instanceName) => { - this.logger.verbose('Reading instance files and setting instances: ' + instanceName); - const files = readdirSync(join(INSTANCE_DIR, instanceName), { encoding: 'utf-8' }); + instances.map(async (instance) => { + this.setInstance({ + instanceId: instance.id, + instanceName: instance.name, + integration: instance.integration, + token: instance.token, + number: instance.number, + businessId: instance.businessId, + }); + }), + ); + } - if (files.length === 0) { - rmSync(join(INSTANCE_DIR, instanceName), { recursive: true, force: true }); - } else { - await this.setInstance(instanceName); - } + private async loadInstancesFromProvider() { + const [instances] = await this.providerFiles.allInstances(); + + if (!instances?.data) { + return; + } + + await Promise.all( + instances?.data?.map(async (instanceId: string) => { + const instance = await this.prismaRepository.instance.findUnique({ + where: { id: instanceId }, + }); + + this.setInstance({ + instanceId: instance.id, + instanceName: instance.name, + integration: instance.integration, + token: instance.token, + businessId: instance.businessId, + }); }), ); } private removeInstance() { this.eventEmitter.on('remove.instance', async (instanceName: string) => { - this.logger.verbose('remove instance: ' + instanceName); try { - this.logger.verbose('instance: ' + instanceName + ' - removing from memory'); - this.waInstances[instanceName] = undefined; - } catch (error) { - this.logger.error(error); - } + await this.waInstances[instanceName]?.sendDataWebhook(Events.REMOVE_INSTANCE, null); - try { - this.logger.verbose('request cleaning up instance: ' + instanceName); this.cleaningUp(instanceName); - this.cleaningStoreFiles(instanceName); + this.cleaningStoreData(instanceName); } finally { this.logger.warn(`Instance "${instanceName}" - REMOVED`); } + + try { + delete this.waInstances[instanceName]; + } catch (error) { + this.logger.error(error); + } }); this.eventEmitter.on('logout.instance', async (instanceName: string) => { - this.logger.verbose('logout instance: ' + instanceName); try { - this.waInstances[instanceName]?.clearCacheChatwoot(); - this.logger.verbose('request cleaning up instance: ' + instanceName); + await this.waInstances[instanceName]?.sendDataWebhook(Events.LOGOUT_INSTANCE, null); + + if (this.configService.get('CHATWOOT').ENABLED) { + this.waInstances[instanceName]?.clearCacheChatwoot(); + } + this.cleaningUp(instanceName); } finally { this.logger.warn(`Instance "${instanceName}" - LOGOUT`); @@ -459,13 +384,10 @@ export class WAMonitoringService { } private noConnection() { - this.logger.verbose('checking instances without connection'); this.eventEmitter.on('no.connection', async (instanceName) => { try { - this.logger.verbose('logging out instance: ' + instanceName); await this.waInstances[instanceName]?.client?.logout('Log out instance: ' + instanceName); - this.logger.verbose('close connection instance: ' + instanceName); this.waInstances[instanceName]?.client?.ws?.close(); this.waInstances[instanceName].instance.qrcode = { count: 0 }; @@ -481,27 +403,4 @@ export class WAMonitoringService { } }); } - - private async deleteTempInstances(collections: Collection[]) { - const shouldDelete = this.configService.get('DEL_TEMP_INSTANCES'); - if (!shouldDelete) { - this.logger.verbose('Temp instances deletion is disabled'); - return; - } - this.logger.verbose('Cleaning up temp instances'); - const auths = await this.repository.auth.list(); - if (auths.length === 0) { - this.logger.verbose('No temp instances found'); - return; - } - let tempInstances = 0; - auths.forEach((auth) => { - if (collections.find((coll) => coll.namespace.replace(/^[\w-]+\./, '') === auth._id)) { - return; - } - tempInstances++; - this.eventEmitter.emit('remove.instance', auth._id, 'inner'); - }); - this.logger.verbose('Temp instances removed: ' + tempInstances); - } } diff --git a/src/api/services/proxy.service.ts b/src/api/services/proxy.service.ts index f86933c1..69ba87b4 100644 --- a/src/api/services/proxy.service.ts +++ b/src/api/services/proxy.service.ts @@ -1,24 +1,23 @@ -import { Logger } from '../../config/logger.config'; -import { InstanceDto } from '../dto/instance.dto'; -import { ProxyDto } from '../dto/proxy.dto'; -import { ProxyRaw } from '../models'; +import { InstanceDto } from '@api/dto/instance.dto'; +import { ProxyDto } from '@api/dto/proxy.dto'; +import { Logger } from '@config/logger.config'; +import { Proxy } from '@prisma/client'; + import { WAMonitoringService } from './monitor.service'; export class ProxyService { constructor(private readonly waMonitor: WAMonitoringService) {} - private readonly logger = new Logger(ProxyService.name); + private readonly logger = new Logger('ProxyService'); public create(instance: InstanceDto, data: ProxyDto) { - this.logger.verbose('create proxy: ' + instance.instanceName); this.waMonitor.waInstances[instance.instanceName].setProxy(data); return { proxy: { ...instance, proxy: data } }; } - public async find(instance: InstanceDto): Promise { + public async find(instance: InstanceDto): Promise { try { - this.logger.verbose('find proxy: ' + instance.instanceName); const result = await this.waMonitor.waInstances[instance.instanceName].findProxy(); if (Object.keys(result).length === 0) { @@ -27,7 +26,7 @@ export class ProxyService { return result; } catch (error) { - return { enabled: false, proxy: null }; + return null; } } } diff --git a/src/api/services/settings.service.ts b/src/api/services/settings.service.ts index 741a2cbc..5b7ab1b8 100644 --- a/src/api/services/settings.service.ts +++ b/src/api/services/settings.service.ts @@ -1,23 +1,22 @@ -import { Logger } from '../../config/logger.config'; -import { InstanceDto } from '../dto/instance.dto'; -import { SettingsDto } from '../dto/settings.dto'; +import { InstanceDto } from '@api/dto/instance.dto'; +import { SettingsDto } from '@api/dto/settings.dto'; +import { Logger } from '@config/logger.config'; + import { WAMonitoringService } from './monitor.service'; export class SettingsService { constructor(private readonly waMonitor: WAMonitoringService) {} - private readonly logger = new Logger(SettingsService.name); + private readonly logger = new Logger('SettingsService'); - public create(instance: InstanceDto, data: SettingsDto) { - this.logger.verbose('create settings: ' + instance.instanceName); - this.waMonitor.waInstances[instance.instanceName].setSettings(data); + public async create(instance: InstanceDto, data: SettingsDto) { + await this.waMonitor.waInstances[instance.instanceName].setSettings(data); return { settings: { ...instance, settings: data } }; } public async find(instance: InstanceDto): Promise { try { - this.logger.verbose('find settings: ' + instance.instanceName); const result = await this.waMonitor.waInstances[instance.instanceName].findSettings(); if (Object.keys(result).length === 0) { @@ -26,7 +25,7 @@ export class SettingsService { return result; } catch (error) { - return { reject_call: false, msg_call: '', groups_ignore: true }; + return null; } } } diff --git a/src/api/services/template.service.ts b/src/api/services/template.service.ts new file mode 100644 index 00000000..949f71c7 --- /dev/null +++ b/src/api/services/template.service.ts @@ -0,0 +1,101 @@ +import { InstanceDto } from '@api/dto/instance.dto'; +import { TemplateDto } from '@api/dto/template.dto'; +import { PrismaRepository } from '@api/repository/repository.service'; +import { ConfigService, WaBusiness } from '@config/env.config'; +import { Logger } from '@config/logger.config'; +import axios from 'axios'; + +import { WAMonitoringService } from './monitor.service'; + +export class TemplateService { + constructor( + private readonly waMonitor: WAMonitoringService, + public readonly prismaRepository: PrismaRepository, + private readonly configService: ConfigService, + ) {} + + private readonly logger = new Logger('TemplateService'); + + private businessId: string; + private token: string; + + public async find(instance: InstanceDto) { + const getInstance = await this.waMonitor.waInstances[instance.instanceName].instance; + + if (!getInstance) { + throw new Error('Instance not found'); + } + + this.businessId = getInstance.businessId; + this.token = getInstance.token; + + const response = await this.requestTemplate({}, 'GET'); + + if (!response) { + throw new Error('Error to create template'); + } + + return response.data; + } + + public async create(instance: InstanceDto, data: TemplateDto) { + try { + const getInstance = await this.waMonitor.waInstances[instance.instanceName].instance; + + if (!getInstance) { + throw new Error('Instance not found'); + } + + this.businessId = getInstance.businessId; + this.token = getInstance.token; + + const postData = { + name: data.name, + category: data.category, + allow_category_change: data.allowCategoryChange, + language: data.language, + components: data.components, + }; + + const response = await this.requestTemplate(postData, 'POST'); + + if (!response || response.error) { + throw new Error('Error to create template'); + } + + const template = await this.prismaRepository.template.create({ + data: { + templateId: response.id, + name: data.name, + template: response, + webhookUrl: data.webhookUrl, + instanceId: getInstance.id, + }, + }); + + return template; + } catch (error) { + this.logger.error(error); + throw new Error('Error to create template'); + } + } + + private async requestTemplate(data: any, method: string) { + try { + let urlServer = this.configService.get('WA_BUSINESS').URL; + const version = this.configService.get('WA_BUSINESS').VERSION; + urlServer = `${urlServer}/${version}/${this.businessId}/message_templates`; + const headers = { 'Content-Type': 'application/json', Authorization: `Bearer ${this.token}` }; + if (method === 'GET') { + const result = await axios.get(urlServer, { headers }); + return result.data; + } else if (method === 'POST') { + const result = await axios.post(urlServer, data, { headers }); + return result.data; + } + } catch (e) { + this.logger.error(e.response.data); + return e.response.data.error; + } + } +} diff --git a/src/api/services/webhook.service.ts b/src/api/services/webhook.service.ts deleted file mode 100644 index 810ce96d..00000000 --- a/src/api/services/webhook.service.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Logger } from '../../config/logger.config'; -import { InstanceDto } from '../dto/instance.dto'; -import { WebhookDto } from '../dto/webhook.dto'; -import { WAMonitoringService } from './monitor.service'; - -export class WebhookService { - constructor(private readonly waMonitor: WAMonitoringService) {} - - private readonly logger = new Logger(WebhookService.name); - - public create(instance: InstanceDto, data: WebhookDto) { - this.logger.verbose('create webhook: ' + instance.instanceName); - this.waMonitor.waInstances[instance.instanceName].setWebhook(data); - - return { webhook: { ...instance, webhook: data } }; - } - - public async find(instance: InstanceDto): Promise { - try { - this.logger.verbose('find webhook: ' + instance.instanceName); - const result = await this.waMonitor.waInstances[instance.instanceName].findWebhook(); - - if (Object.keys(result).length === 0) { - throw new Error('Webhook not found'); - } - - return result; - } catch (error) { - return { enabled: false, url: '', events: [], webhook_by_events: false, webhook_base64: false }; - } - } -} diff --git a/src/api/types/wa.types.ts b/src/api/types/wa.types.ts index 9c33ac6f..0aad0696 100644 --- a/src/api/types/wa.types.ts +++ b/src/api/types/wa.types.ts @@ -1,5 +1,6 @@ /* eslint-disable @typescript-eslint/no-namespace */ -import { AuthenticationState, WAConnectionState } from '@whiskeysockets/baileys'; +import { JsonValue } from '@prisma/client/runtime/library'; +import { AuthenticationState, WAConnectionState } from 'baileys'; export enum Events { APPLICATION_STARTUP = 'application.startup', @@ -10,6 +11,7 @@ export enum Events { STATUS_INSTANCE = 'status.instance', MESSAGES_SET = 'messages.set', MESSAGES_UPSERT = 'messages.upsert', + MESSAGES_EDITED = 'messages.edited', MESSAGES_UPDATE = 'messages.update', MESSAGES_DELETE = 'messages.delete', SEND_MESSAGE = 'send.message', @@ -27,11 +29,12 @@ export enum Events { CALL = 'call', TYPEBOT_START = 'typebot.start', TYPEBOT_CHANGE_STATUS = 'typebot.change-status', - CHAMA_AI_ACTION = 'chama-ai.action', LABELS_EDIT = 'labels.edit', LABELS_ASSOCIATION = 'labels.association', CREDS_UPDATE = 'creds.update', MESSAGING_HISTORY_SET = 'messaging-history.set', + REMOVE_INSTANCE = 'remove.instance', + LOGOUT_INSTANCE = 'logout.instance', } export declare namespace wa { @@ -41,7 +44,9 @@ export declare namespace wa { base64?: string; code?: string; }; + export type Instance = { + id?: string; qrcode?: QrCode; pairingCode?: string; authState?: { state: AuthenticationState; saveCreds: () => void }; @@ -49,55 +54,58 @@ export declare namespace wa { wuid?: string; profileName?: string; profilePictureUrl?: string; - }; - - export type LocalWebHook = { - enabled?: boolean; - url?: string; - events?: string[]; - webhook_by_events?: boolean; - webhook_base64?: boolean; + token?: string; + number?: string; + integration?: string; + businessId?: string; }; export type LocalChatwoot = { enabled?: boolean; - account_id?: string; + accountId?: string; token?: string; url?: string; - name_inbox?: string; - sign_msg?: boolean; + nameInbox?: string; + signMsg?: boolean; + signDelimiter?: string; number?: string; - reopen_conversation?: boolean; - conversation_pending?: boolean; - merge_brazil_contacts?: boolean; - import_contacts?: boolean; - import_messages?: boolean; - days_limit_import_messages?: number; + reopenConversation?: boolean; + conversationPending?: boolean; + mergeBrazilContacts?: boolean; + importContacts?: boolean; + importMessages?: boolean; + daysLimitImportMessages?: number; }; export type LocalSettings = { - reject_call?: boolean; - msg_call?: string; - groups_ignore?: boolean; - always_online?: boolean; - read_messages?: boolean; - read_status?: boolean; - sync_full_history?: boolean; + rejectCall?: boolean; + msgCall?: string; + groupsIgnore?: boolean; + alwaysOnline?: boolean; + readMessages?: boolean; + readStatus?: boolean; + syncFullHistory?: boolean; + wavoipToken?: string; }; - export type LocalWebsocket = { + export type LocalEvent = { enabled?: boolean; - events?: string[]; + events?: JsonValue; }; - export type LocalRabbitmq = { - enabled?: boolean; - events?: string[]; + export type LocalWebHook = LocalEvent & { + url?: string; + headers?: JsonValue; + webhookByEvents?: boolean; + webhookBase64?: boolean; }; - export type LocalSqs = { - enabled?: boolean; - events?: string[]; + export type LocalPusher = LocalEvent & { + appId?: string; + key?: string; + secret?: string; + cluster?: string; + useTLS?: boolean; }; type Session = { @@ -106,19 +114,8 @@ export declare namespace wa { createdAt?: number; }; - export type LocalTypebot = { + export type LocalProxy = { enabled?: boolean; - url?: string; - typebot?: string; - expire?: number; - keyword_finish?: string; - delay_message?: number; - unknown_message?: string; - listening_from_me?: boolean; - sessions?: Session[]; - }; - - type Proxy = { host?: string; port?: string; protocol?: string; @@ -126,25 +123,6 @@ export declare namespace wa { password?: string; }; - export type LocalProxy = { - enabled?: boolean; - proxy?: Proxy; - }; - - export type LocalChamaai = { - enabled?: boolean; - url?: string; - token?: string; - waNumber?: string; - answerByAudio?: boolean; - }; - - export type LocalIntegration = { - integration?: string; - number?: string; - token?: string; - }; - export type StateConnection = { instance?: string; state?: WAConnectionState | 'refused'; @@ -154,7 +132,14 @@ export declare namespace wa { export type StatusMessage = 'ERROR' | 'PENDING' | 'SERVER_ACK' | 'DELIVERY_ACK' | 'READ' | 'DELETED' | 'PLAYED'; } -export const TypeMediaMessage = ['imageMessage', 'documentMessage', 'audioMessage', 'videoMessage', 'stickerMessage']; +export const TypeMediaMessage = [ + 'imageMessage', + 'documentMessage', + 'audioMessage', + 'videoMessage', + 'stickerMessage', + 'ptvMessage', +]; export const MessageSubtype = [ 'ephemeralMessage', @@ -166,4 +151,5 @@ export const MessageSubtype = [ export const Integration = { WHATSAPP_BUSINESS: 'WHATSAPP-BUSINESS', WHATSAPP_BAILEYS: 'WHATSAPP-BAILEYS', + EVOLUTION: 'EVOLUTION', }; diff --git a/src/cache/cacheengine.ts b/src/cache/cacheengine.ts index dd3d18f1..cc4a1b9c 100644 --- a/src/cache/cacheengine.ts +++ b/src/cache/cacheengine.ts @@ -1,24 +1,28 @@ -import { ICache } from '../api/abstract/abstract.cache'; -import { CacheConf, ConfigService } from '../config/env.config'; -import { Logger } from '../config/logger.config'; +import { ICache } from '@api/abstract/abstract.cache'; +import { CacheConf, ConfigService } from '@config/env.config'; +import { Logger } from '@config/logger.config'; + import { LocalCache } from './localcache'; import { RedisCache } from './rediscache'; -const logger = new Logger('Redis'); +const logger = new Logger('CacheEngine'); export class CacheEngine { private engine: ICache; - constructor(private readonly configService: ConfigService, module: string) { + constructor( + private readonly configService: ConfigService, + module: string, + ) { const cacheConf = configService.get('CACHE'); if (cacheConf?.REDIS?.ENABLED && cacheConf?.REDIS?.URI !== '') { + logger.verbose(`RedisCache initialized for ${module}`); this.engine = new RedisCache(configService, module); } else if (cacheConf?.LOCAL?.ENABLED) { + logger.verbose(`LocalCache initialized for ${module}`); this.engine = new LocalCache(configService, module); } - - logger.info(`RedisCache initialized for ${module}`); } public getEngine() { diff --git a/src/cache/localcache.ts b/src/cache/localcache.ts index 54a51d90..2aa2007e 100644 --- a/src/cache/localcache.ts +++ b/src/cache/localcache.ts @@ -1,13 +1,18 @@ +import { ICache } from '@api/abstract/abstract.cache'; +import { CacheConf, CacheConfLocal, ConfigService } from '@config/env.config'; +import { Logger } from '@config/logger.config'; +import { BufferJSON } from 'baileys'; import NodeCache from 'node-cache'; -import { ICache } from '../api/abstract/abstract.cache'; -import { CacheConf, CacheConfLocal, ConfigService } from '../config/env.config'; - export class LocalCache implements ICache { + private readonly logger = new Logger('LocalCache'); private conf: CacheConfLocal; static localCache = new NodeCache(); - constructor(private readonly configService: ConfigService, private readonly module: string) { + constructor( + private readonly configService: ConfigService, + private readonly module: string, + ) { this.conf = this.configService.get('CACHE')?.LOCAL; } @@ -46,16 +51,50 @@ export class LocalCache implements ICache { return `${this.module}:${key}`; } - async hGet() { - console.log('hGet not implemented'); + async hGet(key: string, field: string) { + try { + const data = LocalCache.localCache.get(this.buildKey(key)) as Object; + + if (data && field in data) { + return JSON.parse(data[field], BufferJSON.reviver); + } + + return null; + } catch (error) { + this.logger.error(error); + } } - async hSet() { - console.log('hSet not implemented'); + async hSet(key: string, field: string, value: any) { + try { + const json = JSON.stringify(value, BufferJSON.replacer); + + let hash = LocalCache.localCache.get(this.buildKey(key)); + + if (!hash) { + hash = {}; + } + + hash[field] = json; + LocalCache.localCache.set(this.buildKey(key), hash); + } catch (error) { + this.logger.error(error); + } } - async hDelete() { - console.log('hDelete not implemented'); - return 0; + async hDelete(key: string, field: string) { + try { + const data = LocalCache.localCache.get(this.buildKey(key)) as Object; + + if (data && field in data) { + delete data[field]; + LocalCache.localCache.set(this.buildKey(key), data); + return 1; + } + + return 0; + } catch (error) { + this.logger.error(error); + } } } diff --git a/src/cache/rediscache.client.ts b/src/cache/rediscache.client.ts index b3f8dead..45a0321f 100644 --- a/src/cache/rediscache.client.ts +++ b/src/cache/rediscache.client.ts @@ -1,10 +1,9 @@ +import { CacheConf, CacheConfRedis, configService } from '@config/env.config'; +import { Logger } from '@config/logger.config'; import { createClient, RedisClientType } from 'redis'; -import { CacheConf, CacheConfRedis, configService } from '../config/env.config'; -import { Logger } from '../config/logger.config'; - class Redis { - private logger = new Logger(Redis.name); + private logger = new Logger('Redis'); private client: RedisClientType = null; private conf: CacheConfRedis; private connected = false; @@ -41,10 +40,8 @@ class Redis { }); try { - this.logger.verbose('connecting new redis client'); this.client.connect(); this.connected = true; - this.logger.verbose('connected to new redis client'); } catch (e) { this.connected = false; this.logger.error('redis connect exception caught: ' + e); diff --git a/src/cache/rediscache.ts b/src/cache/rediscache.ts index 6e209ef1..1ec67e76 100644 --- a/src/cache/rediscache.ts +++ b/src/cache/rediscache.ts @@ -1,17 +1,20 @@ -import { BufferJSON } from '@whiskeysockets/baileys'; +import { ICache } from '@api/abstract/abstract.cache'; +import { CacheConf, CacheConfRedis, ConfigService } from '@config/env.config'; +import { Logger } from '@config/logger.config'; +import { BufferJSON } from 'baileys'; import { RedisClientType } from 'redis'; -import { ICache } from '../api/abstract/abstract.cache'; -import { CacheConf, CacheConfRedis, ConfigService } from '../config/env.config'; -import { Logger } from '../config/logger.config'; import { redisClient } from './rediscache.client'; export class RedisCache implements ICache { - private readonly logger = new Logger(RedisCache.name); + private readonly logger = new Logger('RedisCache'); private client: RedisClientType; private conf: CacheConfRedis; - constructor(private readonly configService: ConfigService, private readonly module: string) { + constructor( + private readonly configService: ConfigService, + private readonly module: string, + ) { this.conf = this.configService.get('CACHE')?.REDIS; this.client = redisClient.getConnection(); } diff --git a/src/config/env.config.ts b/src/config/env.config.ts index eab883f7..78ca891c 100644 --- a/src/config/env.config.ts +++ b/src/config/env.config.ts @@ -1,7 +1,7 @@ import { isBooleanString } from 'class-validator'; -import { readFileSync } from 'fs'; -import { load } from 'js-yaml'; -import { join } from 'path'; +import dotenv from 'dotenv'; + +dotenv.config(); export type HttpServer = { TYPE: 'http' | 'https'; @@ -20,7 +20,7 @@ export type Cors = { export type LogBaileys = 'fatal' | 'error' | 'warn' | 'info' | 'debug' | 'trace'; -export type LogLevel = 'ERROR' | 'WARN' | 'DEBUG' | 'INFO' | 'LOG' | 'VERBOSE' | 'DARK' | 'WEBHOOKS'; +export type LogLevel = 'ERROR' | 'WARN' | 'DEBUG' | 'INFO' | 'LOG' | 'VERBOSE' | 'DARK' | 'WEBHOOKS' | 'WEBSOCKET'; export type Log = { LEVEL: LogLevel[]; @@ -28,41 +28,39 @@ export type Log = { BAILEYS: LogBaileys; }; +export type ProviderSession = { + ENABLED: boolean; + HOST: string; + PORT: string; + PREFIX: string; +}; + export type SaveData = { INSTANCE: boolean; + HISTORIC: boolean; NEW_MESSAGE: boolean; MESSAGE_UPDATE: boolean; CONTACTS: boolean; CHATS: boolean; LABELS: boolean; -}; - -export type StoreConf = { - MESSAGES: boolean; - MESSAGE_UP: boolean; - CONTACTS: boolean; - CHATS: boolean; - LABELS: boolean; -}; - -export type CleanStoreConf = { - CLEANING_INTERVAL: number; - MESSAGES: boolean; - MESSAGE_UP: boolean; - CONTACTS: boolean; - CHATS: boolean; + IS_ON_WHATSAPP: boolean; + IS_ON_WHATSAPP_DAYS: number; }; export type DBConnection = { URI: string; - DB_PREFIX_NAME: string; + CLIENT_NAME: string; }; export type Database = { CONNECTION: DBConnection; - ENABLED: boolean; + PROVIDER: string; SAVE_DATA: SaveData; + DELETE_DATA: DeleteData; }; +export type DeleteData = { + LOGICAL_MESSAGE_DELETE: boolean; +}; export type EventsRabbitmq = { APPLICATION_STARTUP: boolean; INSTANCE_CREATE: boolean; @@ -70,6 +68,7 @@ export type EventsRabbitmq = { QRCODE_UPDATED: boolean; MESSAGES_SET: boolean; MESSAGES_UPSERT: boolean; + MESSAGES_EDITED: boolean; MESSAGES_UPDATE: boolean; MESSAGES_DELETE: boolean; SEND_MESSAGE: boolean; @@ -88,7 +87,6 @@ export type EventsRabbitmq = { GROUP_UPDATE: boolean; GROUP_PARTICIPANTS_UPDATE: boolean; CALL: boolean; - NEW_JWT_TOKEN: boolean; TYPEBOT_START: boolean; TYPEBOT_CHANGE_STATUS: boolean; }; @@ -99,6 +97,7 @@ export type Rabbitmq = { EXCHANGE_NAME: string; GLOBAL_ENABLED: boolean; EVENTS: EventsRabbitmq; + PREFIX_KEY: string; }; export type Sqs = { @@ -128,6 +127,7 @@ export type EventsWebhook = { QRCODE_UPDATED: boolean; MESSAGES_SET: boolean; MESSAGES_UPSERT: boolean; + MESSAGES_EDITED: boolean; MESSAGES_UPDATE: boolean; MESSAGES_DELETE: boolean; SEND_MESSAGE: boolean; @@ -146,22 +146,47 @@ export type EventsWebhook = { GROUP_UPDATE: boolean; GROUP_PARTICIPANTS_UPDATE: boolean; CALL: boolean; - NEW_JWT_TOKEN: boolean; TYPEBOT_START: boolean; TYPEBOT_CHANGE_STATUS: boolean; - CHAMA_AI_ACTION: boolean; ERRORS: boolean; ERRORS_WEBHOOK: string; }; +export type EventsPusher = { + APPLICATION_STARTUP: boolean; + INSTANCE_CREATE: boolean; + INSTANCE_DELETE: boolean; + QRCODE_UPDATED: boolean; + MESSAGES_SET: boolean; + MESSAGES_UPSERT: boolean; + MESSAGES_EDITED: boolean; + MESSAGES_UPDATE: boolean; + MESSAGES_DELETE: boolean; + SEND_MESSAGE: boolean; + CONTACTS_SET: boolean; + CONTACTS_UPDATE: boolean; + CONTACTS_UPSERT: boolean; + PRESENCE_UPDATE: boolean; + CHATS_SET: boolean; + CHATS_UPDATE: boolean; + CHATS_DELETE: boolean; + CHATS_UPSERT: boolean; + CONNECTION_UPDATE: boolean; + LABELS_EDIT: boolean; + LABELS_ASSOCIATION: boolean; + GROUPS_UPSERT: boolean; + GROUP_UPDATE: boolean; + GROUP_PARTICIPANTS_UPDATE: boolean; + CALL: boolean; + TYPEBOT_START: boolean; + TYPEBOT_CHANGE_STATUS: boolean; +}; + export type ApiKey = { KEY: string }; -export type Jwt = { EXPIRIN_IN: number; SECRET: string }; export type Auth = { API_KEY: ApiKey; EXPOSE_IN_FETCH_INSTANCES: boolean; - JWT: Jwt; - TYPE: 'jwt' | 'apikey'; }; export type DelInstance = number | boolean; @@ -173,6 +198,16 @@ export type GlobalWebhook = { ENABLED: boolean; WEBHOOK_BY_EVENTS: boolean; }; + +export type GlobalPusher = { + ENABLED: boolean; + APP_ID: string; + KEY: string; + SECRET: string; + CLUSTER: string; + USE_TLS: boolean; +}; + export type CacheConfRedis = { ENABLED: boolean; URI: string; @@ -186,12 +221,15 @@ export type CacheConfLocal = { }; export type SslConf = { PRIVKEY: string; FULLCHAIN: string }; export type Webhook = { GLOBAL?: GlobalWebhook; EVENTS: EventsWebhook }; +export type Pusher = { ENABLED: boolean; GLOBAL?: GlobalPusher; EVENTS: EventsPusher }; export type ConfigSessionPhone = { CLIENT: string; NAME: string; VERSION: string }; export type QrCode = { LIMIT: number; COLOR: string }; -export type Typebot = { API_VERSION: string; KEEP_OPEN: boolean }; +export type Typebot = { ENABLED: boolean; API_VERSION: string; SEND_MEDIA_BASE64: boolean }; export type Chatwoot = { + ENABLED: boolean; MESSAGE_DELETE: boolean; MESSAGE_READ: boolean; + BOT_CONTACT: boolean; IMPORT: { DATABASE: { CONNECTION: { @@ -201,6 +239,19 @@ export type Chatwoot = { PLACEHOLDER_MEDIA_MESSAGE: boolean; }; }; +export type Openai = { ENABLED: boolean; API_KEY_GLOBAL?: string }; +export type Dify = { ENABLED: boolean }; + +export type S3 = { + ACCESS_KEY: string; + SECRET_KEY: string; + ENDPOINT: string; + BUCKET_NAME: string; + ENABLE: boolean; + PORT?: number; + USE_SSL?: boolean; + REGION?: string; +}; export type CacheConf = { REDIS: CacheConfRedis; LOCAL: CacheConfLocal }; export type Production = boolean; @@ -209,8 +260,7 @@ export interface Env { SERVER: HttpServer; CORS: Cors; SSL_CONF: SslConf; - STORE: StoreConf; - CLEAN_STORE: CleanStoreConf; + PROVIDER: ProviderSession; DATABASE: Database; RABBITMQ: Rabbitmq; SQS: Sqs; @@ -221,11 +271,15 @@ export interface Env { DEL_TEMP_INSTANCES: boolean; LANGUAGE: Language; WEBHOOK: Webhook; + PUSHER: Pusher; CONFIG_SESSION_PHONE: ConfigSessionPhone; QRCODE: QrCode; TYPEBOT: Typebot; CHATWOOT: Chatwoot; + OPENAI: Openai; + DIFY: Dify; CACHE: CacheConf; + S3?: S3; AUTHENTICATION: Auth; PRODUCTION?: Production; } @@ -244,7 +298,7 @@ export class ConfigService { } private loadEnv() { - this.env = !(process.env?.DOCKER_ENV === 'true') ? this.envYaml() : this.envProcess(); + this.env = this.envProcess(); this.env.PRODUCTION = process.env?.NODE_ENV === 'PROD'; if (process.env?.DOCKER_ENV === 'true') { this.env.SERVER.TYPE = process.env.SERVER_TYPE as 'http' | 'http'; @@ -252,10 +306,6 @@ export class ConfigService { } } - private envYaml(): Env { - return load(readFileSync(join(process.cwd(), 'src', 'env.yml'), { encoding: 'utf-8' })) as Env; - } - private envProcess(): Env { return { SERVER: { @@ -266,48 +316,47 @@ export class ConfigService { DISABLE_MANAGER: process.env?.SERVER_DISABLE_MANAGER === 'true', }, CORS: { - ORIGIN: process.env.CORS_ORIGIN.split(',') || ['*'], - METHODS: (process.env.CORS_METHODS.split(',') as HttpMethods[]) || ['POST', 'GET', 'PUT', 'DELETE'], + ORIGIN: process.env.CORS_ORIGIN?.split(',') || ['*'], + METHODS: + (process.env.CORS_METHODS?.split(',') as HttpMethods[]) || + (['POST', 'GET', 'PUT', 'DELETE'] as HttpMethods[]), CREDENTIALS: process.env?.CORS_CREDENTIALS === 'true', }, SSL_CONF: { PRIVKEY: process.env?.SSL_CONF_PRIVKEY || '', FULLCHAIN: process.env?.SSL_CONF_FULLCHAIN || '', }, - STORE: { - MESSAGES: process.env?.STORE_MESSAGES === 'true', - MESSAGE_UP: process.env?.STORE_MESSAGE_UP === 'true', - CONTACTS: process.env?.STORE_CONTACTS === 'true', - CHATS: process.env?.STORE_CHATS === 'true', - LABELS: process.env?.STORE_LABELS === 'true', - }, - CLEAN_STORE: { - CLEANING_INTERVAL: Number.isInteger(process.env?.CLEAN_STORE_CLEANING_INTERVAL) - ? Number.parseInt(process.env.CLEAN_STORE_CLEANING_INTERVAL) - : 7200, - MESSAGES: process.env?.CLEAN_STORE_MESSAGES === 'true', - MESSAGE_UP: process.env?.CLEAN_STORE_MESSAGE_UP === 'true', - CONTACTS: process.env?.CLEAN_STORE_CONTACTS === 'true', - CHATS: process.env?.CLEAN_STORE_CHATS === 'true', + PROVIDER: { + ENABLED: process.env?.PROVIDER_ENABLED === 'true', + HOST: process.env.PROVIDER_HOST, + PORT: process.env?.PROVIDER_PORT || '5656', + PREFIX: process.env?.PROVIDER_PREFIX || 'evolution', }, DATABASE: { CONNECTION: { URI: process.env.DATABASE_CONNECTION_URI || '', - DB_PREFIX_NAME: process.env.DATABASE_CONNECTION_DB_PREFIX_NAME || 'evolution', + CLIENT_NAME: process.env.DATABASE_CONNECTION_CLIENT_NAME || 'evolution', }, - ENABLED: process.env?.DATABASE_ENABLED === 'true', + PROVIDER: process.env.DATABASE_PROVIDER || 'postgresql', SAVE_DATA: { INSTANCE: process.env?.DATABASE_SAVE_DATA_INSTANCE === 'true', NEW_MESSAGE: process.env?.DATABASE_SAVE_DATA_NEW_MESSAGE === 'true', MESSAGE_UPDATE: process.env?.DATABASE_SAVE_MESSAGE_UPDATE === 'true', CONTACTS: process.env?.DATABASE_SAVE_DATA_CONTACTS === 'true', CHATS: process.env?.DATABASE_SAVE_DATA_CHATS === 'true', + HISTORIC: process.env?.DATABASE_SAVE_DATA_HISTORIC === 'true', LABELS: process.env?.DATABASE_SAVE_DATA_LABELS === 'true', + IS_ON_WHATSAPP: process.env?.DATABASE_SAVE_IS_ON_WHATSAPP === 'true', + IS_ON_WHATSAPP_DAYS: Number.parseInt(process.env?.DATABASE_SAVE_IS_ON_WHATSAPP_DAYS ?? '7'), + }, + DELETE_DATA: { + LOGICAL_MESSAGE_DELETE: process.env?.DATABASE_DELETE_MESSAGE === 'true', }, }, RABBITMQ: { ENABLED: process.env?.RABBITMQ_ENABLED === 'true', GLOBAL_ENABLED: process.env?.RABBITMQ_GLOBAL_ENABLED === 'true', + PREFIX_KEY: process.env?.RABBITMQ_PREFIX_KEY || 'evolution', EXCHANGE_NAME: process.env?.RABBITMQ_EXCHANGE_NAME || 'evolution_exchange', URI: process.env.RABBITMQ_URI || '', EVENTS: { @@ -317,6 +366,7 @@ export class ConfigService { QRCODE_UPDATED: process.env?.RABBITMQ_EVENTS_QRCODE_UPDATED === 'true', MESSAGES_SET: process.env?.RABBITMQ_EVENTS_MESSAGES_SET === 'true', MESSAGES_UPSERT: process.env?.RABBITMQ_EVENTS_MESSAGES_UPSERT === 'true', + MESSAGES_EDITED: process.env?.RABBITMQ_EVENTS_MESSAGES_EDITED === 'true', MESSAGES_UPDATE: process.env?.RABBITMQ_EVENTS_MESSAGES_UPDATE === 'true', MESSAGES_DELETE: process.env?.RABBITMQ_EVENTS_MESSAGES_DELETE === 'true', SEND_MESSAGE: process.env?.RABBITMQ_EVENTS_SEND_MESSAGE === 'true', @@ -335,7 +385,6 @@ export class ConfigService { GROUP_UPDATE: process.env?.RABBITMQ_EVENTS_GROUPS_UPDATE === 'true', GROUP_PARTICIPANTS_UPDATE: process.env?.RABBITMQ_EVENTS_GROUP_PARTICIPANTS_UPDATE === 'true', CALL: process.env?.RABBITMQ_EVENTS_CALL === 'true', - NEW_JWT_TOKEN: process.env?.RABBITMQ_EVENTS_NEW_JWT_TOKEN === 'true', TYPEBOT_START: process.env?.RABBITMQ_EVENTS_TYPEBOT_START === 'true', TYPEBOT_CHANGE_STATUS: process.env?.RABBITMQ_EVENTS_TYPEBOT_CHANGE_STATUS === 'true', }, @@ -351,23 +400,56 @@ export class ConfigService { ENABLED: process.env?.WEBSOCKET_ENABLED === 'true', GLOBAL_EVENTS: process.env?.WEBSOCKET_GLOBAL_EVENTS === 'true', }, + PUSHER: { + ENABLED: process.env?.PUSHER_ENABLED === 'true', + GLOBAL: { + ENABLED: process.env?.PUSHER_GLOBAL_ENABLED === 'true', + APP_ID: process.env?.PUSHER_GLOBAL_APP_ID || '', + KEY: process.env?.PUSHER_GLOBAL_KEY || '', + SECRET: process.env?.PUSHER_GLOBAL_SECRET || '', + CLUSTER: process.env?.PUSHER_GLOBAL_CLUSTER || '', + USE_TLS: process.env?.PUSHER_GLOBAL_USE_TLS === 'true', + }, + EVENTS: { + APPLICATION_STARTUP: process.env?.PUSHER_EVENTS_APPLICATION_STARTUP === 'true', + INSTANCE_CREATE: process.env?.PUSHER_EVENTS_INSTANCE_CREATE === 'true', + INSTANCE_DELETE: process.env?.PUSHER_EVENTS_INSTANCE_DELETE === 'true', + QRCODE_UPDATED: process.env?.PUSHER_EVENTS_QRCODE_UPDATED === 'true', + MESSAGES_SET: process.env?.PUSHER_EVENTS_MESSAGES_SET === 'true', + MESSAGES_UPSERT: process.env?.PUSHER_EVENTS_MESSAGES_UPSERT === 'true', + MESSAGES_EDITED: process.env?.PUSHER_EVENTS_MESSAGES_EDITED === 'true', + MESSAGES_UPDATE: process.env?.PUSHER_EVENTS_MESSAGES_UPDATE === 'true', + MESSAGES_DELETE: process.env?.PUSHER_EVENTS_MESSAGES_DELETE === 'true', + SEND_MESSAGE: process.env?.PUSHER_EVENTS_SEND_MESSAGE === 'true', + CONTACTS_SET: process.env?.PUSHER_EVENTS_CONTACTS_SET === 'true', + CONTACTS_UPDATE: process.env?.PUSHER_EVENTS_CONTACTS_UPDATE === 'true', + CONTACTS_UPSERT: process.env?.PUSHER_EVENTS_CONTACTS_UPSERT === 'true', + PRESENCE_UPDATE: process.env?.PUSHER_EVENTS_PRESENCE_UPDATE === 'true', + CHATS_SET: process.env?.PUSHER_EVENTS_CHATS_SET === 'true', + CHATS_UPDATE: process.env?.PUSHER_EVENTS_CHATS_UPDATE === 'true', + CHATS_UPSERT: process.env?.PUSHER_EVENTS_CHATS_UPSERT === 'true', + CHATS_DELETE: process.env?.PUSHER_EVENTS_CHATS_DELETE === 'true', + CONNECTION_UPDATE: process.env?.PUSHER_EVENTS_CONNECTION_UPDATE === 'true', + LABELS_EDIT: process.env?.PUSHER_EVENTS_LABELS_EDIT === 'true', + LABELS_ASSOCIATION: process.env?.PUSHER_EVENTS_LABELS_ASSOCIATION === 'true', + GROUPS_UPSERT: process.env?.PUSHER_EVENTS_GROUPS_UPSERT === 'true', + GROUP_UPDATE: process.env?.PUSHER_EVENTS_GROUPS_UPDATE === 'true', + GROUP_PARTICIPANTS_UPDATE: process.env?.PUSHER_EVENTS_GROUP_PARTICIPANTS_UPDATE === 'true', + CALL: process.env?.PUSHER_EVENTS_CALL === 'true', + TYPEBOT_START: process.env?.PUSHER_EVENTS_TYPEBOT_START === 'true', + TYPEBOT_CHANGE_STATUS: process.env?.PUSHER_EVENTS_TYPEBOT_CHANGE_STATUS === 'true', + }, + }, WA_BUSINESS: { - TOKEN_WEBHOOK: process.env.WA_BUSINESS_TOKEN_WEBHOOK || '', - URL: process.env.WA_BUSINESS_URL || '', - VERSION: process.env.WA_BUSINESS_VERSION || '', + TOKEN_WEBHOOK: process.env.WA_BUSINESS_TOKEN_WEBHOOK || 'evolution', + URL: process.env.WA_BUSINESS_URL || 'https://graph.facebook.com', + VERSION: process.env.WA_BUSINESS_VERSION || 'v18.0', LANGUAGE: process.env.WA_BUSINESS_LANGUAGE || 'en', }, LOG: { - LEVEL: (process.env?.LOG_LEVEL.split(',') as LogLevel[]) || [ - 'ERROR', - 'WARN', - 'DEBUG', - 'INFO', - 'LOG', - 'VERBOSE', - 'DARK', - 'WEBHOOKS', - ], + LEVEL: + (process.env?.LOG_LEVEL?.split(',') as LogLevel[]) || + (['ERROR', 'WARN', 'DEBUG', 'INFO', 'LOG', 'VERBOSE', 'DARK', 'WEBHOOKS', 'WEBSOCKET'] as LogLevel[]), COLOR: process.env?.LOG_COLOR === 'true', BAILEYS: (process.env?.LOG_BAILEYS as LogBaileys) || 'error', }, @@ -391,6 +473,7 @@ export class ConfigService { QRCODE_UPDATED: process.env?.WEBHOOK_EVENTS_QRCODE_UPDATED === 'true', MESSAGES_SET: process.env?.WEBHOOK_EVENTS_MESSAGES_SET === 'true', MESSAGES_UPSERT: process.env?.WEBHOOK_EVENTS_MESSAGES_UPSERT === 'true', + MESSAGES_EDITED: process.env?.WEBHOOK_EVENTS_MESSAGES_EDITED === 'true', MESSAGES_UPDATE: process.env?.WEBHOOK_EVENTS_MESSAGES_UPDATE === 'true', MESSAGES_DELETE: process.env?.WEBHOOK_EVENTS_MESSAGES_DELETE === 'true', SEND_MESSAGE: process.env?.WEBHOOK_EVENTS_SEND_MESSAGE === 'true', @@ -409,10 +492,8 @@ export class ConfigService { GROUP_UPDATE: process.env?.WEBHOOK_EVENTS_GROUPS_UPDATE === 'true', GROUP_PARTICIPANTS_UPDATE: process.env?.WEBHOOK_EVENTS_GROUP_PARTICIPANTS_UPDATE === 'true', CALL: process.env?.WEBHOOK_EVENTS_CALL === 'true', - NEW_JWT_TOKEN: process.env?.WEBHOOK_EVENTS_NEW_JWT_TOKEN === 'true', TYPEBOT_START: process.env?.WEBHOOK_EVENTS_TYPEBOT_START === 'true', TYPEBOT_CHANGE_STATUS: process.env?.WEBHOOK_EVENTS_TYPEBOT_CHANGE_STATUS === 'true', - CHAMA_AI_ACTION: process.env?.WEBHOOK_EVENTS_CHAMA_AI_ACTION === 'true', ERRORS: process.env?.WEBHOOK_EVENTS_ERRORS === 'true', ERRORS_WEBHOOK: process.env?.WEBHOOK_EVENTS_ERRORS_WEBHOOK || '', }, @@ -427,12 +508,15 @@ export class ConfigService { COLOR: process.env.QRCODE_COLOR || '#198754', }, TYPEBOT: { + ENABLED: process.env?.TYPEBOT_ENABLED === 'true', API_VERSION: process.env?.TYPEBOT_API_VERSION || 'old', - KEEP_OPEN: process.env.TYPEBOT_KEEP_OPEN === 'true', + SEND_MEDIA_BASE64: process.env?.TYPEBOT_SEND_MEDIA_BASE64 === 'true', }, CHATWOOT: { - MESSAGE_DELETE: process.env.CHATWOOT_MESSAGE_DELETE === 'false', - MESSAGE_READ: process.env.CHATWOOT_MESSAGE_READ === 'false', + ENABLED: process.env?.CHATWOOT_ENABLED === 'true', + MESSAGE_DELETE: process.env.CHATWOOT_MESSAGE_DELETE === 'true', + MESSAGE_READ: process.env.CHATWOOT_MESSAGE_READ === 'true', + BOT_CONTACT: !process.env.CHATWOOT_BOT_CONTACT || process.env.CHATWOOT_BOT_CONTACT === 'true', IMPORT: { DATABASE: { CONNECTION: { @@ -442,6 +526,13 @@ export class ConfigService { PLACEHOLDER_MEDIA_MESSAGE: process.env?.CHATWOOT_IMPORT_PLACEHOLDER_MEDIA_MESSAGE === 'true', }, }, + OPENAI: { + ENABLED: process.env?.OPENAI_ENABLED === 'true', + API_KEY_GLOBAL: process.env?.OPENAI_API_KEY_GLOBAL || null, + }, + DIFY: { + ENABLED: process.env?.DIFY_ENABLED === 'true', + }, CACHE: { REDIS: { ENABLED: process.env?.CACHE_REDIS_ENABLED === 'true', @@ -455,18 +546,21 @@ export class ConfigService { TTL: Number.parseInt(process.env?.CACHE_REDIS_TTL) || 86400, }, }, + S3: { + ACCESS_KEY: process.env?.S3_ACCESS_KEY, + SECRET_KEY: process.env?.S3_SECRET_KEY, + ENDPOINT: process.env?.S3_ENDPOINT, + BUCKET_NAME: process.env?.S3_BUCKET, + ENABLE: process.env?.S3_ENABLED === 'true', + PORT: Number.parseInt(process.env?.S3_PORT || '9000'), + USE_SSL: process.env?.S3_USE_SSL === 'true', + REGION: process.env?.S3_REGION, + }, AUTHENTICATION: { - TYPE: process.env.AUTHENTICATION_TYPE as 'apikey', API_KEY: { KEY: process.env.AUTHENTICATION_API_KEY || 'BQYHJGJHJ', }, EXPOSE_IN_FETCH_INSTANCES: process.env?.AUTHENTICATION_EXPOSE_IN_FETCH_INSTANCES === 'true', - JWT: { - EXPIRIN_IN: Number.isInteger(process.env?.AUTHENTICATION_JWT_EXPIRIN_IN) - ? Number.parseInt(process.env.AUTHENTICATION_JWT_EXPIRIN_IN) - : 3600, - SECRET: process.env.AUTHENTICATION_JWT_SECRET || 'L=0YWt]b2w[WF>#>:&E`', - }, }, }; } diff --git a/src/config/error.config.ts b/src/config/error.config.ts index 6449d52e..302c67d1 100644 --- a/src/config/error.config.ts +++ b/src/config/error.config.ts @@ -15,7 +15,7 @@ export function onUnexpectedError() { logger.error({ origin, stderr: process.stderr.fd, - error, }); + logger.error(error); }); } diff --git a/src/config/event.config.ts b/src/config/event.config.ts index 8451ffdf..20cd1e40 100644 --- a/src/config/event.config.ts +++ b/src/config/event.config.ts @@ -1,7 +1,10 @@ import EventEmitter2 from 'eventemitter2'; +const maxListeners = parseInt(process.env.EVENT_EMITTER_MAX_LISTENERS, 10) || 50; + export const eventEmitter = new EventEmitter2({ delimiter: '.', newListener: false, ignoreErrors: false, + maxListeners: maxListeners, }); diff --git a/src/config/logger.config.ts b/src/config/logger.config.ts index c52d3ccc..bc27db5c 100644 --- a/src/config/logger.config.ts +++ b/src/config/logger.config.ts @@ -58,7 +58,11 @@ enum Background { export class Logger { private readonly configService = configService; - constructor(private context = 'Logger') {} + private context: string; + + constructor(context = 'Logger') { + this.context = context; + } private instance = null; diff --git a/src/dev-env.yml b/src/dev-env.yml deleted file mode 100644 index 23e1b479..00000000 --- a/src/dev-env.yml +++ /dev/null @@ -1,228 +0,0 @@ -# ⚠️ -# ⚠️ ALL SETTINGS DEFINED IN THIS FILE ARE APPLIED TO ALL INSTANCES. -# ⚠️ - -# ⚠️ RENAME THIS FILE TO env.yml - -# Choose the server type for the application -SERVER: - TYPE: http # https - PORT: 8080 # 443 - URL: localhost - DISABLE_MANAGER: false - DISABLE_DOCS: false - -CORS: - ORIGIN: - - "*" - # - yourdomain.com - METHODS: - - POST - - GET - - PUT - - DELETE - CREDENTIALS: true - -# Install ssl certificate and replace string with domain name -# Access: https://certbot.eff.org/instructions?ws=other&os=ubuntufocal -SSL_CONF: - PRIVKEY: /etc/letsencrypt/live//privkey.pem - FULLCHAIN: /etc/letsencrypt/live//fullchain.pem - -# Determine the logs to be displayed -LOG: - LEVEL: - - ERROR - - WARN - - DEBUG - - INFO - - LOG - - VERBOSE - - DARK - - WEBHOOKS - COLOR: true - BAILEYS: error # fatal | error | warn | info | debug | trace - -# Determine how long the instance should be deleted from memory in case of no connection. -# Default time: 5 minutes -# If you don't even want an expiration, enter the value false -DEL_INSTANCE: false # or false -DEL_TEMP_INSTANCES: true # Delete instances with status closed on start - -# Temporary data storage -STORE: - MESSAGES: true - MESSAGE_UP: true - CONTACTS: true - CHATS: true - -CLEAN_STORE: - CLEANING_INTERVAL: 7200 # 7200 seconds === 2h - MESSAGES: true - MESSAGE_UP: true - CONTACTS: true - CHATS: true - -# Permanent data storage -DATABASE: - ENABLED: false - CONNECTION: - URI: "mongodb://root:root@localhost:27017/?authSource=admin&readPreference=primary&ssl=false&directConnection=true" - DB_PREFIX_NAME: evolution - # Choose the data you want to save in the application's database or store - SAVE_DATA: - INSTANCE: false - NEW_MESSAGE: false - MESSAGE_UPDATE: false - CONTACTS: false - CHATS: false - -RABBITMQ: - ENABLED: false - URI: "amqp://guest:guest@localhost:5672" - EXCHANGE_NAME: evolution_exchange - GLOBAL_ENABLED: true - EVENTS: - APPLICATION_STARTUP: false - INSTANCE_CREATE: false - INSTANCE_DELETE: false - QRCODE_UPDATED: false - MESSAGES_SET: false - MESSAGES_UPSERT: true - MESSAGES_UPDATE: true - MESSAGES_DELETE: false - SEND_MESSAGE: false - CONTACTS_SET: false - CONTACTS_UPSERT: false - CONTACTS_UPDATE: false - PRESENCE_UPDATE: false - CHATS_SET: false - CHATS_UPSERT: false - CHATS_UPDATE: false - CHATS_DELETE: false - GROUPS_UPSERT: true - GROUP_UPDATE: true - GROUP_PARTICIPANTS_UPDATE: true - CONNECTION_UPDATE: true - CALL: false - # This events is used with Typebot - TYPEBOT_START: false - TYPEBOT_CHANGE_STATUS: false - -SQS: - ENABLED: true - ACCESS_KEY_ID: "" - SECRET_ACCESS_KEY: "" - ACCOUNT_ID: "" - REGION: "us-east-1" - -WEBSOCKET: - ENABLED: false - GLOBAL_EVENTS: false - -WA_BUSINESS: - TOKEN_WEBHOOK: evolution - URL: https://graph.facebook.com - VERSION: v18.0 - LANGUAGE: pt_BR - -# Global Webhook Settings -# Each instance's Webhook URL and events will be requested at the time it is created -WEBHOOK: - # Define a global webhook that will listen for enabled events from all instances - GLOBAL: - URL: - ENABLED: false - # With this option activated, you work with a url per webhook event, respecting the global url and the name of each event - WEBHOOK_BY_EVENTS: false - # Automatically maps webhook paths - # Set the events you want to hear - EVENTS: - APPLICATION_STARTUP: false - QRCODE_UPDATED: true - MESSAGES_SET: true - MESSAGES_UPSERT: true - MESSAGES_UPDATE: true - MESSAGES_DELETE: true - SEND_MESSAGE: true - CONTACTS_SET: true - CONTACTS_UPSERT: true - CONTACTS_UPDATE: true - PRESENCE_UPDATE: true - CHATS_SET: true - CHATS_UPSERT: true - CHATS_UPDATE: true - CHATS_DELETE: true - GROUPS_UPSERT: true - GROUP_UPDATE: true - GROUP_PARTICIPANTS_UPDATE: true - CONNECTION_UPDATE: true - LABELS_EDIT: true - LABELS_ASSOCIATION: true - CALL: true - # This event fires every time a new token is requested via the refresh route - NEW_JWT_TOKEN: false - # This events is used with Typebot - TYPEBOT_START: false - TYPEBOT_CHANGE_STATUS: false - # This event is used with Chama AI - CHAMA_AI_ACTION: false - # This event is used to send errors to the webhook - ERRORS: false - ERRORS_WEBHOOK: - -CONFIG_SESSION_PHONE: - # Name that will be displayed on smartphone connection - CLIENT: "Evolution API" - NAME: Chrome # Chrome | Firefox | Edge | Opera | Safari - -# Set qrcode display limit -QRCODE: - LIMIT: 30 - COLOR: "#198754" - -TYPEBOT: - API_VERSION: "old" # old | latest - KEEP_OPEN: false - -CHATWOOT: - # If you leave this option as false, when deleting the message for everyone on WhatsApp, it will not be deleted on Chatwoot. - MESSAGE_DELETE: true # false | true - # If you leave this option as true, when sending a message in Chatwoot, the client's last message will be marked as read on WhatsApp. - MESSAGE_READ: false # false | true - IMPORT: - # This db connection is used to import messages from whatsapp to chatwoot database - DATABASE: - CONNECTION: - URI: "postgres://user:password@hostname:port/dbname?sslmode=disable" - PLACEHOLDER_MEDIA_MESSAGE: true - -# Cache to optimize application performance -CACHE: - REDIS: - ENABLED: false - URI: "redis://localhost:6379" - PREFIX_KEY: "evolution" - TTL: 604800 - SAVE_INSTANCES: false - LOCAL: - ENABLED: false - TTL: 86400 - -# Defines an authentication type for the api -# We recommend using the apikey because it will allow you to use a custom token, -# if you use jwt, a random token will be generated and may be expired and you will have to generate a new token -AUTHENTICATION: - TYPE: apikey # jwt or apikey - # Define a global apikey to access all instances - API_KEY: - # OBS: This key must be inserted in the request header to create an instance. - KEY: B6D711FCDE4D4FD5936544120E713976 - # Expose the api key on return from fetch instances - EXPOSE_IN_FETCH_INSTANCES: true - # Set the secret key to encrypt and decrypt your token and its expiration time. - JWT: - EXPIRIN_IN: 0 # seconds - 3600s === 1h | zero (0) - never expires - SECRET: L=0YWt]b2w[WF>#>:&E` - -LANGUAGE: "pt-BR" # pt-BR, en diff --git a/src/docs/swagger.conf.ts b/src/docs/swagger.conf.ts deleted file mode 100644 index 7ce42bae..00000000 --- a/src/docs/swagger.conf.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Router } from 'express'; -import { join } from 'path'; -import swaggerUi from 'swagger-ui-express'; -import YAML from 'yamljs'; - -const document = YAML.load(join(process.cwd(), 'src', 'docs', 'swagger.yaml')); - -const router = Router(); - -export const swaggerRouter = router.use('/docs', swaggerUi.serve).get( - '/docs', - swaggerUi.setup(document, { - customCssUrl: '/css/dark-theme-swagger.css', - customSiteTitle: 'Evolution API', - customfavIcon: '/images/logo.svg', - }), -); diff --git a/src/docs/swagger.yaml b/src/docs/swagger.yaml deleted file mode 100644 index 59b252d3..00000000 --- a/src/docs/swagger.yaml +++ /dev/null @@ -1,2777 +0,0 @@ -openapi: 3.0.0 -info: - title: Evolution API - description: | -
-
- -
- - [![Whatsapp Group](https://img.shields.io/badge/Group-WhatsApp-%2322BC18)](https://evolution-api.com/whatsapp) - [![Discord Community](https://img.shields.io/badge/Discord-Community-blue)](https://evolution-api.com/discord) - [![Postman Collection](https://img.shields.io/badge/Postman-Collection-orange)](https://evolution-api.com/postman) - [![Documentation](https://img.shields.io/badge/Documentation-Official-green)](https://doc.evolution-api.com) - [![License](https://img.shields.io/badge/license-GPL--3.0-orange)](./LICENSE) - [![Support](https://img.shields.io/badge/Donation-picpay-green)](https://app.picpay.com/user/davidsongomes1998) - [![Support](https://img.shields.io/badge/Buy%20me-coffe-orange)](https://bmc.link/evolutionapi) - -
- -
- - - This project is based on the [evolution](https://github.com/code-chat-br/whatsapp-api). The original project is an implementation of [Baileys](https://github.com/WhiskeySockets/Baileys), serving as a Restful API service that controls WhatsApp functions.
- The code allows the creation of multiservice chats, service bots, or any other system that utilizes WhatsApp. The documentation provides instructions on how to set up and use the project, as well as additional information about its features and configuration options. -
- - [![Run in Postman](https://run.pstmn.io/button.svg)](https://god.gw.postman.com/run-collection/26869335-5546d063-156b-4529-915f-909dd628c090?action=collection%2Ffork&source=rip_markdown&collection-url=entityId%3D26869335-5546d063-156b-4529-915f-909dd628c090%26entityType%3Dcollection%26workspaceId%3D339a4ee7-378b-45c9-b5b8-fd2c0a9c2442) - version: 1.8.0 - contact: - name: DavidsonGomes - email: contato@agenciadgcode.com - url: https://img.shields.io/badge/license-GPL--3.0-orange - license: - name: GNU General Public License v3.0 - url: https://github.com/EvolutionAPI/evolution-api/blob/main/LICENSE -servers: [] -components: - securitySchemes: - apikeyAuth: - type: apiKey - in: header - name: apikey - bearerAuth: - type: http - scheme: bearer - bearerFormat: JWT -security: - - bearerAuth: [] -tags: - - name: Instance Controller - - name: Send Message Controller - - name: Chat Controller - - name: Group Controller - - name: Label Controller - - name: Profile Settings - - name: JWT - - name: Settings - - name: Webhook - - name: Websocket - - name: RabbitMQ - - name: Chatwoot - - name: Typebot - - name: Proxy - - name: Chama AI -paths: - /instance/create: - post: - tags: - - Instance Controller - summary: Create Instance - requestBody: - content: - application/json: - schema: - type: object - properties: - instanceName: - type: string - description: Name of the instance (optional). - token: - type: string - description: Token of the instance (optional). - qrcode: - type: boolean - description: QR Code of the instance (optional). - example: - instanceName: "exampleInstance" - token: "87F3F7D0-4B8A-45D0-8618-7399E4AD6469" - qrcode: true - security: - - apikeyAuth: [] - responses: - "200": - description: Successful response - content: - application/json: {} - /instance/fetchInstances: - get: - tags: - - Instance Controller - summary: Fetch Instances - security: - - apikeyAuth: [] - parameters: - - name: instanceName - in: query - schema: - type: string - description: Retrieve one or all instances (optional). - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: - schema: - type: array - items: - type: object - properties: - instance: - type: object - properties: - instanceName: - type: string - owner: - type: string - profileName: - type: string - profilePictureUrl: - type: string - profileStatus: - type: string - status: - type: string - serverUrl: - type: string - apikey: - type: string - /instance/connect/{instanceName}: - get: - tags: - - Instance Controller - summary: Instance Connect - parameters: - - name: instanceName - in: path - required: true - schema: - type: string - description: Connect to your instance. - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: - schema: - type: object - properties: - code: - type: string - base64: - type: string - description: The QR Code as a string. - /instance/restart/{instanceName}: - put: - tags: - - Instance Controller - summary: Instance Restart - parameters: - - name: instanceName - in: path - required: true - schema: - type: string - description: Connect to your instance. - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /instance/connectionState/{instanceName}: - get: - tags: - - Instance Controller - summary: Connection Status - parameters: - - name: instanceName - in: path - required: true - schema: - type: string - description: Check the connection state of your instance. - example: "evolution" - security: - - apikeyAuth: [] - responses: - "200": - description: Successful response - content: - application/json: {} - /instance/logout/{instanceName}: - delete: - tags: - - Instance Controller - summary: Logout Instance - parameters: - - name: instanceName - in: path - required: true - schema: - type: string - description: Logout from your instance. - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /instance/delete/{instanceName}: - delete: - tags: - - Instance Controller - summary: Delete Instance - parameters: - - name: instanceName - in: path - required: true - schema: - type: string - description: Delete your instance. - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - - /message/sendText/{instanceName}: - post: - tags: - - Send Message Controller - summary: Send a text message to a specified instance. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - number: - type: string - description: The recipient's phone number. - example: "1234567890" - textMessage: - type: object - properties: - text: - type: string - description: The content of the text message. - example: "Hello, World!" - options: - type: object - properties: - delay: - type: integer - description: Delay time before sending the message. - presence: - type: string - enum: ["composing", "recording", "paused"] - description: Indicates the sender's action/status. - linkPreview: - type: boolean - description: Indicates whether to enable link preview. - quoted: - type: object - properties: - key: - type: object - properties: - remoteJid: - type: string - description: The ID of the recipient of the original message. - fromMe: - type: boolean - description: Indicates if the message was sent from the user. - id: - type: string - description: The ID of the original message. - message: - type: object - properties: - conversation: - type: string - description: The content of the quoted message. - mentions: - type: object - properties: - everyone: - type: boolean - description: Indicates whether to mention everyone. - mentioned: - type: array - items: - type: string - description: The phone numbers of the users to be mentioned. - required: - - number - - textMessage - parameters: - - name: instanceName - in: path - required: true - schema: - type: string - description: The name of the instance to which the message should be sent. - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /message/sendStatus/{instanceName}: - post: - tags: - - Send Message Controller - summary: Send a status message. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - statusMessage: - type: object - properties: - type: - type: string - enum: ["text", "image", "video", "audio"] - description: Type of the status message. - content: - type: string - description: The content of the status message. - backgroundColor: - type: string - description: The background color of the status message. - font: - type: integer - enum: [1, 2, 3, 4, 5] - description: The font of the status message. - allContacts: - type: boolean - description: Indicates whether to send the status message to all contacts. - statusJidList: - type: array - items: - type: string - description: The phone numbers of the users to whom the status message should be sent. - required: - - type - parameters: - - name: instanceName - in: path - required: true - schema: - type: string - description: The name of the instance to which the status message should be sent. - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /message/sendMedia/{instanceName}: - post: - tags: - - Send Message Controller - summary: Send a media message (image, video, document, audio) to a specified instance. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - number: - type: string - description: The recipient's phone number. - example: "1234567890" - mediaMessage: - type: object - properties: - mediatype: - type: string - enum: ["image", "document", "video", "audio"] - description: Type of the media content. - fileName: - type: string - description: Name of the media file (optional). - caption: - type: string - description: Caption to accompany the media. - media: - type: string - description: URL of the media content. - required: - - mediatype - - media - options: - type: object - properties: - delay: - type: integer - description: Delay time before sending the message. - presence: - type: string - enum: ["composing", "recording", "paused"] - description: Indicates the sender's action/status. - linkPreview: - type: boolean - description: Indicates whether to enable link preview. - quoted: - type: object - properties: - key: - type: object - properties: - remoteJid: - type: string - description: The ID of the recipient of the original message. - fromMe: - type: boolean - description: Indicates if the message was sent from the user. - id: - type: string - description: The ID of the original message. - message: - type: object - properties: - conversation: - type: string - description: The content of the quoted message. - mentions: - type: object - properties: - everyone: - type: boolean - description: Indicates whether to mention everyone. - mentioned: - type: array - items: - type: string - description: The phone numbers of the users to be mentioned. - parameters: - - name: instanceName - in: path - required: true - schema: - type: string - description: The name of the instance to which the media message should be sent. - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /message/sendWhatsAppAudio/{instanceName}: - post: - tags: - - Send Message Controller - summary: Send an audio message via WhatsApp to a specified instance. - description: This endpoint allows users to share an audio message. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - number: - type: string - description: The recipient's phone number. - example: "1234567890" - audioMessage: - type: object - properties: - audio: - type: string - description: URL of the audio file to be sent. - required: - - audio - options: - type: object - properties: - delay: - type: integer - description: Delay time before sending the message. - presence: - type: string - enum: ["composing", "recording", "paused"] - description: Indicates the sender's action/status. - linkPreview: - type: boolean - description: Indicates whether to enable link preview. - quoted: - type: object - properties: - key: - type: object - properties: - remoteJid: - type: string - description: The ID of the recipient of the original message. - fromMe: - type: boolean - description: Indicates if the message was sent from the user. - id: - type: string - description: The ID of the original message. - message: - type: object - properties: - conversation: - type: string - description: The content of the quoted message. - mentions: - type: object - properties: - everyone: - type: boolean - description: Indicates whether to mention everyone. - mentioned: - type: array - items: - type: string - description: The phone numbers of the users to be mentioned. - required: - - number - - audioMessage.audio - parameters: - - name: instanceName - in: path - required: true - schema: - type: string - description: The name of the instance to which the audio should be sent. - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /message/sendSticker/{instanceName}: - post: - tags: - - Send Message Controller - summary: Send an sticker to a specified instance. - description: This endpoint allows users to share an sticker message. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - number: - type: string - description: The recipient's phone number. - example: "1234567890" - stickerMessage: - type: object - properties: - image: - type: string - description: URL of the audio file to be sent. - required: - - image - options: - type: object - properties: - delay: - type: integer - description: Delay time before sending the message. - presence: - type: string - enum: ["composing", "recording", "paused"] - description: Indicates the sender's action/status. - required: - - number - - audioMessage.audio - parameters: - - name: instanceName - in: path - required: true - schema: - type: string - description: The name of the instance to which the audio should be sent. - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /message/sendLocation/{instanceName}: - post: - tags: - - Send Message Controller - summary: Send a location to a specified instance. - description: This endpoint allows users to share a location message. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - number: - type: string - description: The recipient's phone number. - example: "1234567890" - locationMessage: - type: object - properties: - name: - type: string - description: Name or title of the location. - address: - type: string - description: Detailed address of the location. - latitude: - type: number - description: Latitude of the location. - format: float - longitude: - type: number - description: Longitude of the location. - format: float - options: - type: object - properties: - delay: - type: integer - description: Delay time before sending the message. - presence: - type: string - enum: ["composing", "recording", "paused"] - description: Indicates the sender's action/status. - linkPreview: - type: boolean - description: Indicates whether to enable link preview. - quoted: - type: object - properties: - key: - type: object - properties: - remoteJid: - type: string - description: The ID of the recipient of the original message. - fromMe: - type: boolean - description: Indicates if the message was sent from the user. - id: - type: string - description: The ID of the original message. - message: - type: object - properties: - conversation: - type: string - description: The content of the quoted message. - mentions: - type: object - properties: - everyone: - type: boolean - description: Indicates whether to mention everyone. - mentioned: - type: array - items: - type: string - description: The phone numbers of the users to be mentioned. - required: - - number - - locationMessage.latitude - - locationMessage.longitude - parameters: - - name: instanceName - in: path - required: true - schema: - type: string - description: The name of the instance to which the location should be sent. - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /message/sendContact/{instanceName}: - post: - tags: - - Send Message Controller - summary: Send contact details to a specified instance. - description: This endpoint allows users to share one or multiple contact details. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - number: - type: string - description: The recipient's phone number. - example: "1234567890" - contactMessage: - type: array - items: - type: object - properties: - fullName: - type: string - description: Full name of the contact. - wuid: - type: string - description: Unique identifier for the contact. - phoneNumber: - type: string - description: Phone number of the contact. - organization: - type: string - description: Organization of the contact. - email: - type: string - description: Email address of the contact. - url: - type: string - description: Url of the contact. - required: - - fullName - - wuid - - phoneNumber - options: - type: object - properties: - delay: - type: integer - description: Delay time before sending the message. - presence: - type: string - enum: ["composing", "recording", "paused"] - description: Indicates the sender's action/status. - linkPreview: - type: boolean - description: Indicates whether to enable link preview. - quoted: - type: object - properties: - key: - type: object - properties: - remoteJid: - type: string - description: The ID of the recipient of the original message. - fromMe: - type: boolean - description: Indicates if the message was sent from the user. - id: - type: string - description: The ID of the original message. - message: - type: object - properties: - conversation: - type: string - description: The content of the quoted message. - mentions: - type: object - properties: - everyone: - type: boolean - description: Indicates whether to mention everyone. - mentioned: - type: array - items: - type: string - description: The phone numbers of the users to be mentioned. - required: - - number - parameters: - - name: instanceName - in: path - required: true - schema: - type: string - description: The name of the instance to which the contacts should be sent. - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /message/sendReaction/{instanceName}: - post: - tags: - - Send Message Controller - summary: Send a reaction to a specified instance. - description: This endpoint allows users to send a reaction to a message. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - reactionMessage: - type: object - properties: - key: - type: object - properties: - remoteJid: - type: string - description: The ID of the recipient of the original message. - fromMe: - type: boolean - description: Indicates if the reaction was sent from the user. - id: - type: string - description: The ID of the original message. - reaction: - type: string - maxLength: 1 - description: Reaction character (e.g., emoji). - required: - - key.remoteJid - - key.fromMe - - key.id - - reaction - parameters: - - name: instanceName - in: path - required: true - schema: - type: string - description: The name of the instance to which the reaction should be sent. - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /message/sendPoll/{instanceName}: - post: - tags: - - Send Message Controller - summary: Send a poll to a specified instance. - description: This endpoint allows users to send a poll to a chat. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - number: - type: string - description: The recipient's phone number. - example: "1234567890" - pollMessage: - type: object - properties: - name: - type: string - description: Name or title of the poll. - selectableCount: - type: integer - description: Number of selectable options. - values: - type: array - items: - type: string - description: The options of the poll. - options: - type: object - properties: - delay: - type: integer - description: Delay time before sending the message. - presence: - type: string - enum: ["composing", "recording", "paused"] - description: Indicates the sender's action/status. - linkPreview: - type: boolean - description: Indicates whether to enable link preview. - quoted: - type: object - properties: - key: - type: object - properties: - remoteJid: - type: string - description: The ID of the recipient of the original message. - fromMe: - type: boolean - description: Indicates if the message was sent from the user. - id: - type: string - description: The ID of the original message. - message: - type: object - properties: - conversation: - type: string - description: The content of the quoted message. - mentions: - type: object - properties: - everyone: - type: boolean - description: Indicates whether to mention everyone. - mentioned: - type: array - items: - type: string - description: The phone numbers of the users to be mentioned. - parameters: - - name: instanceName - in: path - required: true - schema: - type: string - description: The name of the instance to which the poll should be sent. - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /message/sendList/{instanceName}: - post: - tags: - - Send Message Controller - summary: Send a list to a specified instance. - description: This endpoint allows users to send a list to a chat. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - number: - type: string - options: - type: object - properties: - delay: - type: integer - presence: - type: string - listMessage: - type: object - properties: - title: - type: string - description: - type: string - footerText: - type: string - nullable: true - buttonText: - type: string - sections: - type: array - items: - type: object - properties: - title: - type: string - rows: - type: array - items: - type: object - properties: - title: - type: string - description: - type: string - rowId: - type: string - parameters: - - name: instanceName - in: path - required: true - schema: - type: string - description: The name of the instance to which the poll should be sent. - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - - /chat/whatsappNumbers/{instanceName}: - post: - tags: - - Chat Controller - summary: Provide a list of WhatsApp numbers associated with a given instance. - description: This endpoint returns information on the WhatsApp numbers associated with the specified instance. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - numbers: - type: array - items: - type: string - description: WhatsApp phone number. - example: - - "1234567890" - required: - - numbers - parameters: - - name: instanceName - in: path - required: true - schema: - type: string - description: The name of the instance to which the reaction should be sent. - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /chat/markMessageAsRead/{instanceName}: - put: - tags: - - Chat Controller - summary: Mark specific messages as read for a given instance. - description: This endpoint allows users to mark messages as read for a particular instance. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - read_messages: - type: array - items: - type: object - properties: - remoteJid: - type: string - description: ID of the recipient of the message. - fromMe: - type: boolean - description: Indicates if the message was sent from the user. - id: - type: string - description: Unique ID of the message. - required: - - remoteJid - - fromMe - - id - required: - - read_messages - parameters: - - name: instanceName - in: path - required: true - schema: - type: string - description: The name of the instance to which the reaction should be sent. - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /chat/archiveChat/{instanceName}: - put: - tags: - - Chat Controller - summary: Archive specific chats for a given instance. - description: This endpoint allows users to archive specific chats based on the last message. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - lastMessage: - type: object - properties: - key: - type: object - properties: - remoteJid: - type: string - description: ID of the recipient of the last message. - fromMe: - type: boolean - description: Indicates if the last message was sent from the user. - id: - type: string - description: Unique ID of the last message. - required: - - remoteJid - - fromMe - - id - archive: - type: boolean - description: Indicates whether to archive the chat. - example: true - required: - - lastMessage - - archive - parameters: - - name: instanceName - in: path - required: true - schema: - type: string - description: The name of the instance to which the reaction should be sent. - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /chat/deleteMessageForEveryone/{instanceName}: - delete: - tags: - - Chat Controller - summary: Delete a message for everyone in a given instance. - description: This endpoint allows users to delete a message for everyone in the chat. - parameters: - - name: instanceName - in: path - required: true - schema: - type: string - description: The name of the instance to which the reaction should be sent. - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /chat/fetchProfilePictureUrl/{instanceName}: - post: - tags: - - Chat Controller - summary: Retrieve the profile picture URL of a specific number. - description: This endpoint fetches the profile picture URL associated with the given phone number for the specified instance. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - number: - type: string - description: WhatsApp phone number whose profile picture URL needs to be fetched. - required: - - number - parameters: - - name: instanceName - in: path - required: true - schema: - type: string - description: The name of the instance to which the reaction should be sent. - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /chat/findContacts/{instanceName}: - post: - tags: - - Chat Controller - summary: Retrieve contact details using an ID. - description: This endpoint retrieves contact details associated with the given ID for the specified instance. - requestBody: - content: - application/json: - schema: - type: object - properties: - where: - type: object - properties: - id: - type: string - description: Unique ID of the contact to be fetched. - required: - - id - parameters: - - name: instanceName - in: path - required: true - schema: - type: string - description: The name of the instance to which the reaction should be sent. - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /chat/getBase64FromMediaMessage/{instanceName}: - post: - tags: - - Chat Controller - summary: Convert media message content to Base64. - description: This endpoint retrieves the Base64 representation of the content of a media message for the specified instance. - requestBody: - content: - application/json: - schema: - type: object - properties: - message: - type: object - properties: - key: - type: object - properties: - id: string - description: Unique ID of the message. - convertToMp4: - type: boolean - description: Indicates whether to convert the media to MP4 format. - example: true - parameters: - - name: instanceName - in: path - required: true - schema: - type: string - description: The name of the instance to which the reaction should be sent. - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /chat/findMessages/{instanceName}: - post: - tags: - - Chat Controller - summary: Search for messages based on specific criteria. - description: This endpoint retrieves messages that match the provided criteria for the specified instance. - requestBody: - content: - application/json: - schema: - type: object - properties: - where: - type: object - properties: - key: - type: object - properties: - remoteJid: - type: string - description: ID of the recipient of the message. - fromMe: - type: boolean - description: Indicates if the message was sent from the user. - id: - type: string - description: Unique ID of the message. - required: - - remoteJid - - fromMe - - id - message: - type: object - required: - - key - limit: - type: integer - description: Maximum number of messages to retrieve. - parameters: - - name: instanceName - in: path - required: true - schema: - type: string - description: The name of the instance to which the reaction should be sent. - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /chat/findStatusMessage/{instanceName}: - post: - tags: - - Chat Controller - summary: Search for status messages using an ID. - description: This endpoint retrieves status messages associated with the given ID for the specified instance. - requestBody: - content: - application/json: - schema: - type: object - properties: - where: - type: object - properties: - id: - type: string - description: Unique ID of the status message to be fetched. - required: - - id - parameters: - - name: instanceName - in: path - required: true - schema: - type: string - description: The name of the instance to which the reaction should be sent. - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /chat/findChats/{instanceName}: - get: - tags: - - Chat Controller - summary: List all chats associated with a specific instance. - description: This endpoint retrieves a list of all chats associated with the specified instance. - parameters: - - name: instanceName - in: path - required: true - schema: - type: string - description: The name of the instance to which the reaction should be sent. - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - - /group/create/{instanceName}: - post: - tags: - - Group Controller - summary: Create a new WhatsApp group. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - subject: - type: string - description: "- required - The name of the group." - description: - type: string - description: "- optional - A brief description or summary of the group." - participants: - type: array - items: - type: string - description: "- required - List of participant phone numbers." - parameters: - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /group/updateGroupPicture/{instanceName}: - put: - tags: - - Group Controller - summary: Update the group's display picture. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - image: - type: string - description: "- required - URL of the new group picture." - parameters: - - name: groupJid - in: query - schema: - type: string - description: "- required - The unique identifier of the group." - example: "120363046555718472@g.us" - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /group/updateGroupSubject/{instanceName}: - put: - tags: - - Group Controller - summary: Update the group's display picture. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - subject: - type: string - description: "- required - The new name of the group." - parameters: - - name: groupJid - in: query - schema: - type: string - description: "- required - The unique identifier of the group." - example: "120363046555718472@g.us" - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /group/updateGroupDescription/{instanceName}: - put: - tags: - - Group Controller - summary: Update the group's display picture. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - description: - type: string - description: "- required - The new description of the group." - parameters: - - name: groupJid - in: query - schema: - type: string - description: "- required - The unique identifier of the group." - example: "120363046555718472@g.us" - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /group/inviteCode/{instanceName}: - get: - tags: - - Group Controller - summary: Update the group's display picture. - parameters: - - name: groupJid - in: query - schema: - type: string - description: "- required - The unique identifier of the group." - example: "120363046555718472@g.us" - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /group/revokeInviteCode/{instanceName}: - put: - tags: - - Group Controller - summary: Update the group's display picture. - parameters: - - name: groupJid - in: query - schema: - type: string - description: "- required - The unique identifier of the group." - example: "120363046555718472@g.us" - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /group/sendInvite/{instanceName}: - post: - tags: - - Group Controller - summary: Update the group's display picture. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - groupJid: - type: string - description: "The unique identifier of the group." - description: - type: string - description: "The new description of the group." - numbers: - type: array - description: "List of participant phone numbers to be invited." - items: - type: string - parameters: - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /group/inviteInfo/{instanceName}: - get: - tags: - - Group Controller - summary: Retrieve details about a specific group. - parameters: - - name: inviteCode - in: query - schema: - type: string - description: "- required - The invite code of the group." - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /group/findGroupInfos/{instanceName}: - get: - tags: - - Group Controller - summary: Retrieve details about a specific group. - parameters: - - name: groupJid - in: query - schema: - type: string - description: "- required - The unique identifier of the group." - example: "120363046555718472@g.us" - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /group/fetchAllGroups/{instanceName}: - get: - tags: - - Group Controller - summary: Retrieve details about a specific group. - parameters: - - name: getParticipants - in: query - schema: - type: boolean - description: "- required - Indicates whether to retrieve the participants of the group." - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /group/participants/{instanceName}: - get: - tags: - - Group Controller - summary: Retrieve a list of participants in a specific group. - parameters: - - name: groupJid - in: query - schema: - type: string - description: "- required - The unique identifier of the group." - example: "120363046555718472@g.us" - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /group/updateParticipant/{instanceName}: - put: - tags: - - Group Controller - summary: Update the status or role of a participant in the group. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - action: - type: string - enum: ["add", "remove", "promote", "demote"] - description: "- required - The action to be taken on the participant." - participants: - type: array - items: - type: string - description: "- required - List of participant phone numbers to be updated." - parameters: - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /group/updateSetting/{instanceName}: - put: - tags: - - Group Controller - summary: Update the status or role of a participant in the group. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - action: - type: string - enum: - ["announcement", "not_announcement", "locked", "unlocked"] - description: "- required - The action to be taken on the participant." - parameters: - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /group/toggleEphemeral/{instanceName}: - put: - tags: - - Group Controller - summary: Update the status or role of a participant in the group. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - expiration: - type: number - description: "- required - The action to be taken on the participant." - parameters: - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /group/leaveGroup/{instanceName}: - delete: - tags: - - Group Controller - summary: Exit from the specified WhatsApp group. - parameters: - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - - /instance/refreshToken/: - put: - tags: - - JWT - summary: Refresh an expired JWT token. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - oldToken: - type: string - description: "- required - The expired JWT token." - responses: - "200": - description: Successful response - content: - application/json: {} - - /webhook/set/{instanceName}: - post: - tags: - - Webhook - summary: Set up or modify the webhook for an instance. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - url: - type: string - format: uri - description: "The endpoint URL where the webhook data will be sent." - webhook_by_events: - type: boolean - description: "Indicates whether to send the webhook data by events." - webhook_base64: - type: boolean - description: "Indicates whether to send the webhook data in Base64 format." - events: - type: array - enum: - [ - "APPLICATION_STARTUP", - "QRCODE_UPDATED", - "MESSAGES_SET", - "MESSAGES_UPSERT", - "MESSAGES_UPDATE", - "MESSAGES_DELETE", - "SEND_MESSAGE", - "CONTACTS_SET", - "CONTACTS_UPSERT", - "CONTACTS_UPDATE", - "PRESENCE_UPDATE", - "CHATS_SET", - "CHATS_UPSERT", - "CHATS_UPDATE", - "CHATS_DELETE", - "GROUPS_UPSERT", - "GROUP_UPDATE", - "GROUP_PARTICIPANTS_UPDATE", - "CONNECTION_UPDATE", - "LABELS_EDIT", - "LABELS_ASSOCIATION", - "CALL", - "NEW_JWT_TOKEN", - ] - items: - type: string - description: "List of events to be sent to the webhook." - parameters: - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /webhook/find/{instanceName}: - get: - tags: - - Webhook - summary: Retrieve the webhook settings for a specific instance. - parameters: - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - - /websocket/set/{instanceName}: - post: - tags: - - Websocket - summary: Set up or modify the Websocket for an instance. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - enabled: - type: boolean - description: "Indicates whether to enable the websocket." - events: - type: array - enum: - [ - "APPLICATION_STARTUP", - "QRCODE_UPDATED", - "MESSAGES_SET", - "MESSAGES_UPSERT", - "MESSAGES_UPDATE", - "MESSAGES_DELETE", - "SEND_MESSAGE", - "CONTACTS_SET", - "CONTACTS_UPSERT", - "CONTACTS_UPDATE", - "PRESENCE_UPDATE", - "CHATS_SET", - "CHATS_UPSERT", - "CHATS_UPDATE", - "CHATS_DELETE", - "GROUPS_UPSERT", - "GROUP_UPDATE", - "GROUP_PARTICIPANTS_UPDATE", - "CONNECTION_UPDATE", - "LABELS_EDIT", - "LABELS_ASSOCIATION", - "CALL", - "NEW_JWT_TOKEN", - ] - items: - type: string - description: "List of events to be sent to the websocket." - parameters: - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /websocket/find/{instanceName}: - get: - tags: - - Websocket - summary: Retrieve the websocket settings for a specific instance. - parameters: - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - - /rabbitmq/set/{instanceName}: - post: - tags: - - RabbitMQ - summary: Set up or modify the RabbitMQ for an instance. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - enabled: - type: boolean - description: "Indicates whether to enable the RabbitMQ." - events: - type: array - enum: - [ - "APPLICATION_STARTUP", - "QRCODE_UPDATED", - "MESSAGES_SET", - "MESSAGES_UPSERT", - "MESSAGES_UPDATE", - "MESSAGES_DELETE", - "SEND_MESSAGE", - "CONTACTS_SET", - "CONTACTS_UPSERT", - "CONTACTS_UPDATE", - "PRESENCE_UPDATE", - "CHATS_SET", - "CHATS_UPSERT", - "CHATS_UPDATE", - "CHATS_DELETE", - "GROUPS_UPSERT", - "GROUP_UPDATE", - "GROUP_PARTICIPANTS_UPDATE", - "CONNECTION_UPDATE", - "LABELS_EDIT", - "LABELS_ASSOCIATION", - "CALL", - "NEW_JWT_TOKEN", - ] - items: - type: string - description: "List of events to be sent to the RabbitMQ." - parameters: - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /rabbitmq/find/{instanceName}: - get: - tags: - - RabbitMQ - summary: Retrieve the RabbitMQ settings for a specific instance. - parameters: - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - - /label/findLabels/{instanceName}: - get: - tags: - - Label Controller - summary: List all labels for an instance. - parameters: - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: - schema: - type: array - items: - type: object - properties: - color: - type: integer - name: - type: string - id: - type: string - predefinedId: - type: string - required: - - color - - name - - id - /label/handleLabel/{instanceName}: - put: - tags: - - Label Controller - summary: Change the label (add or remove) for an specific chat. - parameters: - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - requestBody: - content: - application/json: - schema: - type: object - properties: - number: - type: string - labelId: - type: string - action: - type: string - enum: - - add - - remove - required: - - number - - labelId - - action - example: - number: '553499999999' - labelId: '1' - action: add - responses: - "200": - description: Successful response - content: - application/json: - schema: - type: object - properties: - numberJid: - type: string - labelId: - type: string - remove: - type: boolean - add: - type: boolean - required: - - numberJid - - labelId - - /settings/set/{instanceName}: - post: - tags: - - Settings - summary: Set up or modify the Settings for an instance. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - reject_call: - type: boolean - description: "Indicates whether to reject incoming calls." - msg_call: - type: string - description: "Message to be sent when rejecting a call." - groups_ignore: - type: boolean - description: "Indicates whether to ignore group messages." - always_online: - type: boolean - description: "Indicates whether to keep the instance always online." - read_messages: - type: boolean - description: "Indicates whether to mark messages as read." - read_status: - type: boolean - description: "Indicates whether to mark status messages as read." - sync_full_history: - type: boolean - description: "Indicates whether to request a full history messages sync on connect." - parameters: - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /settings/find/{instanceName}: - get: - tags: - - Settings - summary: Retrieve the Settings for a specific instance. - parameters: - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - - /chatwoot/set/{instanceName}: - post: - tags: - - Chatwoot - summary: Set up or modify the Chatwoot for an instance. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - enabled: - type: boolean - description: "Indicates whether to enable the Chatwoot integration." - account_id: - type: string - description: "The Chatwoot account ID." - token: - type: string - description: "The Chatwoot token." - url: - type: string - description: "The Chatwoot URL." - sign_msg: - type: boolean - description: "Indicates whether to sign messages." - reopen_conversation: - type: boolean - description: "Indicates whether to reopen conversations." - conversation_pending: - type: boolean - description: "Indicates whether to mark conversations as pending." - merge_brazil_contacts: - type: boolean - description: "Indicates whether to merge Brazil numbers in case of numbers with and without ninth digit." - import_contacts: - type: boolean - description: "Indicates whether to import contacts from phone to Chatwoot when connecting." - import_messages: - type: boolean - description: "Indicates whether to import messages from phone to Chatwoot when connecting." - days_limit_import_messages: - type: number - description: "Indicates number of days to limit messages imported to Chatwoot." - parameters: - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /chatwoot/find/{instanceName}: - get: - tags: - - Chatwoot - summary: Retrieve the Chatwoot for a specific instance. - parameters: - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - - /typebot/set/{instanceName}: - post: - tags: - - Typebot - summary: Set up or modify the Typebot for an instance. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - enabled: - type: boolean - description: "Indicates whether to enable the Typebot integration." - url: - type: string - description: "The Chatwoot URL." - typebot: - type: string - description: "The Typebot Name." - expire: - type: number - description: "The Typebot Expire." - keyword_finish: - type: string - description: "The Typebot Keyword Finish." - delay_message: - type: number - description: "The Typebot Delay Message." - unknown_message: - type: string - description: "The Typebot Unknown Message." - listening_from_me: - type: boolean - description: "Indicates whether to listening from me." - parameters: - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /typebot/start/{instanceName}: - post: - tags: - - Typebot - summary: Start the Typebot for an instance. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - url: - type: string - description: "The Typebot URL." - typebot: - type: string - description: "The Typebot Name." - remoteJid: - type: string - description: "The Typebot RemoteJid." - startSession: - type: boolean - description: "Indicates whether to start session." - variables: - type: array - description: "List of variables." - items: - type: object - properties: - name: - type: string - description: "The variable name." - value: - type: string - description: "The variable value." - parameters: - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /typebot/find/{instanceName}: - get: - tags: - - Typebot - summary: Retrieve the Typebot for a specific instance. - parameters: - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /typebot/changeStatus/{instanceName}: - post: - tags: - - Typebot - summary: Change the status of the Typebot for an instance. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - remoteJid: - type: string - description: "The Typebot RemoteJid." - status: - type: string - description: "The Typebot Status." - enum: ["opened", "paused", "closed"] - parameters: - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - - /proxy/set/{instanceName}: - post: - tags: - - Proxy - summary: Set up or modify the Proxy for an instance. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - enabled: - type: boolean - description: "Indicates whether to enable the Proxy integration." - proxy: - type: string - description: "The Proxy URI." - parameters: - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /proxy/find/{instanceName}: - get: - tags: - - Proxy - summary: Retrieve the Proxy for a specific instance. - parameters: - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - - /chamaai/set/{instanceName}: - post: - tags: - - Chama AI - summary: Set up or modify the Chama AI for an instance. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - enabled: - type: boolean - description: "Indicates whether to enable the Chamai AI integration." - url: - type: string - description: "The Chamai AI URL." - token: - type: string - description: "The Chamai AI Token." - waNumber: - type: string - description: "The Chamai AI WhatsApp Number." - answerByAudio: - type: boolean - description: "Indicates whether to answer by audio." - parameters: - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /chamaai/find/{instanceName}: - get: - tags: - - Chama AI - summary: Retrieve the Chama AI for a specific instance. - parameters: - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - - /chat/fetchBusinessProfile/{instanceName}: - post: - tags: - - Profile Settings - summary: Fetch the business profile of a specific contact. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - number: - type: string - description: "- required - The phone number of the contact." - parameters: - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /chat/fetchProfile/{instanceName}: - post: - tags: - - Profile Settings - summary: Fetch the profile of a specific contact. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - number: - type: string - description: "- required - The phone number of the contact." - parameters: - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /chat/updateProfileName/{instanceName}: - post: - tags: - - Profile Settings - summary: Update the name of a specific contact. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - name: - type: string - description: "- required - The new name of the contact." - parameters: - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /chat/updateProfileStatus/{instanceName}: - post: - tags: - - Profile Settings - summary: Update the status of a specific contact. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - status: - type: string - description: "- required - The new status of the contact." - parameters: - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /chat/updateProfilePicture/{instanceName}: - put: - tags: - - Profile Settings - summary: Update the profile picture of a specific contact. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - picture: - type: string - description: "- required - The new profile picture of the contact." - parameters: - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /chat/removeProfilePicture/{instanceName}: - delete: - tags: - - Profile Settings - summary: Remove the profile picture of a specific contact. - parameters: - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /chat/fetchPrivacySettings/{instanceName}: - get: - tags: - - Profile Settings - summary: Fetch the privacy settings of a specific contact. - parameters: - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} - /chat/updatePrivacySettings/{instanceName}: - put: - tags: - - Profile Settings - summary: Update the privacy settings of a specific contact. - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - privacySettings: - type: object - description: "- required - The new privacy settings of the contact." - properties: - readreceipts: - type: string - enum: ["all", "none"] - description: "- required - The new read receipts privacy setting of the contact." - profile: - type: string - enum: ["all", "contacts", "contact_blacklist", "none"] - description: "- required - The new profile privacy setting of the contact." - status: - type: string - enum: ["all", "contacts", "contact_blacklist", "none"] - description: "- required - The new status privacy setting of the contact." - online: - type: string - enum: ["all", "match_last_seen"] - description: "- required - The new online privacy setting of the contact." - last: - type: string - enum: ["all", "contacts", "contact_blacklist", "none"] - description: "- required - The new last seen privacy setting of the contact." - groupadd: - type: string - enum: ["all", "contacts", "contact_blacklist", "none"] - description: "- required - The new group add privacy setting of the contact." - parameters: - - name: instanceName - in: path - schema: - type: string - required: true - description: "- required" - example: "evolution" - responses: - "200": - description: Successful response - content: - application/json: {} diff --git a/src/exceptions/400.exception.ts b/src/exceptions/400.exception.ts index 2ea3a7a4..123696cb 100644 --- a/src/exceptions/400.exception.ts +++ b/src/exceptions/400.exception.ts @@ -1,4 +1,4 @@ -import { HttpStatus } from '../api/routes/index.router'; +import { HttpStatus } from '@api/routes/index.router'; export class BadRequestException { constructor(...objectError: any[]) { diff --git a/src/exceptions/401.exception.ts b/src/exceptions/401.exception.ts index f5383e0e..8ff9076c 100644 --- a/src/exceptions/401.exception.ts +++ b/src/exceptions/401.exception.ts @@ -1,4 +1,4 @@ -import { HttpStatus } from '../api/routes/index.router'; +import { HttpStatus } from '@api/routes/index.router'; export class UnauthorizedException { constructor(...objectError: any[]) { diff --git a/src/exceptions/403.exception.ts b/src/exceptions/403.exception.ts index 53d8f05c..f1f39998 100644 --- a/src/exceptions/403.exception.ts +++ b/src/exceptions/403.exception.ts @@ -1,4 +1,4 @@ -import { HttpStatus } from '../api/routes/index.router'; +import { HttpStatus } from '@api/routes/index.router'; export class ForbiddenException { constructor(...objectError: any[]) { diff --git a/src/exceptions/404.exception.ts b/src/exceptions/404.exception.ts index f2fd5c28..16f912e4 100644 --- a/src/exceptions/404.exception.ts +++ b/src/exceptions/404.exception.ts @@ -1,4 +1,4 @@ -import { HttpStatus } from '../api/routes/index.router'; +import { HttpStatus } from '@api/routes/index.router'; export class NotFoundException { constructor(...objectError: any[]) { diff --git a/src/exceptions/500.exception.ts b/src/exceptions/500.exception.ts index c5111f6d..316223e5 100644 --- a/src/exceptions/500.exception.ts +++ b/src/exceptions/500.exception.ts @@ -1,4 +1,4 @@ -import { HttpStatus } from '../api/routes/index.router'; +import { HttpStatus } from '@api/routes/index.router'; export class InternalServerErrorException { constructor(...objectError: any[]) { diff --git a/src/libs/db.connect.ts b/src/libs/db.connect.ts deleted file mode 100644 index b11610c7..00000000 --- a/src/libs/db.connect.ts +++ /dev/null @@ -1,25 +0,0 @@ -import mongoose from 'mongoose'; - -import { configService, Database } from '../config/env.config'; -import { Logger } from '../config/logger.config'; - -const logger = new Logger('MongoDB'); - -const db = configService.get('DATABASE'); -export const dbserver = (() => { - if (db.ENABLED) { - logger.verbose('connecting'); - const dbs = mongoose.createConnection(db.CONNECTION.URI, { - dbName: db.CONNECTION.DB_PREFIX_NAME + '-whatsapp-api', - }); - logger.verbose('connected in ' + db.CONNECTION.URI); - logger.info('ON - dbName: ' + dbs['$dbName']); - - process.on('beforeExit', () => { - logger.verbose('instance destroyed'); - dbserver.destroy(true, (error) => logger.error(error)); - }); - - return dbs; - } -})(); diff --git a/src/main.ts b/src/main.ts index 881996cc..15a582ac 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,31 +1,41 @@ -import 'express-async-errors'; +// Import this first from sentry instrument! +import '@utils/instrumentSentry'; +// Now import other modules +import { ProviderFiles } from '@api/provider/sessions'; +import { PrismaRepository } from '@api/repository/repository.service'; +import { HttpStatus, router } from '@api/routes/index.router'; +import { eventManager, waMonitor } from '@api/server.module'; +import { Auth, configService, Cors, HttpServer, ProviderSession, Webhook } from '@config/env.config'; +import { onUnexpectedError } from '@config/error.config'; +import { Logger } from '@config/logger.config'; +import { ROOT_DIR } from '@config/path.config'; +import * as Sentry from '@sentry/node'; +import { ServerUP } from '@utils/server-up'; import axios from 'axios'; import compression from 'compression'; import cors from 'cors'; import express, { json, NextFunction, Request, Response, urlencoded } from 'express'; import { join } from 'path'; -import { initAMQP, initGlobalQueues } from './api/integrations/rabbitmq/libs/amqp.server'; -import { initSQS } from './api/integrations/sqs/libs/sqs.server'; -import { initIO } from './api/integrations/websocket/libs/socket.server'; -import { HttpStatus, router } from './api/routes/index.router'; -import { waMonitor } from './api/server.module'; -import { Auth, configService, Cors, HttpServer, Rabbitmq, Sqs, Webhook } from './config/env.config'; -import { onUnexpectedError } from './config/error.config'; -import { Logger } from './config/logger.config'; -import { ROOT_DIR } from './config/path.config'; -import { swaggerRouter } from './docs/swagger.conf'; -import { ServerUP } from './utils/server-up'; - function initWA() { waMonitor.loadInstance(); } -function bootstrap() { +async function bootstrap() { const logger = new Logger('SERVER'); const app = express(); + let providerFiles: ProviderFiles = null; + if (configService.get('PROVIDER').ENABLED) { + providerFiles = new ProviderFiles(configService); + await providerFiles.onModuleInit(); + logger.info('Provider:Files - ON'); + } + + const prismaRepository = new PrismaRepository(configService); + await prismaRepository.onModuleInit(); + app.use( cors({ origin(requestOrigin, callback) { @@ -54,8 +64,6 @@ function bootstrap() { app.use('/', router); - if (!configService.get('SERVER').DISABLE_DOCS) app.use(swaggerRouter); - app.use( (err: Error, req: Request, res: Response, next: NextFunction) => { if (err) { @@ -128,16 +136,19 @@ function bootstrap() { server.listen(port, () => logger.log(httpServer.TYPE.toUpperCase() + ' - ON: ' + port)); initWA(); + eventManager.init(server); - initIO(server); + if (process.env.SENTRY_DSN) { + logger.info('Sentry - ON'); - if (configService.get('RABBITMQ')?.ENABLED) { - initAMQP().then(() => { - if (configService.get('RABBITMQ')?.GLOBAL_ENABLED) initGlobalQueues(); - }); + // Add this after all routes, + // but before any and other error-handling middlewares are defined + Sentry.setupExpressErrorHandler(app); } - if (configService.get('SQS')?.ENABLED) initSQS(); + server.listen(httpServer.PORT, () => logger.log(httpServer.TYPE.toUpperCase() + ' - ON: ' + httpServer.PORT)); + + initWA(); onUnexpectedError(); } diff --git a/src/utils/advancedOperatorsSearch.ts b/src/utils/advancedOperatorsSearch.ts new file mode 100644 index 00000000..dc0ec5ce --- /dev/null +++ b/src/utils/advancedOperatorsSearch.ts @@ -0,0 +1,45 @@ +function normalizeString(str: string): string { + return str + .normalize('NFD') + .replace(/[\u0300-\u036f]/g, '') + .toLowerCase(); +} + +export function advancedOperatorsSearch(data: string, query: string): boolean { + const filters = query.split(' ').reduce((acc: Record, filter) => { + const [operator, ...values] = filter.split(':'); + const value = values.join(':'); + + if (!acc[operator]) { + acc[operator] = []; + } + acc[operator].push(value); + return acc; + }, {}); + + const normalizedItem = normalizeString(data); + + return Object.entries(filters).every(([operator, values]) => { + return values.some((val) => { + const subValues = val.split(','); + return subValues.every((subVal) => { + const normalizedSubVal = normalizeString(subVal); + + switch (operator.toLowerCase()) { + case 'contains': + return normalizedItem.includes(normalizedSubVal); + case 'notcontains': + return !normalizedItem.includes(normalizedSubVal); + case 'startswith': + return normalizedItem.startsWith(normalizedSubVal); + case 'endswith': + return normalizedItem.endsWith(normalizedSubVal); + case 'exact': + return normalizedItem === normalizedSubVal; + default: + return false; + } + }); + }); + }); +} diff --git a/src/utils/createJid.ts b/src/utils/createJid.ts new file mode 100644 index 00000000..a680e821 --- /dev/null +++ b/src/utils/createJid.ts @@ -0,0 +1,71 @@ +// Check if the number is MX or AR +function formatMXOrARNumber(jid: string): string { + const countryCode = jid.substring(0, 2); + + if (Number(countryCode) === 52 || Number(countryCode) === 54) { + if (jid.length === 13) { + const number = countryCode + jid.substring(3); + return number; + } + + return jid; + } + return jid; +} + +// Check if the number is br +function formatBRNumber(jid: string) { + const regexp = new RegExp(/^(\d{2})(\d{2})\d{1}(\d{8})$/); + if (regexp.test(jid)) { + const match = regexp.exec(jid); + if (match && match[1] === '55') { + const joker = Number.parseInt(match[3][0]); + const ddd = Number.parseInt(match[2]); + if (joker < 7 || ddd < 31) { + return match[0]; + } + return match[1] + match[2] + match[3]; + } + return jid; + } else { + return jid; + } +} + +export function createJid(number: string): string { + number = number.replace(/:\d+/, ''); + + if (number.includes('@g.us') || number.includes('@s.whatsapp.net') || number.includes('@lid')) { + return number; + } + + if (number.includes('@broadcast')) { + return number; + } + + number = number + ?.replace(/\s/g, '') + .replace(/\+/g, '') + .replace(/\(/g, '') + .replace(/\)/g, '') + .split(':')[0] + .split('@')[0]; + + if (number.includes('-') && number.length >= 24) { + number = number.replace(/[^\d-]/g, ''); + return `${number}@g.us`; + } + + number = number.replace(/\D/g, ''); + + if (number.length >= 18) { + number = number.replace(/[^\d-]/g, ''); + return `${number}@g.us`; + } + + number = formatMXOrARNumber(number); + + number = formatBRNumber(number); + + return `${number}@s.whatsapp.net`; +} diff --git a/src/utils/findBotByTrigger.ts b/src/utils/findBotByTrigger.ts new file mode 100644 index 00000000..26860d0e --- /dev/null +++ b/src/utils/findBotByTrigger.ts @@ -0,0 +1,128 @@ +import { advancedOperatorsSearch } from './advancedOperatorsSearch'; + +export const findBotByTrigger = async (botRepository: any, content: string, instanceId: string) => { + // Check for triggerType 'all' + const findTriggerAll = await botRepository.findFirst({ + where: { + enabled: true, + triggerType: 'all', + instanceId: instanceId, + }, + }); + + if (findTriggerAll) return findTriggerAll; + + const findTriggerAdvanced = await botRepository.findMany({ + where: { + enabled: true, + triggerType: 'advanced', + instanceId: instanceId, + }, + }); + for (const advanced of findTriggerAdvanced) { + if (advancedOperatorsSearch(content, advanced.triggerValue)) { + return advanced; + } + } + + // Check for exact match + const findTriggerEquals = await botRepository.findFirst({ + where: { + enabled: true, + triggerType: 'keyword', + triggerOperator: 'equals', + triggerValue: content, + instanceId: instanceId, + }, + }); + + if (findTriggerEquals) return findTriggerEquals; + + // Check for regex match + const findRegex = await botRepository.findMany({ + where: { + enabled: true, + triggerType: 'keyword', + triggerOperator: 'regex', + instanceId: instanceId, + }, + }); + + let findTriggerRegex = null; + + for (const regex of findRegex) { + const regexValue = new RegExp(regex.triggerValue); + + if (regexValue.test(content)) { + findTriggerRegex = regex; + break; + } + } + + if (findTriggerRegex) return findTriggerRegex; + + // Check for startsWith match + const findStartsWith = await botRepository.findMany({ + where: { + enabled: true, + triggerType: 'keyword', + triggerOperator: 'startsWith', + instanceId: instanceId, + }, + }); + + let findTriggerStartsWith = null; + + for (const startsWith of findStartsWith) { + if (content.startsWith(startsWith.triggerValue)) { + findTriggerStartsWith = startsWith; + break; + } + } + + if (findTriggerStartsWith) return findTriggerStartsWith; + + // Check for endsWith match + const findEndsWith = await botRepository.findMany({ + where: { + enabled: true, + triggerType: 'keyword', + triggerOperator: 'endsWith', + instanceId: instanceId, + }, + }); + + let findTriggerEndsWith = null; + + for (const endsWith of findEndsWith) { + if (content.endsWith(endsWith.triggerValue)) { + findTriggerEndsWith = endsWith; + break; + } + } + + if (findTriggerEndsWith) return findTriggerEndsWith; + + // Check for contains match + const findContains = await botRepository.findMany({ + where: { + enabled: true, + triggerType: 'keyword', + triggerOperator: 'contains', + instanceId: instanceId, + }, + }); + + let findTriggerContains = null; + + for (const contains of findContains) { + if (content.includes(contains.triggerValue)) { + findTriggerContains = contains; + break; + } + } + + if (findTriggerContains) return findTriggerContains; + + return null; +}; diff --git a/src/utils/getConversationMessage.ts b/src/utils/getConversationMessage.ts new file mode 100644 index 00000000..b2522ab0 --- /dev/null +++ b/src/utils/getConversationMessage.ts @@ -0,0 +1,74 @@ +import { configService, S3 } from '@config/env.config'; + +const getTypeMessage = (msg: any) => { + let mediaId: string; + + if (configService.get('S3').ENABLE) mediaId = msg.message.mediaUrl; + else mediaId = msg.key.id; + + const types = { + conversation: msg?.message?.conversation, + extendedTextMessage: msg?.message?.extendedTextMessage?.text, + contactMessage: msg?.message?.contactMessage?.displayName, + locationMessage: msg?.message?.locationMessage?.degreesLatitude, + viewOnceMessageV2: + msg?.message?.viewOnceMessageV2?.message?.imageMessage?.url || + msg?.message?.viewOnceMessageV2?.message?.videoMessage?.url || + msg?.message?.viewOnceMessageV2?.message?.audioMessage?.url, + listResponseMessage: msg?.message?.listResponseMessage?.title, + responseRowId: msg?.message?.listResponseMessage?.singleSelectReply?.selectedRowId, + templateButtonReplyMessage: + msg?.message?.templateButtonReplyMessage?.selectedId || msg?.message?.buttonsResponseMessage?.selectedButtonId, + // Medias + audioMessage: msg?.message?.speechToText + ? msg?.message?.speechToText + : msg?.message?.audioMessage + ? `audioMessage|${mediaId}` + : undefined, + imageMessage: msg?.message?.imageMessage + ? `imageMessage|${mediaId}${msg?.message?.imageMessage?.caption ? `|${msg?.message?.imageMessage?.caption}` : ''}` + : undefined, + videoMessage: msg?.message?.videoMessage + ? `videoMessage|${mediaId}${msg?.message?.videoMessage?.caption ? `|${msg?.message?.videoMessage?.caption}` : ''}` + : undefined, + documentMessage: msg?.message?.documentMessage + ? `documentMessage|${mediaId}${ + msg?.message?.documentMessage?.caption ? `|${msg?.message?.documentMessage?.caption}` : '' + }` + : undefined, + documentWithCaptionMessage: msg?.message?.documentWithCaptionMessage?.message?.documentMessage + ? `documentWithCaptionMessage|${mediaId}${ + msg?.message?.documentWithCaptionMessage?.message?.documentMessage?.caption + ? `|${msg?.message?.documentWithCaptionMessage?.message?.documentMessage?.caption}` + : '' + }` + : undefined, + externalAdReplyBody: msg?.contextInfo?.externalAdReply?.body + ? `externalAdReplyBody|${msg.contextInfo.externalAdReply.body}` + : undefined, + }; + + const messageType = Object.keys(types).find((key) => types[key] !== undefined) || 'unknown'; + + return { ...types, messageType }; +}; + +const getMessageContent = (types: any) => { + const typeKey = Object.keys(types).find((key) => key !== 'externalAdReplyBody' && types[key] !== undefined); + + let result = typeKey ? types[typeKey] : undefined; + + if (types.externalAdReplyBody) { + result = result ? `${result}\n${types.externalAdReplyBody}` : types.externalAdReplyBody; + } + + return result; +}; + +export const getConversationMessage = (msg: any) => { + const types = getTypeMessage(msg); + + const messageContent = getMessageContent(types); + + return messageContent; +}; diff --git a/src/utils/i18n.ts b/src/utils/i18n.ts index 8e23181d..b26a5ef0 100644 --- a/src/utils/i18n.ts +++ b/src/utils/i18n.ts @@ -1,9 +1,8 @@ +import { ConfigService, Language } from '@config/env.config'; import fs from 'fs'; import i18next from 'i18next'; import path from 'path'; -import { ConfigService, Language } from '../config/env.config'; - const languages = ['en', 'pt-BR', 'es']; const translationsPath = path.join(__dirname, 'translations'); const configService: ConfigService = new ConfigService(); diff --git a/src/utils/instrumentSentry.ts b/src/utils/instrumentSentry.ts new file mode 100644 index 00000000..1a87086f --- /dev/null +++ b/src/utils/instrumentSentry.ts @@ -0,0 +1,12 @@ +import * as Sentry from '@sentry/node'; + +const dsn = process.env.SENTRY_DSN; + +if (dsn) { + Sentry.init({ + dsn: dsn, + environment: process.env.NODE_ENV || 'development', + tracesSampleRate: 1.0, + profilesSampleRate: 1.0, + }); +} diff --git a/src/utils/makeProxyAgent.ts b/src/utils/makeProxyAgent.ts index 60d5f20c..dcf560f6 100644 --- a/src/utils/makeProxyAgent.ts +++ b/src/utils/makeProxyAgent.ts @@ -1,8 +1,14 @@ import { HttpsProxyAgent } from 'https-proxy-agent'; -import { wa } from '../api/types/wa.types'; +type Proxy = { + host: string; + password?: string; + port: string; + protocol: string; + username?: string; +}; -export function makeProxyAgent(proxy: wa.Proxy | string) { +export function makeProxyAgent(proxy: Proxy | string) { if (typeof proxy === 'string') { return new HttpsProxyAgent(proxy); } diff --git a/src/utils/onWhatsappCache.ts b/src/utils/onWhatsappCache.ts new file mode 100644 index 00000000..a77ac396 --- /dev/null +++ b/src/utils/onWhatsappCache.ts @@ -0,0 +1,100 @@ +import { prismaRepository } from '@api/server.module'; +import { configService, Database } from '@config/env.config'; +import dayjs from 'dayjs'; + +function getAvailableNumbers(remoteJid: string) { + const numbersAvailable: string[] = []; + + if (remoteJid.startsWith('+')) { + remoteJid = remoteJid.slice(1); + } + + const [number, domain] = remoteJid.split('@'); + + // Brazilian numbers + if (remoteJid.startsWith('55')) { + const numberWithDigit = + number.slice(4, 5) === '9' && number.length === 13 ? number : `${number.slice(0, 4)}9${number.slice(4)}`; + const numberWithoutDigit = number.length === 12 ? number : number.slice(0, 4) + number.slice(5); + + numbersAvailable.push(numberWithDigit); + numbersAvailable.push(numberWithoutDigit); + } + + // Mexican/Argentina numbers + // Ref: https://faq.whatsapp.com/1294841057948784 + else if (number.startsWith('52') || number.startsWith('54')) { + let prefix = ''; + if (number.startsWith('52')) { + prefix = '1'; + } + if (number.startsWith('54')) { + prefix = '9'; + } + + const numberWithDigit = + number.slice(2, 3) === prefix && number.length === 13 + ? number + : `${number.slice(0, 2)}${prefix}${number.slice(2)}`; + const numberWithoutDigit = number.length === 12 ? number : number.slice(0, 2) + number.slice(3); + + numbersAvailable.push(numberWithDigit); + numbersAvailable.push(numberWithoutDigit); + } + + // Other countries + else { + numbersAvailable.push(remoteJid); + } + + return numbersAvailable.map((number) => `${number}@${domain}`); +} + +interface ISaveOnWhatsappCacheParams { + remoteJid: string; +} +export async function saveOnWhatsappCache(data: ISaveOnWhatsappCacheParams[]) { + if (configService.get('DATABASE').SAVE_DATA.IS_ON_WHATSAPP) { + const upsertsQuery = data.map((item) => { + const remoteJid = item.remoteJid.startsWith('+') ? item.remoteJid.slice(1) : item.remoteJid; + const numbersAvailable = getAvailableNumbers(remoteJid); + + return prismaRepository.isOnWhatsapp.upsert({ + create: { remoteJid: remoteJid, jidOptions: numbersAvailable.join(',') }, + update: { jidOptions: numbersAvailable.join(',') }, + where: { remoteJid: remoteJid }, + }); + }); + + await prismaRepository.$transaction(upsertsQuery); + } +} + +export async function getOnWhatsappCache(remoteJids: string[]) { + let results: { + remoteJid: string; + number: string; + jidOptions: string[]; + }[] = []; + + if (configService.get('DATABASE').SAVE_DATA.IS_ON_WHATSAPP) { + const remoteJidsWithoutPlus = remoteJids.map((remoteJid) => getAvailableNumbers(remoteJid)).flat(); + + const onWhatsappCache = await prismaRepository.isOnWhatsapp.findMany({ + where: { + OR: remoteJidsWithoutPlus.map((remoteJid) => ({ jidOptions: { contains: remoteJid } })), + updatedAt: { + gte: dayjs().subtract(configService.get('DATABASE').SAVE_DATA.IS_ON_WHATSAPP_DAYS, 'days').toDate(), + }, + }, + }); + + results = onWhatsappCache.map((item) => ({ + remoteJid: item.remoteJid, + number: item.remoteJid.split('@')[0], + jidOptions: item.jidOptions.split(','), + })); + } + + return results; +} diff --git a/src/utils/renderStatus.ts b/src/utils/renderStatus.ts new file mode 100644 index 00000000..e57b1224 --- /dev/null +++ b/src/utils/renderStatus.ts @@ -0,0 +1,10 @@ +import { wa } from '@api/types/wa.types'; + +export const status: Record = { + 0: 'ERROR', + 1: 'PENDING', + 2: 'SERVER_ACK', + 3: 'DELIVERY_ACK', + 4: 'READ', + 5: 'PLAYED', +}; diff --git a/src/utils/sendTelemetry.ts b/src/utils/sendTelemetry.ts new file mode 100644 index 00000000..037ca55d --- /dev/null +++ b/src/utils/sendTelemetry.ts @@ -0,0 +1,38 @@ +import axios from 'axios'; +import fs from 'fs'; + +const packageJson = JSON.parse(fs.readFileSync('./package.json', 'utf8')); + +export interface TelemetryData { + route: string; + apiVersion: string; + timestamp: Date; +} + +export const sendTelemetry = async (route: string): Promise => { + const enabled = process.env.TELEMETRY_ENABLED === undefined || process.env.TELEMETRY_ENABLED === 'true'; + + if (!enabled) { + return; + } + + if (route === '/') { + return; + } + + const telemetry: TelemetryData = { + route, + apiVersion: `${packageJson.version}`, + timestamp: new Date(), + }; + + const url = + process.env.TELEMETRY_URL && process.env.TELEMETRY_URL !== '' + ? process.env.TELEMETRY_URL + : 'https://log.evolution-api.com/telemetry'; + + axios + .post(url, telemetry) + .then(() => {}) + .catch(() => {}); +}; diff --git a/src/utils/server-up.ts b/src/utils/server-up.ts index e06caea7..326b3be4 100644 --- a/src/utils/server-up.ts +++ b/src/utils/server-up.ts @@ -1,10 +1,9 @@ +import { configService, SslConf } from '@config/env.config'; import { Express } from 'express'; import { readFileSync } from 'fs'; import * as http from 'http'; import * as https from 'https'; -import { configService, SslConf } from '../config/env.config'; - export class ServerUP { static #app: Express; diff --git a/src/utils/translations/en.json b/src/utils/translations/en.json index 1b10e7b8..43dfd8d2 100644 --- a/src/utils/translations/en.json +++ b/src/utils/translations/en.json @@ -2,7 +2,6 @@ "qrgeneratedsuccesfully": "QRCode successfully generated!", "scanqr": "Scan this QR code within the next 40 seconds.", "qrlimitreached": "QRCode generation limit reached, to generate a new QRCode, send the 'init' message again.", - "numbernotinwhatsapp": "The message was not sent as the contact is not a valid Whatsapp number.", "cw.inbox.connected": "🚀 Connection successfully established!", "cw.inbox.disconnect": "🚨 Disconnecting WhatsApp from inbox *{{inboxName}}*.", "cw.inbox.alreadyConnected": "🚨 {{inboxName}} instance is connected.", @@ -23,5 +22,6 @@ "cw.contactMessage.name": "Name", "cw.contactMessage.number": "Number", "cw.message.notsent": "🚨 The message could not be sent. Please check your connection. {{error}}", + "cw.message.numbernotinwhatsapp": "🚨 The message was not sent as the contact is not a valid Whatsapp number.", "cw.message.edited": "Edited Message" } \ No newline at end of file diff --git a/src/utils/translations/es.json b/src/utils/translations/es.json index 13f0d4b7..be830885 100644 --- a/src/utils/translations/es.json +++ b/src/utils/translations/es.json @@ -2,7 +2,6 @@ "qrgeneratedsuccesfully": "Código QR generado exitosamente!", "scanqr": "Escanea este código QR en los próximos 40 segundos.", "qrlimitreached": "🚨 Se alcanzó el límite de generación de QRCode. Para generar un nuevo QRCode, envíe el mensaje 'init' nuevamente.", - "numbernotinwhatsapp": "⚠️ El mensaje no fue enviado porque el contacto no es un número de Whatsapp válido..", "cw.inbox.connected": "🚀 ¡Conexión establecida exitosamente!", "cw.inbox.disconnect": "🚨 Instancia *{{inboxName}}* desconectado de Whatsapp.", "cw.inbox.alreadyConnected": "🚨 La instancia {{inboxName}} está conectada.", @@ -23,5 +22,6 @@ "cw.contactMessage.name": "Nombre", "cw.contactMessage.number": "Numero", "cw.message.notsent": "🚨 El mensaje no se pudo enviar. Comprueba tu conexión. {{error}}", + "cw.message.numbernotinwhatsapp": "🚨 El mensaje no fue enviado porque el contacto no es un número de Whatsapp válido.", "cw.message.edited": "Mensaje editado" } \ No newline at end of file diff --git a/src/utils/translations/pt-BR.json b/src/utils/translations/pt-BR.json index 85ed293b..31bf468a 100644 --- a/src/utils/translations/pt-BR.json +++ b/src/utils/translations/pt-BR.json @@ -2,7 +2,6 @@ "qrgeneratedsuccesfully": "QRCode gerado com sucesso!", "scanqr": "Escaneie o QRCode com o WhatsApp nos próximos 40 segundos.", "qrlimitreached": "Limite de geração de QRCode atingido! Para gerar um novo QRCode, envie o texto 'init' nesta conversa.", - "numbernotinwhatsapp": "A mensagem não foi enviada, pois o contato não é um número válido do WhatsApp.", "cw.inbox.connected": "🚀 Conectado com sucesso!", "cw.inbox.disconnect": "🚨 Instância *{{inboxName}}* desconectada do WhatsApp.", "cw.inbox.alreadyConnected": "🚨 Instância *{{inboxName}}* já está conectada.", @@ -23,5 +22,6 @@ "cw.contactMessage.name": "Nome", "cw.contactMessage.number": "Número", "cw.message.notsent": "🚨 Não foi possível enviar a mensagem. Verifique sua conexão. {{error}}", + "cw.message.numbernotinwhatsapp": "🚨 A mensagem não foi enviada, pois o contato não é um número válido do WhatsApp.", "cw.message.edited": "Mensagem editada" } \ No newline at end of file diff --git a/src/utils/use-multi-file-auth-state-db.ts b/src/utils/use-multi-file-auth-state-db.ts deleted file mode 100644 index 995ac92a..00000000 --- a/src/utils/use-multi-file-auth-state-db.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { - AuthenticationCreds, - AuthenticationState, - BufferJSON, - initAuthCreds, - proto, - SignalDataTypeMap, -} from '@whiskeysockets/baileys'; - -import { configService, Database } from '../config/env.config'; -import { Logger } from '../config/logger.config'; -import { dbserver } from '../libs/db.connect'; - -export async function useMultiFileAuthStateDb( - coll: string, -): Promise<{ state: AuthenticationState; saveCreds: () => Promise }> { - const logger = new Logger(useMultiFileAuthStateDb.name); - - const client = dbserver.getClient(); - - const collection = client - .db(configService.get('DATABASE').CONNECTION.DB_PREFIX_NAME + '-instances') - .collection(coll); - - const writeData = async (data: any, key: string): Promise => { - try { - await client.connect(); - let msgParsed = JSON.parse(JSON.stringify(data, BufferJSON.replacer)); - if (Array.isArray(msgParsed)) { - msgParsed = { - _id: key, - content_array: msgParsed, - }; - } - return await collection.replaceOne({ _id: key }, msgParsed, { - upsert: true, - }); - } catch (error) { - logger.error(error); - } - }; - - const readData = async (key: string): Promise => { - try { - await client.connect(); - let data = (await collection.findOne({ _id: key })) as any; - if (data?.content_array) { - data = data.content_array; - } - const creds = JSON.stringify(data); - return JSON.parse(creds, BufferJSON.reviver); - } catch (error) { - logger.error(error); - } - }; - - const removeData = async (key: string) => { - try { - await client.connect(); - return await collection.deleteOne({ _id: key }); - } catch (error) { - logger.error(error); - } - }; - - const creds: AuthenticationCreds = (await readData('creds')) || initAuthCreds(); - - return { - state: { - creds, - keys: { - get: async (type, ids: string[]) => { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - const data: { [_: string]: SignalDataTypeMap[type] } = {}; - await Promise.all( - ids.map(async (id) => { - let value = await readData(`${type}-${id}`); - if (type === 'app-state-sync-key' && value) { - value = proto.Message.AppStateSyncKeyData.fromObject(value); - } - - data[id] = value; - }), - ); - - return data; - }, - set: async (data: any) => { - const tasks: Promise[] = []; - for (const category in data) { - for (const id in data[category]) { - const value = data[category][id]; - const key = `${category}-${id}`; - tasks.push(value ? writeData(value, key) : removeData(key)); - } - } - - await Promise.all(tasks); - }, - }, - }, - saveCreds: async () => { - return await writeData(creds, 'creds'); - }, - }; -} diff --git a/src/utils/use-multi-file-auth-state-prisma.ts b/src/utils/use-multi-file-auth-state-prisma.ts new file mode 100644 index 00000000..e16dc8b0 --- /dev/null +++ b/src/utils/use-multi-file-auth-state-prisma.ts @@ -0,0 +1,182 @@ +import { prismaRepository } from '@api/server.module'; +import { CacheService } from '@api/services/cache.service'; +import { INSTANCE_DIR } from '@config/path.config'; +import { AuthenticationState, BufferJSON, initAuthCreds, WAProto as proto } from 'baileys'; +import fs from 'fs/promises'; +import path from 'path'; + +const fixFileName = (file: string): string | undefined => { + if (!file) { + return undefined; + } + const replacedSlash = file.replace(/\//g, '__'); + const replacedColon = replacedSlash.replace(/:/g, '-'); + return replacedColon; +}; + +export async function keyExists(sessionId: string): Promise { + try { + const key = await prismaRepository.session.findUnique({ where: { sessionId: sessionId } }); + return !!key; + } catch (error) { + return false; + } +} + +export async function saveKey(sessionId: string, keyJson: any): Promise { + const exists = await keyExists(sessionId); + try { + if (!exists) + return await prismaRepository.session.create({ + data: { + sessionId: sessionId, + creds: JSON.stringify(keyJson), + }, + }); + await prismaRepository.session.update({ + where: { sessionId: sessionId }, + data: { creds: JSON.stringify(keyJson) }, + }); + } catch (error) { + return null; + } +} + +export async function getAuthKey(sessionId: string): Promise { + try { + const register = await keyExists(sessionId); + if (!register) return null; + const auth = await prismaRepository.session.findUnique({ where: { sessionId: sessionId } }); + return JSON.parse(auth?.creds); + } catch (error) { + return null; + } +} + +async function deleteAuthKey(sessionId: string): Promise { + try { + const register = await keyExists(sessionId); + if (!register) return; + await prismaRepository.session.delete({ where: { sessionId: sessionId } }); + } catch (error) { + return; + } +} + +async function fileExists(file: string): Promise { + try { + const stat = await fs.stat(file); + if (stat.isFile()) return true; + } catch (error) { + return; + } +} + +export default async function useMultiFileAuthStatePrisma( + sessionId: string, + cache: CacheService, +): Promise<{ + state: AuthenticationState; + saveCreds: () => Promise; +}> { + const localFolder = path.join(INSTANCE_DIR, sessionId); + const localFile = (key: string) => path.join(localFolder, fixFileName(key) + '.json'); + await fs.mkdir(localFolder, { recursive: true }); + + async function writeData(data: any, key: string): Promise { + const dataString = JSON.stringify(data, BufferJSON.replacer); + + if (key != 'creds') { + if (process.env.CACHE_REDIS_ENABLED === 'true') { + return await cache.hSet(sessionId, key, data); + } else { + await fs.writeFile(localFile(key), dataString); + return; + } + } + await saveKey(sessionId, dataString); + return; + } + + async function readData(key: string): Promise { + try { + let rawData; + + if (key != 'creds') { + if (process.env.CACHE_REDIS_ENABLED === 'true') { + return await cache.hGet(sessionId, key); + } else { + if (!(await fileExists(localFile(key)))) return null; + rawData = await fs.readFile(localFile(key), { encoding: 'utf-8' }); + return JSON.parse(rawData, BufferJSON.reviver); + } + } else { + rawData = await getAuthKey(sessionId); + } + + const parsedData = JSON.parse(rawData, BufferJSON.reviver); + return parsedData; + } catch (error) { + return null; + } + } + + async function removeData(key: string): Promise { + try { + if (key != 'creds') { + if (process.env.CACHE_REDIS_ENABLED === 'true') { + return await cache.hDelete(sessionId, key); + } else { + await fs.unlink(localFile(key)); + } + } else { + await deleteAuthKey(sessionId); + } + } catch (error) { + return; + } + } + + let creds = await readData('creds'); + if (!creds) { + creds = initAuthCreds(); + await writeData(creds, 'creds'); + } + + return { + state: { + creds, + keys: { + get: async (type, ids) => { + const data = {}; + await Promise.all( + ids.map(async (id) => { + let value = await readData(`${type}-${id}`); + if (type === 'app-state-sync-key' && value) { + value = proto.Message.AppStateSyncKeyData.fromObject(value); + } + + data[id] = value; + }), + ); + return data; + }, + set: async (data) => { + const tasks = []; + for (const category in data) { + for (const id in data[category]) { + const value = data[category][id]; + const key = `${category}-${id}`; + + tasks.push(value ? writeData(value, key) : removeData(key)); + } + } + await Promise.all(tasks); + }, + }, + }, + saveCreds: () => { + return writeData(creds, 'creds'); + }, + }; +} diff --git a/src/utils/use-multi-file-auth-state-provider-files.ts b/src/utils/use-multi-file-auth-state-provider-files.ts new file mode 100644 index 00000000..4dfa2fb2 --- /dev/null +++ b/src/utils/use-multi-file-auth-state-provider-files.ts @@ -0,0 +1,131 @@ +/** + * ┌──────────────────────────────────────────────────────────────────────────────┐ + * │ @author jrCleber │ + * │ @filename use-multi-file-auth-state-provider-files.ts │ + * │ Developed by: Cleber Wilson │ + * │ Creation date: May 31, 2024 │ + * │ Contact: contato@codechat.dev │ + * ├──────────────────────────────────────────────────────────────────────────────┤ + * │ @copyright © Cleber Wilson 2023. All rights reserved. │ + * │ Licensed under the Apache License, Version 2.0 │ + * │ │ + * │ @license "https://github.com/code-chat-br/whatsapp-api/blob/main/LICENSE" │ + * │ │ + * │ You may not use this file except in compliance with the License. │ + * │ You may obtain a copy of the License at │ + * │ │ + * │ http://www.apache.org/licenses/LICENSE-2.0 │ + * │ │ + * │ Unless required by applicable law or agreed to in writing, software │ + * │ distributed under the License is distributed on an "AS IS" BASIS, │ + * │ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. │ + * │ │ + * │ See the License for the specific language governing permissions and │ + * │ limitations under the License. │ + * │ │ + * │ @type {AuthState} │ + * │ @function useMultiFileAuthStateRedisDb │ + * │ @returns {Promise} │ + * ├──────────────────────────────────────────────────────────────────────────────┤ + * │ @important │ + * │ For any future changes to the code in this file, it is recommended to │ + * │ contain, together with the modification, the information of the developer │ + * │ who changed it and the date of modification. │ + * └──────────────────────────────────────────────────────────────────────────────┘ + */ + +import { ProviderFiles } from '@api/provider/sessions'; +import { Logger } from '@config/logger.config'; +import { AuthenticationCreds, AuthenticationState, BufferJSON, initAuthCreds, proto, SignalDataTypeMap } from 'baileys'; +import { isNotEmpty } from 'class-validator'; + +export type AuthState = { state: AuthenticationState; saveCreds: () => Promise }; + +export class AuthStateProvider { + constructor(private readonly providerFiles: ProviderFiles) {} + + private readonly logger = new Logger('AuthStateProvider'); + + public async authStateProvider(instance: string): Promise { + const [, error] = await this.providerFiles.create(instance); + if (error) { + this.logger.error(['Failed to create folder on file server', error?.message, error?.stack]); + return; + } + + const writeData = async (data: any, key: string): Promise => { + const json = JSON.stringify(data, BufferJSON.replacer); + const [response, error] = await this.providerFiles.write(instance, key, { + data: json, + }); + if (error) { + // this.logger.error(['writeData', error?.message, error?.stack]); + return; + } + return response; + }; + + const readData = async (key: string): Promise => { + const [response, error] = await this.providerFiles.read(instance, key); + if (error) { + // this.logger.error(['readData', error?.message, error?.stack]); + return; + } + if (isNotEmpty(response?.data)) { + return JSON.parse(JSON.stringify(response.data), BufferJSON.reviver); + } + }; + + const removeData = async (key: string) => { + const [response, error] = await this.providerFiles.delete(instance, key); + if (error) { + // this.logger.error(['removeData', error?.message, error?.stack]); + return; + } + + return response; + }; + + const creds: AuthenticationCreds = (await readData('creds')) || initAuthCreds(); + + return { + state: { + creds, + keys: { + get: async (type, ids: string[]) => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + const data: { [_: string]: SignalDataTypeMap[type] } = {}; + await Promise.all( + ids.map(async (id) => { + let value = await readData(`${type}-${id}`); + if (type === 'app-state-sync-key' && value) { + value = proto.Message.AppStateSyncKeyData.fromObject(value); + } + + data[id] = value; + }), + ); + + return data; + }, + set: async (data: any) => { + const tasks: Promise[] = []; + for (const category in data) { + for (const id in data[category]) { + const value = data[category][id]; + const key = `${category}-${id}`; + tasks.push(value ? await writeData(value, key) : await removeData(key)); + } + } + + await Promise.all(tasks); + }, + }, + }, + saveCreds: async () => { + return await writeData(creds, 'creds'); + }, + }; + } +} diff --git a/src/utils/use-multi-file-auth-state-redis-db.ts b/src/utils/use-multi-file-auth-state-redis-db.ts index 66bb89ea..837f8092 100644 --- a/src/utils/use-multi-file-auth-state-redis-db.ts +++ b/src/utils/use-multi-file-auth-state-redis-db.ts @@ -1,13 +1,6 @@ -import { - AuthenticationCreds, - AuthenticationState, - initAuthCreds, - proto, - SignalDataTypeMap, -} from '@whiskeysockets/baileys'; - -import { CacheService } from '../api/services/cache.service'; -import { Logger } from '../config/logger.config'; +import { CacheService } from '@api/services/cache.service'; +import { Logger } from '@config/logger.config'; +import { AuthenticationCreds, AuthenticationState, initAuthCreds, proto, SignalDataTypeMap } from 'baileys'; export async function useMultiFileAuthStateRedisDb( instanceName: string, @@ -16,7 +9,7 @@ export async function useMultiFileAuthStateRedisDb( state: AuthenticationState; saveCreds: () => Promise; }> { - const logger = new Logger(useMultiFileAuthStateRedisDb.name); + const logger = new Logger('useMultiFileAuthStateRedisDb'); const writeData = async (data: any, key: string): Promise => { try { diff --git a/src/validate/chat.schema.ts b/src/validate/chat.schema.ts new file mode 100644 index 00000000..dba27995 --- /dev/null +++ b/src/validate/chat.schema.ts @@ -0,0 +1,317 @@ +import { JSONSchema7, JSONSchema7Definition } from 'json-schema'; +import { v4 } from 'uuid'; + +const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => { + const properties = {}; + propertyNames.forEach( + (property) => + (properties[property] = { + minLength: 1, + description: `The "${property}" cannot be empty`, + }), + ); + return { + if: { + propertyNames: { + enum: [...propertyNames], + }, + }, + then: { properties }, + }; +}; + +const numberDefinition: JSONSchema7Definition = { + type: 'string', + description: 'Invalid format', +}; + +export const whatsappNumberSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + numbers: { + type: 'array', + minItems: 1, + uniqueItems: true, + items: { + type: 'string', + description: '"numbers" must be an array of numeric strings', + }, + }, + }, +}; + +export const readMessageSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + readMessages: { + type: 'array', + minItems: 1, + uniqueItems: true, + items: { + properties: { + id: { type: 'string' }, + fromMe: { type: 'boolean', enum: [true, false] }, + remoteJid: { type: 'string' }, + }, + required: ['id', 'fromMe', 'remoteJid'], + ...isNotEmpty('id', 'remoteJid'), + }, + }, + }, + required: ['readMessages'], +}; + +export const archiveChatSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + chat: { type: 'string' }, + lastMessage: { + type: 'object', + properties: { + key: { + type: 'object', + properties: { + id: { type: 'string' }, + remoteJid: { type: 'string' }, + fromMe: { type: 'boolean', enum: [true, false] }, + }, + required: ['id', 'fromMe', 'remoteJid'], + ...isNotEmpty('id', 'remoteJid'), + }, + messageTimestamp: { type: 'integer', minLength: 1 }, + }, + required: ['key'], + ...isNotEmpty('messageTimestamp'), + }, + archive: { type: 'boolean', enum: [true, false] }, + }, + required: ['archive'], +}; + +export const markChatUnreadSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + chat: { type: 'string' }, + lastMessage: { + type: 'object', + properties: { + key: { + type: 'object', + properties: { + id: { type: 'string' }, + remoteJid: { type: 'string' }, + fromMe: { type: 'boolean', enum: [true, false] }, + }, + required: ['id', 'fromMe', 'remoteJid'], + ...isNotEmpty('id', 'remoteJid'), + }, + messageTimestamp: { type: 'integer', minLength: 1 }, + }, + required: ['key'], + ...isNotEmpty('messageTimestamp'), + }, + }, + required: ['lastMessage'], +}; + +export const deleteMessageSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + id: { type: 'string' }, + fromMe: { type: 'boolean', enum: [true, false] }, + remoteJid: { type: 'string' }, + participant: { type: 'string' }, + }, + required: ['id', 'fromMe', 'remoteJid'], + ...isNotEmpty('id', 'remoteJid', 'participant'), +}; + +export const profilePictureSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + number: { type: 'string' }, + picture: { type: 'string' }, + }, +}; + +export const updateMessageSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + number: { type: 'string' }, + text: { type: 'string' }, + key: { + type: 'object', + properties: { + id: { type: 'string' }, + remoteJid: { type: 'string' }, + fromMe: { type: 'boolean', enum: [true, false] }, + }, + required: ['id', 'fromMe', 'remoteJid'], + ...isNotEmpty('id', 'remoteJid'), + }, + }, + ...isNotEmpty('number', 'text', 'key'), +}; + +export const presenceSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + number: { ...numberDefinition }, + delay: { type: 'number' }, + presence: { + type: 'string', + enum: ['unavailable', 'available', 'composing', 'recording', 'paused'], + }, + }, + required: ['number', 'presence', 'delay'], +}; + +export const blockUserSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + number: { type: 'string' }, + status: { type: 'string', enum: ['block', 'unblock'] }, + }, + required: ['number', 'status'], + ...isNotEmpty('number', 'status'), +}; + +export const contactValidateSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + where: { + type: 'object', + properties: { + _id: { type: 'string', minLength: 1 }, + pushName: { type: 'string', minLength: 1 }, + id: { type: 'string', minLength: 1 }, + }, + ...isNotEmpty('_id', 'id', 'pushName'), + }, + }, +}; + +export const messageValidateSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + where: { + type: 'object', + properties: { + _id: { type: 'string', minLength: 1 }, + key: { + type: 'object', + if: { + propertyNames: { + enum: ['fromMe', 'remoteJid', 'id'], + }, + }, + then: { + properties: { + remoteJid: { + type: 'string', + minLength: 1, + description: 'The property cannot be empty', + }, + id: { + type: 'string', + minLength: 1, + description: 'The property cannot be empty', + }, + fromMe: { type: 'boolean', enum: [true, false] }, + }, + }, + }, + message: { type: 'object' }, + }, + ...isNotEmpty('_id'), + }, + limit: { type: 'integer' }, + }, +}; + +export const messageUpSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + where: { + type: 'object', + properties: { + _id: { type: 'string' }, + remoteJid: { type: 'string' }, + id: { type: 'string' }, + fromMe: { type: 'boolean', enum: [true, false] }, + participant: { type: 'string' }, + status: { + type: 'string', + enum: ['ERROR', 'PENDING', 'SERVER_ACK', 'DELIVERY_ACK', 'READ', 'PLAYED'], + }, + }, + ...isNotEmpty('_id', 'remoteJid', 'id', 'status'), + }, + limit: { type: 'integer' }, + }, +}; + +export const privacySettingsSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + readreceipts: { type: 'string', enum: ['all', 'none'] }, + profile: { + type: 'string', + enum: ['all', 'contacts', 'contact_blacklist', 'none'], + }, + status: { + type: 'string', + enum: ['all', 'contacts', 'contact_blacklist', 'none'], + }, + online: { type: 'string', enum: ['all', 'match_last_seen'] }, + last: { type: 'string', enum: ['all', 'contacts', 'contact_blacklist', 'none'] }, + groupadd: { + type: 'string', + enum: ['all', 'contacts', 'contact_blacklist', 'none'], + }, + }, + required: ['readreceipts', 'profile', 'status', 'online', 'last', 'groupadd'], + ...isNotEmpty('readreceipts', 'profile', 'status', 'online', 'last', 'groupadd'), +}; + +export const profileNameSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + name: { type: 'string' }, + }, + ...isNotEmpty('name'), +}; + +export const profileStatusSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + status: { type: 'string' }, + }, + ...isNotEmpty('status'), +}; + +export const profileSchema: JSONSchema7 = { + type: 'object', + properties: { + wuid: { type: 'string' }, + name: { type: 'string' }, + picture: { type: 'string' }, + status: { type: 'string' }, + isBusiness: { type: 'boolean' }, + }, +}; diff --git a/src/validate/group.schema.ts b/src/validate/group.schema.ts new file mode 100644 index 00000000..8da188d8 --- /dev/null +++ b/src/validate/group.schema.ts @@ -0,0 +1,193 @@ +import { JSONSchema7 } from 'json-schema'; +import { v4 } from 'uuid'; + +const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => { + const properties = {}; + propertyNames.forEach( + (property) => + (properties[property] = { + minLength: 1, + description: `The "${property}" cannot be empty`, + }), + ); + return { + if: { + propertyNames: { + enum: [...propertyNames], + }, + }, + then: { properties }, + }; +}; + +export const createGroupSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + subject: { type: 'string' }, + description: { type: 'string' }, + profilePicture: { type: 'string' }, + promoteParticipants: { type: 'boolean', enum: [true, false] }, + participants: { + type: 'array', + minItems: 1, + uniqueItems: true, + items: { + type: 'string', + minLength: 10, + pattern: '\\d+', + description: '"participants" must be an array of numeric strings', + }, + }, + }, + required: ['subject', 'participants'], + ...isNotEmpty('subject', 'description', 'profilePicture'), +}; + +export const groupJidSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + groupJid: { type: 'string', pattern: '^[\\d-]+@g.us$' }, + }, + required: ['groupJid'], + ...isNotEmpty('groupJid'), +}; + +export const getParticipantsSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + getParticipants: { type: 'string', enum: ['true', 'false'] }, + }, + required: ['getParticipants'], + ...isNotEmpty('getParticipants'), +}; + +export const groupSendInviteSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + groupJid: { type: 'string' }, + description: { type: 'string' }, + numbers: { + type: 'array', + minItems: 1, + uniqueItems: true, + items: { + type: 'string', + minLength: 10, + pattern: '\\d+', + description: '"numbers" must be an array of numeric strings', + }, + }, + }, + required: ['groupJid', 'description', 'numbers'], + ...isNotEmpty('groupJid', 'description', 'numbers'), +}; + +export const groupInviteSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + inviteCode: { type: 'string', pattern: '^[a-zA-Z0-9]{22}$' }, + }, + required: ['inviteCode'], + ...isNotEmpty('inviteCode'), +}; + +export const AcceptGroupInviteSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + inviteCode: { type: 'string', pattern: '^[a-zA-Z0-9]{22}$' }, + }, + required: ['inviteCode'], + ...isNotEmpty('inviteCode'), +}; + +export const updateParticipantsSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + groupJid: { type: 'string' }, + action: { + type: 'string', + enum: ['add', 'remove', 'promote', 'demote'], + }, + participants: { + type: 'array', + minItems: 1, + uniqueItems: true, + items: { + type: 'string', + minLength: 10, + pattern: '\\d+', + description: '"participants" must be an array of numeric strings', + }, + }, + }, + required: ['groupJid', 'action', 'participants'], + ...isNotEmpty('groupJid', 'action'), +}; + +export const updateSettingsSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + groupJid: { type: 'string' }, + action: { + type: 'string', + enum: ['announcement', 'not_announcement', 'locked', 'unlocked'], + }, + }, + required: ['groupJid', 'action'], + ...isNotEmpty('groupJid', 'action'), +}; + +export const toggleEphemeralSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + groupJid: { type: 'string' }, + expiration: { + type: 'number', + enum: [0, 86400, 604800, 7776000], + }, + }, + required: ['groupJid', 'expiration'], + ...isNotEmpty('groupJid', 'expiration'), +}; + +export const updateGroupPictureSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + groupJid: { type: 'string' }, + image: { type: 'string' }, + }, + required: ['groupJid', 'image'], + ...isNotEmpty('groupJid', 'image'), +}; + +export const updateGroupSubjectSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + groupJid: { type: 'string' }, + subject: { type: 'string' }, + }, + required: ['groupJid', 'subject'], + ...isNotEmpty('groupJid', 'subject'), +}; + +export const updateGroupDescriptionSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + groupJid: { type: 'string' }, + description: { type: 'string' }, + }, + required: ['groupJid', 'description'], + ...isNotEmpty('groupJid', 'description'), +}; diff --git a/src/validate/instance.schema.ts b/src/validate/instance.schema.ts new file mode 100644 index 00000000..06c34df9 --- /dev/null +++ b/src/validate/instance.schema.ts @@ -0,0 +1,189 @@ +import { Integration } from '@api/types/wa.types'; +import { JSONSchema7 } from 'json-schema'; +import { v4 } from 'uuid'; + +const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => { + const properties = {}; + propertyNames.forEach( + (property) => + (properties[property] = { + minLength: 1, + description: `The "${property}" cannot be empty`, + }), + ); + return { + if: { + propertyNames: { + enum: [...propertyNames], + }, + }, + then: { properties }, + }; +}; + +export const instanceSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + // Instance + instanceName: { type: 'string' }, + token: { type: 'string' }, + number: { type: 'string', pattern: '^\\d+[\\.@\\w-]+' }, + businessId: { type: 'string' }, + qrcode: { type: 'boolean' }, + Integration: { + type: 'string', + enum: Object.values(Integration), + }, + // Settings + rejectCall: { type: 'boolean' }, + msgCall: { type: 'string' }, + groupsIgnore: { type: 'boolean' }, + alwaysOnline: { type: 'boolean' }, + readMessages: { type: 'boolean' }, + readStatus: { type: 'boolean' }, + syncFullHistory: { type: 'boolean' }, + wavoipToken: { type: 'string' }, + // Proxy + proxyHost: { type: 'string' }, + proxyPort: { type: 'string' }, + proxyProtocol: { type: 'string' }, + proxyUsername: { type: 'string' }, + proxyPassword: { type: 'string' }, + // Webhook + webhookUrl: { type: 'string' }, + webhookByEvents: { type: 'boolean' }, + webhookBase64: { type: 'boolean' }, + webhookEvents: { + type: 'array', + minItems: 0, + items: { + type: 'string', + enum: [ + 'APPLICATION_STARTUP', + 'QRCODE_UPDATED', + 'MESSAGES_SET', + 'MESSAGES_UPSERT', + 'MESSAGES_EDITED', + 'MESSAGES_UPDATE', + 'MESSAGES_DELETE', + 'SEND_MESSAGE', + 'CONTACTS_SET', + 'CONTACTS_UPSERT', + 'CONTACTS_UPDATE', + 'PRESENCE_UPDATE', + 'CHATS_SET', + 'CHATS_UPSERT', + 'CHATS_UPDATE', + 'CHATS_DELETE', + 'GROUPS_UPSERT', + 'GROUP_UPDATE', + 'GROUP_PARTICIPANTS_UPDATE', + 'CONNECTION_UPDATE', + 'LABELS_EDIT', + 'LABELS_ASSOCIATION', + 'CALL', + 'TYPEBOT_START', + 'TYPEBOT_CHANGE_STATUS', + ], + }, + }, + // RabbitMQ + rabbitmqEnabled: { type: 'boolean' }, + rabbitmqEvents: { + type: 'array', + minItems: 0, + items: { + type: 'string', + enum: [ + 'APPLICATION_STARTUP', + 'QRCODE_UPDATED', + 'MESSAGES_SET', + 'MESSAGES_UPSERT', + 'MESSAGES_EDITED', + 'MESSAGES_UPDATE', + 'MESSAGES_DELETE', + 'SEND_MESSAGE', + 'CONTACTS_SET', + 'CONTACTS_UPSERT', + 'CONTACTS_UPDATE', + 'PRESENCE_UPDATE', + 'CHATS_SET', + 'CHATS_UPSERT', + 'CHATS_UPDATE', + 'CHATS_DELETE', + 'GROUPS_UPSERT', + 'GROUP_UPDATE', + 'GROUP_PARTICIPANTS_UPDATE', + 'CONNECTION_UPDATE', + 'LABELS_EDIT', + 'LABELS_ASSOCIATION', + 'CALL', + 'TYPEBOT_START', + 'TYPEBOT_CHANGE_STATUS', + ], + }, + }, + // SQS + sqsEnabled: { type: 'boolean' }, + sqsEvents: { + type: 'array', + minItems: 0, + items: { + type: 'string', + enum: [ + 'APPLICATION_STARTUP', + 'QRCODE_UPDATED', + 'MESSAGES_SET', + 'MESSAGES_UPSERT', + 'MESSAGES_EDITED', + 'MESSAGES_UPDATE', + 'MESSAGES_DELETE', + 'SEND_MESSAGE', + 'CONTACTS_SET', + 'CONTACTS_UPSERT', + 'CONTACTS_UPDATE', + 'PRESENCE_UPDATE', + 'CHATS_SET', + 'CHATS_UPSERT', + 'CHATS_UPDATE', + 'CHATS_DELETE', + 'GROUPS_UPSERT', + 'GROUP_UPDATE', + 'GROUP_PARTICIPANTS_UPDATE', + 'CONNECTION_UPDATE', + 'LABELS_EDIT', + 'LABELS_ASSOCIATION', + 'CALL', + 'TYPEBOT_START', + 'TYPEBOT_CHANGE_STATUS', + ], + }, + }, + // Chatwoot + chatwootAccountId: { type: 'string' }, + chatwootToken: { type: 'string' }, + chatwootUrl: { type: 'string' }, + chatwootSignMsg: { type: 'boolean' }, + chatwootReopenConversation: { type: 'boolean' }, + chatwootConversationPending: { type: 'boolean' }, + chatwootImportContacts: { type: 'boolean' }, + chatwootNameInbox: { type: 'string' }, + chatwootMergeBrazilContacts: { type: 'boolean' }, + chatwootImportMessages: { type: 'boolean' }, + chatwootDaysLimitImportMessages: { type: 'number' }, + }, + ...isNotEmpty('instanceName'), +}; + +export const presenceOnlySchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + presence: { + type: 'string', + enum: ['unavailable', 'available', 'composing', 'recording', 'paused'], + }, + }, + required: ['presence'], +}; diff --git a/src/validate/label.schema.ts b/src/validate/label.schema.ts new file mode 100644 index 00000000..eb5dc5a5 --- /dev/null +++ b/src/validate/label.schema.ts @@ -0,0 +1,38 @@ +import { JSONSchema7, JSONSchema7Definition } from 'json-schema'; +import { v4 } from 'uuid'; + +const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => { + const properties = {}; + propertyNames.forEach( + (property) => + (properties[property] = { + minLength: 1, + description: `The "${property}" cannot be empty`, + }), + ); + return { + if: { + propertyNames: { + enum: [...propertyNames], + }, + }, + then: { properties }, + }; +}; + +const numberDefinition: JSONSchema7Definition = { + type: 'string', + description: 'Invalid format', +}; + +export const handleLabelSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + number: { ...numberDefinition }, + labelId: { type: 'string' }, + action: { type: 'string', enum: ['add', 'remove'] }, + }, + required: ['number', 'labelId', 'action'], + ...isNotEmpty('number', 'labelId', 'action'), +}; diff --git a/src/validate/message.schema.ts b/src/validate/message.schema.ts new file mode 100644 index 00000000..d514c619 --- /dev/null +++ b/src/validate/message.schema.ts @@ -0,0 +1,449 @@ +import { JSONSchema7, JSONSchema7Definition } from 'json-schema'; +import { v4 } from 'uuid'; + +const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => { + const properties = {}; + propertyNames.forEach( + (property) => + (properties[property] = { + minLength: 1, + description: `The "${property}" cannot be empty`, + }), + ); + return { + if: { + propertyNames: { + enum: [...propertyNames], + }, + }, + then: { properties }, + }; +}; + +const numberDefinition: JSONSchema7Definition = { + type: 'string', + description: 'Invalid format', +}; + +export const templateMessageSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + number: { ...numberDefinition }, + name: { type: 'string' }, + language: { type: 'string' }, + components: { type: 'array' }, + webhookUrl: { type: 'string' }, + }, + required: ['name', 'language'], +}; + +const quotedOptionsSchema: JSONSchema7 = { + properties: { + key: { + type: 'object', + properties: { + id: { type: 'string' }, + remoteJid: { type: 'string' }, + fromMe: { type: 'boolean', enum: [true, false] }, + }, + required: ['id'], + ...isNotEmpty('id'), + }, + message: { type: 'object' }, + }, +}; + +export const offerCallSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + number: { ...numberDefinition }, + isVideo: { type: 'boolean', enum: [true, false] }, + callDuration: { type: 'integer', minimum: 1, maximum: 15 }, + }, + required: ['number', 'callDuration'], +}; + +export const textMessageSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + number: { ...numberDefinition }, + text: { type: 'string' }, + linkPreview: { type: 'boolean' }, + delay: { + type: 'integer', + description: 'Enter a value in milliseconds', + }, + quoted: { ...quotedOptionsSchema }, + everyOne: { type: 'boolean', enum: [true, false] }, + mentioned: { + type: 'array', + minItems: 1, + uniqueItems: true, + items: { + type: 'string', + pattern: '^\\d+', + description: '"mentioned" must be an array of numeric strings', + }, + }, + }, + required: ['number', 'text'], +}; + +export const mediaMessageSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + number: { ...numberDefinition }, + mediatype: { type: 'string', enum: ['image', 'document', 'video', 'audio'] }, + mimetype: { type: 'string' }, + media: { type: 'string' }, + fileName: { type: 'string' }, + caption: { type: 'string' }, + delay: { + type: 'integer', + description: 'Enter a value in milliseconds', + }, + quoted: { ...quotedOptionsSchema }, + everyOne: { type: 'boolean', enum: [true, false] }, + mentioned: { + type: 'array', + minItems: 1, + uniqueItems: true, + items: { + type: 'string', + pattern: '^\\d+', + description: '"mentioned" must be an array of numeric strings', + }, + }, + }, + required: ['number', 'mediatype'], +}; + +export const ptvMessageSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + number: { ...numberDefinition }, + video: { type: 'string' }, + delay: { + type: 'integer', + description: 'Enter a value in milliseconds', + }, + quoted: { ...quotedOptionsSchema }, + everyOne: { type: 'boolean', enum: [true, false] }, + mentioned: { + type: 'array', + minItems: 1, + uniqueItems: true, + items: { + type: 'string', + pattern: '^\\d+', + description: '"mentioned" must be an array of numeric strings', + }, + }, + }, + required: ['number'], +}; + +export const audioMessageSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + number: { ...numberDefinition }, + audio: { type: 'string' }, + delay: { + type: 'integer', + description: 'Enter a value in milliseconds', + }, + quoted: { ...quotedOptionsSchema }, + everyOne: { type: 'boolean', enum: [true, false] }, + mentioned: { + type: 'array', + minItems: 1, + uniqueItems: true, + items: { + type: 'string', + pattern: '^\\d+', + description: '"mentioned" must be an array of numeric strings', + }, + }, + }, + required: ['number'], +}; + +export const statusMessageSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + type: { type: 'string', enum: ['text', 'image', 'audio', 'video'] }, + content: { type: 'string' }, + caption: { type: 'string' }, + backgroundColor: { type: 'string' }, + font: { type: 'integer', minimum: 0, maximum: 5 }, + statusJidList: { + type: 'array', + minItems: 1, + uniqueItems: true, + items: { + type: 'string', + pattern: '^\\d+', + description: '"statusJidList" must be an array of numeric strings', + }, + }, + allContacts: { type: 'boolean', enum: [true, false] }, + }, + required: ['type'], +}; + +export const stickerMessageSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + number: { ...numberDefinition }, + sticker: { type: 'string' }, + delay: { + type: 'integer', + description: 'Enter a value in milliseconds', + }, + quoted: { ...quotedOptionsSchema }, + everyOne: { type: 'boolean', enum: [true, false] }, + mentioned: { + type: 'array', + minItems: 1, + uniqueItems: true, + items: { + type: 'string', + pattern: '^\\d+', + description: '"mentioned" must be an array of numeric strings', + }, + }, + }, + required: ['number'], +}; + +export const locationMessageSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + number: { ...numberDefinition }, + latitude: { type: 'number' }, + longitude: { type: 'number' }, + name: { type: 'string' }, + address: { type: 'string' }, + delay: { + type: 'integer', + description: 'Enter a value in milliseconds', + }, + quoted: { ...quotedOptionsSchema }, + everyOne: { type: 'boolean', enum: [true, false] }, + mentioned: { + type: 'array', + minItems: 1, + uniqueItems: true, + items: { + type: 'string', + pattern: '^\\d+', + description: '"mentioned" must be an array of numeric strings', + }, + }, + }, + required: ['number', 'latitude', 'longitude', 'name', 'address'], +}; + +export const contactMessageSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + number: { ...numberDefinition }, + contact: { + type: 'array', + items: { + type: 'object', + properties: { + fullName: { type: 'string' }, + wuid: { + type: 'string', + minLength: 10, + pattern: '\\d+', + description: '"wuid" must be a numeric string', + }, + phoneNumber: { type: 'string', minLength: 10 }, + organization: { type: 'string' }, + email: { type: 'string' }, + url: { type: 'string' }, + }, + required: ['fullName', 'phoneNumber'], + ...isNotEmpty('fullName'), + }, + minItems: 1, + uniqueItems: true, + }, + }, + required: ['number', 'contact'], +}; + +export const reactionMessageSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + key: { + type: 'object', + properties: { + id: { type: 'string' }, + remoteJid: { type: 'string' }, + fromMe: { type: 'boolean', enum: [true, false] }, + }, + required: ['id', 'remoteJid', 'fromMe'], + ...isNotEmpty('id', 'remoteJid'), + }, + reaction: { type: 'string' }, + }, + required: ['key', 'reaction'], +}; + +export const pollMessageSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + number: { ...numberDefinition }, + name: { type: 'string' }, + selectableCount: { type: 'integer', minimum: 0, maximum: 10 }, + values: { + type: 'array', + minItems: 2, + maxItems: 10, + uniqueItems: true, + items: { + type: 'string', + }, + }, + delay: { + type: 'integer', + description: 'Enter a value in milliseconds', + }, + quoted: { ...quotedOptionsSchema }, + everyOne: { type: 'boolean', enum: [true, false] }, + mentioned: { + type: 'array', + minItems: 1, + uniqueItems: true, + items: { + type: 'string', + pattern: '^\\d+', + description: '"mentioned" must be an array of numeric strings', + }, + }, + }, + required: ['number', 'name', 'selectableCount', 'values'], +}; + +export const listMessageSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + number: { ...numberDefinition }, + title: { type: 'string' }, + description: { type: 'string' }, + footerText: { type: 'string' }, + buttonText: { type: 'string' }, + sections: { + type: 'array', + minItems: 1, + uniqueItems: true, + items: { + type: 'object', + properties: { + title: { type: 'string' }, + rows: { + type: 'array', + minItems: 1, + uniqueItems: true, + items: { + type: 'object', + properties: { + title: { type: 'string' }, + description: { type: 'string' }, + rowId: { type: 'string' }, + }, + required: ['title', 'rowId'], + ...isNotEmpty('title', 'description', 'rowId'), + }, + }, + }, + required: ['title', 'rows'], + ...isNotEmpty('title'), + }, + }, + delay: { + type: 'integer', + description: 'Enter a value in milliseconds', + }, + quoted: { ...quotedOptionsSchema }, + everyOne: { type: 'boolean', enum: [true, false] }, + mentioned: { + type: 'array', + minItems: 1, + uniqueItems: true, + items: { + type: 'string', + pattern: '^\\d+', + description: '"mentioned" must be an array of numeric strings', + }, + }, + }, + required: ['number', 'title', 'footerText', 'buttonText', 'sections'], +}; + +export const buttonsMessageSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + number: { ...numberDefinition }, + thumbnailUrl: { type: 'string' }, + title: { type: 'string' }, + description: { type: 'string' }, + footer: { type: 'string' }, + buttons: { + type: 'array', + items: { + type: 'object', + properties: { + type: { + type: 'string', + enum: ['reply', 'copy', 'url', 'call', 'pix'], + }, + displayText: { type: 'string' }, + id: { type: 'string' }, + url: { type: 'string' }, + phoneNumber: { type: 'string' }, + currency: { type: 'string' }, + name: { type: 'string' }, + keyType: { type: 'string', enum: ['phone', 'email', 'cpf', 'cnpj', 'random'] }, + key: { type: 'string' }, + }, + required: ['type'], + ...isNotEmpty('id', 'url', 'phoneNumber'), + }, + }, + delay: { + type: 'integer', + description: 'Enter a value in milliseconds', + }, + quoted: { ...quotedOptionsSchema }, + everyOne: { type: 'boolean', enum: [true, false] }, + mentioned: { + type: 'array', + minItems: 1, + uniqueItems: true, + items: { + type: 'string', + pattern: '^\\d+', + description: '"mentioned" must be an array of numeric strings', + }, + }, + }, + required: ['number'], +}; diff --git a/src/api/integrations/chamaai/validate/chamaai.schema.ts b/src/validate/proxy.schema.ts similarity index 62% rename from src/api/integrations/chamaai/validate/chamaai.schema.ts rename to src/validate/proxy.schema.ts index 0b80104f..564b42d5 100644 --- a/src/api/integrations/chamaai/validate/chamaai.schema.ts +++ b/src/validate/proxy.schema.ts @@ -20,16 +20,17 @@ const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => { }; }; -export const chamaaiSchema: JSONSchema7 = { +export const proxySchema: JSONSchema7 = { $id: v4(), type: 'object', properties: { enabled: { type: 'boolean', enum: [true, false] }, - url: { type: 'string' }, - token: { type: 'string' }, - waNumber: { type: 'string' }, - answerByAudio: { type: 'boolean', enum: [true, false] }, + host: { type: 'string' }, + port: { type: 'string' }, + protocol: { type: 'string' }, + username: { type: 'string' }, + password: { type: 'string' }, }, - required: ['enabled', 'url', 'token', 'waNumber', 'answerByAudio'], - ...isNotEmpty('enabled', 'url', 'token', 'waNumber', 'answerByAudio'), + required: ['enabled', 'host', 'port', 'protocol'], + ...isNotEmpty('enabled', 'host', 'port', 'protocol'), }; diff --git a/src/validate/settings.schema.ts b/src/validate/settings.schema.ts new file mode 100644 index 00000000..95a0e9c9 --- /dev/null +++ b/src/validate/settings.schema.ts @@ -0,0 +1,38 @@ +import { JSONSchema7 } from 'json-schema'; +import { v4 } from 'uuid'; + +const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => { + const properties = {}; + propertyNames.forEach( + (property) => + (properties[property] = { + minLength: 1, + description: `The "${property}" cannot be empty`, + }), + ); + return { + if: { + propertyNames: { + enum: [...propertyNames], + }, + }, + then: { properties }, + }; +}; + +export const settingsSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + rejectCall: { type: 'boolean' }, + msgCall: { type: 'string' }, + groupsIgnore: { type: 'boolean' }, + alwaysOnline: { type: 'boolean' }, + readMessages: { type: 'boolean' }, + readStatus: { type: 'boolean' }, + syncFullHistory: { type: 'boolean' }, + wavoipToken: { type: 'string' }, + }, + required: ['rejectCall', 'groupsIgnore', 'alwaysOnline', 'readMessages', 'readStatus', 'syncFullHistory'], + ...isNotEmpty('rejectCall', 'groupsIgnore', 'alwaysOnline', 'readMessages', 'readStatus', 'syncFullHistory'), +}; diff --git a/src/validate/template.schema.ts b/src/validate/template.schema.ts new file mode 100644 index 00000000..4adb08c0 --- /dev/null +++ b/src/validate/template.schema.ts @@ -0,0 +1,36 @@ +import { JSONSchema7 } from 'json-schema'; +import { v4 } from 'uuid'; + +const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => { + const properties = {}; + propertyNames.forEach( + (property) => + (properties[property] = { + minLength: 1, + description: `The "${property}" cannot be empty`, + }), + ); + return { + if: { + propertyNames: { + enum: [...propertyNames], + }, + }, + then: { properties }, + }; +}; + +export const templateSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + name: { type: 'string' }, + category: { type: 'string', enum: ['AUTHENTICATION', 'MARKETING', 'UTILITY'] }, + allowCategoryChange: { type: 'boolean' }, + language: { type: 'string' }, + components: { type: 'array' }, + webhookUrl: { type: 'string' }, + }, + required: ['name', 'category', 'language', 'components'], + ...isNotEmpty('name', 'category', 'language', 'components'), +}; diff --git a/src/validate/validate.schema.ts b/src/validate/validate.schema.ts index 8f7cb1a0..cf3d7828 100644 --- a/src/validate/validate.schema.ts +++ b/src/validate/validate.schema.ts @@ -1,1086 +1,11 @@ -import { JSONSchema7, JSONSchema7Definition } from 'json-schema'; -import { v4 } from 'uuid'; - // Integrations Schema -export * from '../api/integrations/chamaai/validate/chamaai.schema'; -export * from '../api/integrations/chatwoot/validate/chatwoot.schema'; -export * from '../api/integrations/rabbitmq/validate/rabbitmq.schema'; -export * from '../api/integrations/sqs/validate/sqs.schema'; -export * from '../api/integrations/typebot/validate/typebot.schema'; - -const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => { - const properties = {}; - propertyNames.forEach( - (property) => - (properties[property] = { - minLength: 1, - description: `The "${property}" cannot be empty`, - }), - ); - return { - if: { - propertyNames: { - enum: [...propertyNames], - }, - }, - then: { properties }, - }; -}; - -// Instance Schema -export const instanceNameSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - instanceName: { type: 'string' }, - webhook: { type: 'string' }, - webhook_by_events: { type: 'boolean' }, - events: { - type: 'array', - minItems: 0, - items: { - type: 'string', - enum: [ - 'APPLICATION_STARTUP', - 'QRCODE_UPDATED', - 'MESSAGES_SET', - 'MESSAGES_UPSERT', - 'MESSAGES_UPDATE', - 'MESSAGES_DELETE', - 'SEND_MESSAGE', - 'CONTACTS_SET', - 'CONTACTS_UPSERT', - 'CONTACTS_UPDATE', - 'PRESENCE_UPDATE', - 'CHATS_SET', - 'CHATS_UPSERT', - 'CHATS_UPDATE', - 'CHATS_DELETE', - 'GROUPS_UPSERT', - 'GROUP_UPDATE', - 'GROUP_PARTICIPANTS_UPDATE', - 'CONNECTION_UPDATE', - 'LABELS_EDIT', - 'LABELS_ASSOCIATION', - 'CALL', - 'NEW_JWT_TOKEN', - 'TYPEBOT_START', - 'TYPEBOT_CHANGE_STATUS', - 'CHAMA_AI_ACTION', - ], - }, - }, - qrcode: { type: 'boolean', enum: [true, false] }, - number: { type: 'string', pattern: '^\\d+[\\.@\\w-]+' }, - token: { type: 'string' }, - }, - ...isNotEmpty('instanceName'), -}; - -export const oldTokenSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - oldToken: { type: 'string' }, - }, - required: ['oldToken'], - ...isNotEmpty('oldToken'), -}; - -const quotedOptionsSchema: JSONSchema7 = { - properties: { - key: { - type: 'object', - properties: { - id: { type: 'string' }, - remoteJid: { type: 'string' }, - fromMe: { type: 'boolean', enum: [true, false] }, - }, - required: ['id'], - ...isNotEmpty('id'), - }, - message: { type: 'object' }, - }, -}; - -const mentionsOptionsSchema: JSONSchema7 = { - properties: { - everyOne: { type: 'boolean', enum: [true, false] }, - mentioned: { - type: 'array', - minItems: 1, - uniqueItems: true, - items: { - type: 'string', - pattern: '^\\d+', - description: '"mentioned" must be an array of numeric strings', - }, - }, - }, -}; - -// Send Message Schema -const optionsSchema: JSONSchema7 = { - properties: { - delay: { - type: 'integer', - description: 'Enter a value in milliseconds', - }, - presence: { - type: 'string', - enum: ['unavailable', 'available', 'composing', 'recording', 'paused'], - }, - quoted: { ...quotedOptionsSchema }, - mentions: { ...mentionsOptionsSchema }, - }, -}; - -const numberDefinition: JSONSchema7Definition = { - type: 'string', - description: 'Invalid format', -}; - -export const textMessageSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - number: { ...numberDefinition }, - options: { ...optionsSchema }, - textMessage: { - type: 'object', - properties: { - text: { type: 'string' }, - }, - required: ['text'], - ...isNotEmpty('text'), - }, - }, - required: ['textMessage', 'number'], -}; - -export const presenceSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - number: { ...numberDefinition }, - options: { ...optionsSchema, required: ['presence', 'delay'] }, - }, - required: ['options', 'number'], -}; - -export const presenceOnlySchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - presence: { - type: 'string', - enum: ['unavailable', 'available', 'composing', 'recording', 'paused'], - }, - }, - required: ['presence'], -}; - -export const pollMessageSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - number: { ...numberDefinition }, - options: { ...optionsSchema }, - pollMessage: { - type: 'object', - properties: { - name: { type: 'string' }, - selectableCount: { type: 'integer', minimum: 0, maximum: 10 }, - values: { - type: 'array', - minItems: 2, - maxItems: 10, - uniqueItems: true, - items: { - type: 'string', - }, - }, - }, - required: ['name', 'selectableCount', 'values'], - ...isNotEmpty('name', 'selectableCount', 'values'), - }, - }, - required: ['pollMessage', 'number'], -}; - -export const statusMessageSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - statusMessage: { - type: 'object', - properties: { - type: { type: 'string', enum: ['text', 'image', 'audio', 'video'] }, - content: { type: 'string' }, - caption: { type: 'string' }, - backgroundColor: { type: 'string' }, - font: { type: 'integer', minimum: 0, maximum: 5 }, - statusJidList: { - type: 'array', - minItems: 1, - uniqueItems: true, - items: { - type: 'string', - pattern: '^\\d+', - description: '"statusJidList" must be an array of numeric strings', - }, - }, - allContacts: { type: 'boolean', enum: [true, false] }, - }, - required: ['type', 'content'], - ...isNotEmpty('type', 'content'), - }, - }, - required: ['statusMessage'], -}; - -export const mediaMessageSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - number: { ...numberDefinition }, - options: { ...optionsSchema }, - mediaMessage: { - type: 'object', - properties: { - mediatype: { type: 'string', enum: ['image', 'document', 'video', 'audio'] }, - media: { type: 'string' }, - fileName: { type: 'string' }, - caption: { type: 'string' }, - }, - required: ['mediatype', 'media'], - ...isNotEmpty('fileName', 'caption', 'media'), - }, - }, - required: ['mediaMessage', 'number'], -}; - -export const stickerMessageSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - number: { ...numberDefinition }, - options: { ...optionsSchema }, - stickerMessage: { - type: 'object', - properties: { - image: { type: 'string' }, - }, - required: ['image'], - ...isNotEmpty('image'), - }, - }, - required: ['stickerMessage', 'number'], -}; - -export const audioMessageSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - number: { ...numberDefinition }, - options: { ...optionsSchema }, - audioMessage: { - type: 'object', - properties: { - audio: { type: 'string' }, - }, - required: ['audio'], - ...isNotEmpty('audio'), - }, - }, - required: ['audioMessage', 'number'], -}; - -export const templateMessageSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - number: { ...numberDefinition }, - options: { ...optionsSchema }, - templateMessage: { - type: 'object', - properties: { - name: { type: 'string' }, - language: { type: 'string' }, - components: { type: 'array' }, - }, - required: ['name', 'language'], - ...isNotEmpty('name', 'language'), - }, - }, - required: ['templateMessage', 'number'], -}; - -export const buttonMessageSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - number: { ...numberDefinition }, - options: { ...optionsSchema }, - buttonMessage: { - type: 'object', - properties: { - title: { type: 'string' }, - description: { type: 'string' }, - footerText: { type: 'string' }, - buttons: { - type: 'array', - minItems: 1, - uniqueItems: true, - items: { - type: 'object', - properties: { - buttonText: { type: 'string' }, - buttonId: { type: 'string' }, - }, - required: ['buttonText', 'buttonId'], - ...isNotEmpty('buttonText', 'buttonId'), - }, - }, - mediaMessage: { - type: 'object', - properties: { - media: { type: 'string' }, - fileName: { type: 'string' }, - mediatype: { type: 'string', enum: ['image', 'document', 'video'] }, - }, - required: ['media', 'mediatype'], - ...isNotEmpty('media', 'fileName'), - }, - }, - required: ['title', 'buttons'], - ...isNotEmpty('title', 'description'), - }, - }, - required: ['number', 'buttonMessage'], -}; - -export const locationMessageSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - number: { ...numberDefinition }, - options: { ...optionsSchema }, - locationMessage: { - type: 'object', - properties: { - latitude: { type: 'number' }, - longitude: { type: 'number' }, - name: { type: 'string' }, - address: { type: 'string' }, - }, - required: ['latitude', 'longitude'], - ...isNotEmpty('name', 'addresss'), - }, - }, - required: ['number', 'locationMessage'], -}; - -export const listMessageSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - number: { ...numberDefinition }, - options: { ...optionsSchema }, - listMessage: { - type: 'object', - properties: { - title: { type: 'string' }, - description: { type: 'string' }, - footerText: { type: 'string' }, - buttonText: { type: 'string' }, - sections: { - type: 'array', - minItems: 1, - uniqueItems: true, - items: { - type: 'object', - properties: { - title: { type: 'string' }, - rows: { - type: 'array', - minItems: 1, - uniqueItems: true, - items: { - type: 'object', - properties: { - title: { type: 'string' }, - description: { type: 'string' }, - rowId: { type: 'string' }, - }, - required: ['title', 'rowId'], - ...isNotEmpty('title', 'description', 'rowId'), - }, - }, - }, - required: ['title', 'rows'], - ...isNotEmpty('title'), - }, - }, - }, - required: ['title', 'description', 'buttonText', 'sections'], - ...isNotEmpty('title', 'description', 'buttonText', 'footerText'), - }, - }, - required: ['number', 'listMessage'], -}; - -export const contactMessageSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - number: { ...numberDefinition }, - options: { ...optionsSchema }, - contactMessage: { - type: 'array', - items: { - type: 'object', - properties: { - fullName: { type: 'string' }, - wuid: { - type: 'string', - minLength: 10, - pattern: '\\d+', - description: '"wuid" must be a numeric string', - }, - phoneNumber: { type: 'string', minLength: 10 }, - organization: { type: 'string' }, - email: { type: 'string' }, - url: { type: 'string' }, - }, - required: ['fullName', 'phoneNumber'], - ...isNotEmpty('fullName'), - }, - minItems: 1, - uniqueItems: true, - }, - }, - required: ['number', 'contactMessage'], -}; - -export const reactionMessageSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - reactionMessage: { - type: 'object', - properties: { - key: { - type: 'object', - properties: { - id: { type: 'string' }, - remoteJid: { type: 'string' }, - fromMe: { type: 'boolean', enum: [true, false] }, - }, - required: ['id', 'remoteJid', 'fromMe'], - ...isNotEmpty('id', 'remoteJid'), - }, - reaction: { type: 'string' }, - }, - required: ['key', 'reaction'], - ...isNotEmpty('reaction'), - }, - }, - required: ['reactionMessage'], -}; - -// Chat Schema -export const whatsappNumberSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - numbers: { - type: 'array', - minItems: 1, - uniqueItems: true, - items: { - type: 'string', - description: '"numbers" must be an array of numeric strings', - }, - }, - }, -}; - -export const readMessageSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - read_messages: { - type: 'array', - minItems: 1, - uniqueItems: true, - items: { - properties: { - id: { type: 'string' }, - fromMe: { type: 'boolean', enum: [true, false] }, - remoteJid: { type: 'string' }, - }, - required: ['id', 'fromMe', 'remoteJid'], - ...isNotEmpty('id', 'remoteJid'), - }, - }, - }, - required: ['read_messages'], -}; - -export const privacySettingsSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - privacySettings: { - type: 'object', - properties: { - readreceipts: { type: 'string', enum: ['all', 'none'] }, - profile: { - type: 'string', - enum: ['all', 'contacts', 'contact_blacklist', 'none'], - }, - status: { - type: 'string', - enum: ['all', 'contacts', 'contact_blacklist', 'none'], - }, - online: { type: 'string', enum: ['all', 'match_last_seen'] }, - last: { type: 'string', enum: ['all', 'contacts', 'contact_blacklist', 'none'] }, - groupadd: { - type: 'string', - enum: ['all', 'contacts', 'contact_blacklist', 'none'], - }, - }, - required: ['readreceipts', 'profile', 'status', 'online', 'last', 'groupadd'], - ...isNotEmpty('readreceipts', 'profile', 'status', 'online', 'last', 'groupadd'), - }, - }, - required: ['privacySettings'], -}; - -export const blockUserSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - number: { type: 'string' }, - status: { type: 'string', enum: ['block', 'unblock'] }, - }, - required: ['number', 'status'], - ...isNotEmpty('number', 'status'), -}; - -export const archiveChatSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - chat: { type: 'string' }, - lastMessage: { - type: 'object', - properties: { - key: { - type: 'object', - properties: { - id: { type: 'string' }, - remoteJid: { type: 'string' }, - fromMe: { type: 'boolean', enum: [true, false] }, - }, - required: ['id', 'fromMe', 'remoteJid'], - ...isNotEmpty('id', 'remoteJid'), - }, - messageTimestamp: { type: 'integer', minLength: 1 }, - }, - required: ['key'], - ...isNotEmpty('messageTimestamp'), - }, - archive: { type: 'boolean', enum: [true, false] }, - }, - required: ['archive'], -}; - -export const markChatUnreadSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - chat: { type: 'string' }, - lastMessage: { - type: 'object', - properties: { - key: { - type: 'object', - properties: { - id: { type: 'string' }, - remoteJid: { type: 'string' }, - fromMe: { type: 'boolean', enum: [true, false] }, - }, - required: ['id', 'fromMe', 'remoteJid'], - ...isNotEmpty('id', 'remoteJid'), - }, - messageTimestamp: { type: 'integer', minLength: 1 }, - }, - required: ['key'], - ...isNotEmpty('messageTimestamp'), - }, - }, - required: ['lastMessage'], -}; - -export const deleteMessageSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - id: { type: 'string' }, - fromMe: { type: 'boolean', enum: [true, false] }, - remoteJid: { type: 'string' }, - participant: { type: 'string' }, - }, - required: ['id', 'fromMe', 'remoteJid'], - ...isNotEmpty('id', 'remoteJid', 'participant'), -}; - -export const contactValidateSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - where: { - type: 'object', - properties: { - _id: { type: 'string', minLength: 1 }, - pushName: { type: 'string', minLength: 1 }, - id: { type: 'string', minLength: 1 }, - }, - ...isNotEmpty('_id', 'id', 'pushName'), - }, - }, -}; - -export const profileNameSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - name: { type: 'string' }, - }, - ...isNotEmpty('name'), -}; - -export const profileStatusSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - status: { type: 'string' }, - }, - ...isNotEmpty('status'), -}; - -export const updateMessageSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - number: { type: 'string' }, - text: { type: 'string' }, - key: { - type: 'object', - properties: { - id: { type: 'string' }, - remoteJid: { type: 'string' }, - fromMe: { type: 'boolean', enum: [true, false] }, - }, - required: ['id', 'fromMe', 'remoteJid'], - ...isNotEmpty('id', 'remoteJid'), - }, - }, - ...isNotEmpty('number', 'text', 'key'), -}; - -export const profilePictureSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - number: { type: 'string' }, - picture: { type: 'string' }, - }, -}; - -export const profileSchema: JSONSchema7 = { - type: 'object', - properties: { - wuid: { type: 'string' }, - name: { type: 'string' }, - picture: { type: 'string' }, - status: { type: 'string' }, - isBusiness: { type: 'boolean' }, - }, -}; - -export const messageValidateSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - where: { - type: 'object', - properties: { - _id: { type: 'string', minLength: 1 }, - key: { - type: 'object', - if: { - propertyNames: { - enum: ['fromMe', 'remoteJid', 'id'], - }, - }, - then: { - properties: { - remoteJid: { - type: 'string', - minLength: 1, - description: 'The property cannot be empty', - }, - id: { - type: 'string', - minLength: 1, - description: 'The property cannot be empty', - }, - fromMe: { type: 'boolean', enum: [true, false] }, - }, - }, - }, - message: { type: 'object' }, - }, - ...isNotEmpty('_id'), - }, - limit: { type: 'integer' }, - }, -}; - -export const messageUpSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - where: { - type: 'object', - properties: { - _id: { type: 'string' }, - remoteJid: { type: 'string' }, - id: { type: 'string' }, - fromMe: { type: 'boolean', enum: [true, false] }, - participant: { type: 'string' }, - status: { - type: 'string', - enum: ['ERROR', 'PENDING', 'SERVER_ACK', 'DELIVERY_ACK', 'READ', 'PLAYED'], - }, - }, - ...isNotEmpty('_id', 'remoteJid', 'id', 'status'), - }, - limit: { type: 'integer' }, - }, -}; - -// Group Schema -export const createGroupSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - subject: { type: 'string' }, - description: { type: 'string' }, - profilePicture: { type: 'string' }, - promoteParticipants: { type: 'boolean', enum: [true, false] }, - participants: { - type: 'array', - minItems: 1, - uniqueItems: true, - items: { - type: 'string', - minLength: 10, - pattern: '\\d+', - description: '"participants" must be an array of numeric strings', - }, - }, - }, - required: ['subject', 'participants'], - ...isNotEmpty('subject', 'description', 'profilePicture'), -}; - -export const groupJidSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - groupJid: { type: 'string', pattern: '^[\\d-]+@g.us$' }, - }, - required: ['groupJid'], - ...isNotEmpty('groupJid'), -}; - -export const getParticipantsSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - getParticipants: { type: 'string', enum: ['true', 'false'] }, - }, - required: ['getParticipants'], - ...isNotEmpty('getParticipants'), -}; - -export const groupSendInviteSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - groupJid: { type: 'string' }, - description: { type: 'string' }, - numbers: { - type: 'array', - minItems: 1, - uniqueItems: true, - items: { - type: 'string', - minLength: 10, - pattern: '\\d+', - description: '"numbers" must be an array of numeric strings', - }, - }, - }, - required: ['groupJid', 'description', 'numbers'], - ...isNotEmpty('groupJid', 'description', 'numbers'), -}; - -export const groupInviteSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - inviteCode: { type: 'string', pattern: '^[a-zA-Z0-9]{22}$' }, - }, - required: ['inviteCode'], - ...isNotEmpty('inviteCode'), -}; - -export const AcceptGroupInviteSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - inviteCode: { type: 'string', pattern: '^[a-zA-Z0-9]{22}$' }, - }, - required: ['inviteCode'], - ...isNotEmpty('inviteCode'), -}; - -export const updateParticipantsSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - groupJid: { type: 'string' }, - action: { - type: 'string', - enum: ['add', 'remove', 'promote', 'demote'], - }, - participants: { - type: 'array', - minItems: 1, - uniqueItems: true, - items: { - type: 'string', - minLength: 10, - pattern: '\\d+', - description: '"participants" must be an array of numeric strings', - }, - }, - }, - required: ['groupJid', 'action', 'participants'], - ...isNotEmpty('groupJid', 'action'), -}; - -export const updateSettingsSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - groupJid: { type: 'string' }, - action: { - type: 'string', - enum: ['announcement', 'not_announcement', 'locked', 'unlocked'], - }, - }, - required: ['groupJid', 'action'], - ...isNotEmpty('groupJid', 'action'), -}; - -export const toggleEphemeralSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - groupJid: { type: 'string' }, - expiration: { - type: 'number', - enum: [0, 86400, 604800, 7776000], - }, - }, - required: ['groupJid', 'expiration'], - ...isNotEmpty('groupJid', 'expiration'), -}; - -export const updateGroupPictureSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - groupJid: { type: 'string' }, - image: { type: 'string' }, - }, - required: ['groupJid', 'image'], - ...isNotEmpty('groupJid', 'image'), -}; - -export const updateGroupSubjectSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - groupJid: { type: 'string' }, - subject: { type: 'string' }, - }, - required: ['groupJid', 'subject'], - ...isNotEmpty('groupJid', 'subject'), -}; - -export const updateGroupDescriptionSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - groupJid: { type: 'string' }, - description: { type: 'string' }, - }, - required: ['groupJid', 'description'], - ...isNotEmpty('groupJid', 'description'), -}; - -export const webhookSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - url: { type: 'string' }, - events: { - type: 'array', - minItems: 0, - items: { - type: 'string', - enum: [ - 'APPLICATION_STARTUP', - 'QRCODE_UPDATED', - 'MESSAGES_SET', - 'MESSAGES_UPSERT', - 'MESSAGES_UPDATE', - 'MESSAGES_DELETE', - 'SEND_MESSAGE', - 'CONTACTS_SET', - 'CONTACTS_UPSERT', - 'CONTACTS_UPDATE', - 'PRESENCE_UPDATE', - 'CHATS_SET', - 'CHATS_UPSERT', - 'CHATS_UPDATE', - 'CHATS_DELETE', - 'GROUPS_UPSERT', - 'GROUP_UPDATE', - 'GROUP_PARTICIPANTS_UPDATE', - 'CONNECTION_UPDATE', - 'LABELS_EDIT', - 'LABELS_ASSOCIATION', - 'CALL', - 'NEW_JWT_TOKEN', - 'TYPEBOT_START', - 'TYPEBOT_CHANGE_STATUS', - 'CHAMA_AI_ACTION', - ], - }, - }, - }, - required: ['url'], - ...isNotEmpty('url'), -}; - -export const settingsSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - reject_call: { type: 'boolean', enum: [true, false] }, - msg_call: { type: 'string' }, - groups_ignore: { type: 'boolean', enum: [true, false] }, - always_online: { type: 'boolean', enum: [true, false] }, - read_messages: { type: 'boolean', enum: [true, false] }, - read_status: { type: 'boolean', enum: [true, false] }, - sync_full_history: { type: 'boolean', enum: [true, false] }, - }, - required: ['reject_call', 'groups_ignore', 'always_online', 'read_messages', 'read_status', 'sync_full_history'], - ...isNotEmpty('reject_call', 'groups_ignore', 'always_online', 'read_messages', 'read_status', 'sync_full_history'), -}; - -export const websocketSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - enabled: { type: 'boolean', enum: [true, false] }, - events: { - type: 'array', - minItems: 0, - items: { - type: 'string', - enum: [ - 'APPLICATION_STARTUP', - 'QRCODE_UPDATED', - 'MESSAGES_SET', - 'MESSAGES_UPSERT', - 'MESSAGES_UPDATE', - 'MESSAGES_DELETE', - 'SEND_MESSAGE', - 'CONTACTS_SET', - 'CONTACTS_UPSERT', - 'CONTACTS_UPDATE', - 'PRESENCE_UPDATE', - 'CHATS_SET', - 'CHATS_UPSERT', - 'CHATS_UPDATE', - 'CHATS_DELETE', - 'GROUPS_UPSERT', - 'GROUP_UPDATE', - 'GROUP_PARTICIPANTS_UPDATE', - 'CONNECTION_UPDATE', - 'LABELS_EDIT', - 'LABELS_ASSOCIATION', - 'CALL', - 'NEW_JWT_TOKEN', - 'TYPEBOT_START', - 'TYPEBOT_CHANGE_STATUS', - 'CHAMA_AI_ACTION', - ], - }, - }, - }, - required: ['enabled'], - ...isNotEmpty('enabled'), -}; - -export const proxySchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - enabled: { type: 'boolean', enum: [true, false] }, - proxy: { - type: 'object', - properties: { - host: { type: 'string' }, - port: { type: 'string' }, - protocol: { type: 'string' }, - username: { type: 'string' }, - password: { type: 'string' }, - }, - required: ['host', 'port', 'protocol'], - ...isNotEmpty('host', 'port', 'protocol'), - }, - }, - required: ['enabled', 'proxy'], - ...isNotEmpty('enabled', 'proxy'), -}; - -export const handleLabelSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - number: { ...numberDefinition }, - labelId: { type: 'string' }, - action: { type: 'string', enum: ['add', 'remove'] }, - }, - required: ['number', 'labelId', 'action'], -}; +export * from './chat.schema'; +export * from './group.schema'; +export * from './instance.schema'; +export * from './label.schema'; +export * from './message.schema'; +export * from './proxy.schema'; +export * from './settings.schema'; +export * from './template.schema'; +export * from '@api/integrations/chatbot/chatbot.schema'; +export * from '@api/integrations/event/event.schema'; diff --git a/start.sh b/start.sh deleted file mode 100644 index 06a55e4a..00000000 --- a/start.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh - -if [ "$DOCKER_ENV" = "true" ]; -then - echo "Enabling environment variables for Docker" - echo "DOCKER_ENV=$DOCKER_ENV" - echo -else - mkdir -p ./dist/src - cp ./src/env.yml ./dist/src -fi -echo "> removing dist" -rm -rf ./dist -echo -echo "> transpiling..." -npm run build - -echo -echo "> Successfully build " - -echo -echo "> Starting application..." -echo - -node ./dist/src/main.js \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 156bb77c..af814134 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,8 +3,8 @@ "experimentalDecorators": true, "emitDecoratorMetadata": true, "declaration": true, - "target": "ES6", - "module": "commonjs", + "target": "es2020", + "module": "CommonJS", "rootDir": "./", "resolveJsonModule": true, "removeComments": true, @@ -16,7 +16,18 @@ "skipLibCheck": true, "strictNullChecks": false, "incremental": true, - "noImplicitAny": false + "noImplicitAny": false, + "baseUrl": ".", + "paths": { + "@api/*": ["./src/api/*"], + "@cache/*": ["./src/cache/*"], + "@config/*": ["./src/config/*"], + "@exceptions": ["./src/exceptions"], + "@libs/*": ["./src/libs/*"], + "@utils/*": ["./src/utils/*"], + "@validate/*": ["./src/validate/*"] + }, + "moduleResolution": "Node" }, "exclude": ["node_modules", "./test", "./dist", "./prisma"], "include": [ diff --git a/tsup.config.ts b/tsup.config.ts new file mode 100644 index 00000000..2450b52f --- /dev/null +++ b/tsup.config.ts @@ -0,0 +1,19 @@ +import { cpSync } from 'node:fs'; + +import { defineConfig } from 'tsup'; + +export default defineConfig({ + entry: ['src'], + outDir: 'dist', + splitting: false, + sourcemap: true, + clean: true, + minify: true, + format: ['cjs', 'esm'], + onSuccess: async () => { + cpSync('src/utils/translations', 'dist/translations', { recursive: true }); + }, + loader: { + '.json': 'file', + }, +}); diff --git a/views/manager.hbs b/views/manager.hbs deleted file mode 100644 index 57d5fca4..00000000 --- a/views/manager.hbs +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - Instance Manager - - - - - - - - - \ No newline at end of file