From 3eb22445fe45f3d84f4ae889aa8b01f0b22c07f6 Mon Sep 17 00:00:00 2001 From: Ben Teichman Date: Tue, 23 Apr 2024 14:59:34 -0400 Subject: [PATCH] feat: upgrade toolchain to latest (#139) --- .circleci/continue-config.yml | 44 +- .depcheckrc | 34 - .editorconfig | 31 +- .gitignore | 54 +- .husky/commit-msg | 1 - .husky/pre-commit | 1 - .husky/pre-push | 1 - .lintstagedrc.js | 4 - .prettierignore | 27 +- .releaserc | 5 - .vscode/settings.json | 68 +- README.md | 8 +- commitlint.config.js | 3 - eslint.config.mjs | 14 + examples/live-agent/.eslintrc.js | 7 - examples/live-agent/index.html | 26 +- examples/live-agent/package.json | 15 +- examples/live-agent/server/package.json | 8 +- .../server/src/intercom/intercom.routes.ts | 2 +- .../server/src/intercom/intercom.service.ts | 8 +- examples/live-agent/server/src/main.ts | 2 +- examples/live-agent/server/tsconfig.json | 2 +- examples/live-agent/src/context.tsx | 3 +- .../live-agent/src/traces/LiveAgent.trace.ts | 4 +- .../live-agent/src/use-live-agent.hook.ts | 17 +- examples/live-agent/tsconfig.json | 6 +- lerna.json | 8 +- package.json | 119 +- packages/react-chat/.depcheckrc | 36 - packages/react-chat/.dependency-cruiser.mjs | 3 + packages/react-chat/.eslintignore | 7 - packages/react-chat/.eslintoutputrc | 13 - packages/react-chat/.eslintrc.js | 42 - packages/react-chat/.gitignore | 4 - packages/react-chat/.storybook/main.ts | 9 +- packages/react-chat/.storybook/preview.tsx | 2 +- packages/react-chat/README.md | 18 +- packages/react-chat/chromatic.config.json | 4 +- packages/react-chat/config/test/setup.ts | 2 +- packages/react-chat/e2e/embedded.html | 75 +- packages/react-chat/e2e/extensions.html | 221 +- packages/react-chat/e2e/extensions.spec.ts | 11 +- packages/react-chat/e2e/overlay.html | 51 +- packages/react-chat/e2e/proactive.html | 53 +- packages/react-chat/e2e/proactive.spec.ts | 2 +- packages/react-chat/examples/index.html | 2 +- packages/react-chat/package.json | 146 +- packages/react-chat/playwright.config.ts | 4 +- packages/react-chat/sonar-project.properties | 8 + packages/react-chat/src/common/index.ts | 1 - packages/react-chat/src/common/utils.ts | 5 - .../AssistantInfo/AssistantInfo.story.tsx | 5 +- .../src/components/Avatar/Avatar.story.tsx | 2 +- .../src/components/Avatar/index.tsx | 2 +- .../src/components/Bubble/Bubble.story.tsx | 2 +- .../src/components/Bubble/index.tsx | 5 +- .../src/components/Button/Button.story.tsx | 2 +- .../src/components/Button/Button.test.tsx | 8 +- .../src/components/Card/Card.story.tsx | 5 +- .../react-chat/src/components/Card/index.tsx | 2 +- .../react-chat/src/components/Card/types.ts | 2 +- .../components/Carousel/Carousel.story.tsx | 5 +- .../components/Carousel/CarouselButton.tsx | 31 +- .../src/components/Carousel/hooks.ts | 5 +- .../src/components/Carousel/index.tsx | 19 +- .../src/components/Carousel/styled.ts | 4 +- .../src/components/Chat/Chat.story.tsx | 11 +- .../react-chat/src/components/Chat/hooks.ts | 2 +- .../react-chat/src/components/Chat/index.tsx | 24 +- .../react-chat/src/components/Chat/styled.ts | 3 +- .../components/ChatInput/ChatInput.story.tsx | 2 +- .../src/components/ChatInput/index.tsx | 3 +- .../src/components/Feedback/index.tsx | 12 +- .../src/components/Footer/Footer.story.tsx | 2 +- .../src/components/Footer/index.tsx | 3 +- .../src/components/Header/Header.story.tsx | 2 +- .../src/components/Header/index.tsx | 3 +- .../src/components/Icon/Icon.story.tsx | 2 +- .../src/components/Image/Default.tsx | 6 +- .../src/components/Image/Image.story.tsx | 2 +- .../src/components/Input/Input.story.tsx | 2 +- .../react-chat/src/components/Input/index.tsx | 5 +- .../react-chat/src/components/Input/styled.ts | 3 +- .../components/Launcher/Launcher.story.tsx | 2 +- .../src/components/Launcher/index.tsx | 3 +- .../src/components/Loader/Loader.story.tsx | 2 +- .../components/Message/DebugMessage/index.tsx | 2 +- .../src/components/Message/Message.story.tsx | 2 +- .../src/components/Proactive/Close.tsx | 2 +- .../src/components/Proactive/index.tsx | 8 +- .../src/components/Prompt/Prompt.story.tsx | 2 +- .../SystemResponse/ExtensionMessage.tsx | 5 +- .../SystemResponse/SystemMessage.tsx | 11 +- .../SystemResponse/SystemResponse.story.tsx | 16 +- .../src/components/SystemResponse/hooks.ts | 15 +- .../src/components/SystemResponse/index.tsx | 20 +- .../components/SystemResponse/state/end.tsx | 2 +- .../src/components/SystemResponse/styled.ts | 2 +- .../src/components/SystemResponse/types.ts | 10 +- .../src/components/Text/Default.tsx | 1 - .../src/components/Text/Markdown.tsx | 3 +- .../components/Textarea/Textarea.story.tsx | 4 +- .../src/components/Textarea/index.tsx | 25 +- .../src/components/Textarea/styled.ts | 3 +- .../components/Timestamp/Timestamp.story.tsx | 2 +- .../src/components/Tooltip/Tooltip.story.tsx | 2 +- .../src/components/Tooltip/index.tsx | 2 +- .../TypingIndicator/TypingIndicator.story.tsx | 2 +- .../UserResponse/UserResponse.story.tsx | 2 +- .../src/contexts/RuntimeContext/index.tsx | 3 +- .../src/contexts/RuntimeContext/messages.ts | 5 +- .../traces/EffectExtensions.trace.ts | 9 +- .../RuntimeContext/traces/NoReply.trace.ts | 12 +- .../traces/ResponseExtensions.trace.ts | 9 +- .../src/contexts/RuntimeContext/useNoReply.ts | 2 +- .../contexts/RuntimeContext/useRuntimeAPI.ts | 17 +- .../RuntimeContext/useRuntimeState.ts | 15 +- .../src/dtos/AssistantOptions.dto.ts | 2 +- .../src/dtos/ChatConfig.dto.test.ts | 2 + .../react-chat/src/dtos/ChatConfig.dto.ts | 5 +- packages/react-chat/src/dtos/Extension.dto.ts | 2 +- .../src/dtos/RenderOptions.dto.test.ts | 7 +- .../react-chat/src/dtos/RenderOptions.dto.ts | 1 - packages/react-chat/src/hocs/tag.tsx | 11 +- packages/react-chat/src/hooks/useChatAPI.ts | 13 +- packages/react-chat/src/hooks/useStateRef.ts | 6 +- packages/react-chat/src/hooks/useTheme.ts | 2 +- packages/react-chat/src/index.tsx | 18 +- packages/react-chat/src/styles.css | 5 - packages/react-chat/src/styles/animation.ts | 17 +- packages/react-chat/src/styles/fragments.ts | 2 +- packages/react-chat/src/types/index.ts | 7 +- .../src/{common/types.ts => types/session.ts} | 2 +- packages/react-chat/src/types/trace.ts | 8 +- packages/react-chat/src/utils/actions.ts | 4 +- .../react-chat/src/utils/assistant.test.ts | 42 +- packages/react-chat/src/utils/assistant.ts | 10 +- packages/react-chat/src/utils/broadcast.ts | 4 +- packages/react-chat/src/utils/chat.ts | 4 +- packages/react-chat/src/utils/controls.tsx | 21 +- packages/react-chat/src/utils/functional.ts | 2 +- packages/react-chat/src/utils/session.ts | 5 +- packages/react-chat/src/utils/stylesheet.ts | 2 +- packages/react-chat/src/utils/url.ts | 3 +- packages/react-chat/src/utils/variants.tsx | 15 +- .../react-chat/src/views/ChatWidget/index.tsx | 2 +- .../react-chat/src/views/ChatWidget/styled.ts | 3 +- .../react-chat/src/views/ChatWindow/index.tsx | 4 +- packages/react-chat/tsconfig.build.json | 6 +- packages/react-chat/tsconfig.json | 26 +- packages/react-chat/vite.config.ts | 9 +- packages/react-chat/vite.package.config.ts | 2 +- packages/react-chat/vitest.config.mts | 16 + packages/react-chat/vitest.config.ts | 21 - scripts/setup_github_pages.sh | 12 - scripts/template.html | 26 - sonar-project.properties | 2 +- turbo.json | 41 +- yarn.lock | 6666 +++++++---------- 159 files changed, 3557 insertions(+), 5150 deletions(-) delete mode 100644 .depcheckrc delete mode 100644 .lintstagedrc.js delete mode 100644 .releaserc delete mode 100644 commitlint.config.js create mode 100644 eslint.config.mjs delete mode 100644 examples/live-agent/.eslintrc.js delete mode 100644 packages/react-chat/.depcheckrc create mode 100644 packages/react-chat/.dependency-cruiser.mjs delete mode 100644 packages/react-chat/.eslintignore delete mode 100644 packages/react-chat/.eslintoutputrc delete mode 100644 packages/react-chat/.eslintrc.js create mode 100644 packages/react-chat/sonar-project.properties rename packages/react-chat/src/{common/types.ts => types/session.ts} (92%) create mode 100644 packages/react-chat/vitest.config.mts delete mode 100644 packages/react-chat/vitest.config.ts delete mode 100755 scripts/setup_github_pages.sh delete mode 100644 scripts/template.html diff --git a/.circleci/continue-config.yml b/.circleci/continue-config.yml index f4ebe99e3..eb51f61c9 100644 --- a/.circleci/continue-config.yml +++ b/.circleci/continue-config.yml @@ -3,7 +3,7 @@ version: 2.1 parameters: ssh-fingerprint: type: string - default: "SHA256:r/0YTSpeTcY6psL0RvgtmDjZJB+raeTcfd/5bcQQ2DQ" + default: 'SHA256:r/0YTSpeTcY6psL0RvgtmDjZJB+raeTcfd/5bcQQ2DQ' build-apps: type: boolean default: false @@ -21,14 +21,14 @@ defaults: - vfcommon/notify_slack: channel: dev_general event: fail - mentions: "@eng_platform" + mentions: '@eng_platform' template: basic_fail_1 branch_pattern: master executors: playwright: docker: - - image: mcr.microsoft.com/playwright:v1.41.1-jammy + - image: mcr.microsoft.com/playwright:v1.43.1-jammy jobs: test: # Main unit, style, and dependency tests @@ -41,16 +41,25 @@ jobs: avoid_post_install_scripts: false - vfcommon/monorepo_lint_report: run_on_root: true + - vfcommon/monorepo_types_tests: + run_on_root: true - vfcommon/monorepo_dependency_tests: run_on_root: true - vfcommon/monorepo_unit_tests: run_on_root: true + - run: + name: Collect test reports + command: | + # copy all .report.xml files to the root directory + # and give them unique names based on their paths + find . -type f -name "*.report.xml" | xargs -I {} sh -c 'cp {} reports/$(echo {} | cut -c 3- | tr "/" "_")' + - store_test_results: + path: './reports' - vfcommon/monorepo_save_cache: - package: "all" - monorepo_engine: "turborepo" - cache_identifier: "monorepo-test-cache" - ## disable sonarcloud until project set up - # - sonarcloud/scan + package: 'all' + monorepo_engine: 'turborepo' + cache_identifier: 'monorepo-test-cache' + - sonarcloud/scan e2e: executor: playwright @@ -65,6 +74,15 @@ jobs: command: yarn test:e2e - store_artifacts: path: packages/react-chat/test-results + - run: + name: Collect test reports + command: | + # copy all .report.xml files to the root directory + # and give them unique names based on their paths + mkdir -p reports + find . -type f -name "*.report.xml" | xargs -I {} sh -c 'cp {} reports/$(echo {} | cut -c 3- | tr "/" "_")' + - store_test_results: + path: './reports' push-to-cdn: # Main unit, style, and dependency tests executor: vfcommon/node-executor-node-20 @@ -87,13 +105,13 @@ workflows: avoid_post_install_scripts: false name: build package: all - monorepo_engine: "turborepo" + monorepo_engine: 'turborepo' force_execute: true run_in_container: false - container_folder_to_copy: "" #Copy all + container_folder_to_copy: '' #Copy all post_build_steps: - persist_to_workspace: - root: "." + root: '.' paths: - ./packages/*/dist # persist dist folder too @@ -115,8 +133,8 @@ workflows: avoid_post_install_scripts: false ssh_key: << pipeline.parameters.ssh-fingerprint >> context: dev-test - release_engine: "lite" - commit_message: "chore(release): publish --skip-ci" + release_engine: 'lite' + commit_message: 'chore(release): publish --skip-ci' requires: - test - e2e diff --git a/.depcheckrc b/.depcheckrc deleted file mode 100644 index 07debff24..000000000 --- a/.depcheckrc +++ /dev/null @@ -1,34 +0,0 @@ -{ - "specials": [ - "bin", - "babel", - "eslint", - "lint-staged", - "istanbul", - "commitizen", - "husky", - "prettier", - "ttypescript" - ], - "ignores": [ - "@commitlint/*", - "@storybook/*", - "@types/*", - "@voiceflow/commitlint-config", - "@voiceflow/eslint-config", - "@voiceflow/git-branch-check", - "@voiceflow/tsconfig", - "@svgr/webpack", - "@emotion/core", - "@vitest/coverage-c8", - "storybook-dark-mode", - "eslint-import-resolver-typescript", - "eslint-plugin-mdx", - "eslint-plugin-storybook", - "babel-loader", - "fixpack", - "husky", - "lint-staged", - "slate" - ] -} diff --git a/.editorconfig b/.editorconfig index 2b192c31c..f5cf4fd52 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,30 +1,15 @@ +# EditorConfig: https://EditorConfig.org + +# top-most EditorConfig file root = true [*] -charset = utf-8 -end_of_line = lf -indent_size = 2 indent_style = space -insert_final_newline = true +indent_size = 2 +end_of_line = lf +charset = utf-8 trim_trailing_whitespace = true +insert_final_newline = true -[vcbuild.bat] -end_of_line = crlf - -[Makefile] -indent_size = 8 -indent_style = tab - -[{deps}/**] -charset = ignore -end_of_line = ignore -indent_size = ignore -indent_style = ignore -trim_trailing_whitespace = ignore - -[{test/fixtures,deps,tools/node_modules,tools/gyp,tools/icu,tools/msvs}/**] -insert_final_newline = false - -[*.js] +[*.json] trim_trailing_whitespace = false -max_line_length = 150 diff --git a/.gitignore b/.gitignore index 54203a350..cda8b149d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,36 +1,46 @@ -.DS_Store -.idea +*.log +*.local +.cache + +# Node node_modules -dump.rdb -coverage -log/ +# output +build +dist +storybook-static +docs -.nyc_output +# Turborepo +.turbo + +# Dotenv +.env +.env.* +!.env.e2e +!.env.test + +# MacOS +.DS_Store + +# ESlint +.eslintcache # Yarn .pnp.* -.yarn/* +.yarn !.yarn/patches !.yarn/plugins !.yarn/releases !.yarn/sdks !.yarn/versions -# build folders -build -dist - -# docs -docs - -#Sonar report -sonar/ -nyc_coverage* +# Tests +reports +*.report.xml -.turbo +# Coverage +sonar -.env.* - -build-storybook.log -storybook-static/ +#jetbrains +.idea diff --git a/.husky/commit-msg b/.husky/commit-msg index f2b882190..ba6cc2399 100755 --- a/.husky/commit-msg +++ b/.husky/commit-msg @@ -1,4 +1,3 @@ #!/usr/bin/env sh -. "$(dirname -- "$0")/_/husky.sh" yarn commitlint --edit "$1" diff --git a/.husky/pre-commit b/.husky/pre-commit index 5a182ef10..2de738c74 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,4 +1,3 @@ #!/usr/bin/env sh -. "$(dirname -- "$0")/_/husky.sh" yarn lint-staged diff --git a/.husky/pre-push b/.husky/pre-push index 4eea212e0..f246eb0d3 100755 --- a/.husky/pre-push +++ b/.husky/pre-push @@ -1,4 +1,3 @@ #!/usr/bin/env sh -. "$(dirname -- "$0")/_/husky.sh" yarn git-branch-check diff --git a/.lintstagedrc.js b/.lintstagedrc.js deleted file mode 100644 index 7bcb59a67..000000000 --- a/.lintstagedrc.js +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = { - 'package.json': ['fixpack'], - '**/*.{js,ts}': ['eslint --fix'], -}; diff --git a/.prettierignore b/.prettierignore index e754fee7d..92c6e233c 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,7 +1,26 @@ -coverage -.idea -.nyc_output +CHANGELOG.md + +# Node +node_modules + +# output build dist -node_modules +storybook-static + +# Yarn +.pnp.* +.yarn +*.lock + +# Yalc +.yalc + +# Coverage +sonar + +# Tests +*.report.xml +# Playwright +test-results diff --git a/.releaserc b/.releaserc deleted file mode 100644 index 8b993a237..000000000 --- a/.releaserc +++ /dev/null @@ -1,5 +0,0 @@ -{ - branches: [ - master - ] -} diff --git a/.vscode/settings.json b/.vscode/settings.json index 1d37891e0..e078b516c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,28 +1,48 @@ { - "editor.formatOnSave": true, - "eslint.format.enable": true, + "[html]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[javascript]": { + "editor.defaultFormatter": "dbaeumer.vscode-eslint" + }, + "[javascriptreact]": { + "editor.defaultFormatter": "dbaeumer.vscode-eslint" + }, + "[json]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[jsonc]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[markdown]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[typescript]": { + "editor.defaultFormatter": "dbaeumer.vscode-eslint" + }, + "[typescriptreact]": { + "editor.defaultFormatter": "dbaeumer.vscode-eslint" + }, + "[yaml]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[css]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, "editor.codeActionsOnSave": { - "source.fixAll.tslint": "explicit", "source.fixAll.eslint": "explicit" }, - "eslint.runtime": "node", - "eslint.execArgv": ["--max_old_space_size=8192"], - "eslint.options": { - "extensions": [ - ".js", - ".jsx", - ".md", - ".mdx", - ".ts", - ".tsx" - ] - }, - "eslint.validate": [ - "markdown", - "mdx", - "javascript", - "javascriptreact", - "typescript", - "typescriptreact" - ] -} \ No newline at end of file + "eslint.format.enable": true, + "eslint.experimental.useFlatConfig": true, + "search.exclude": { + "**/node_modules": true, + "**/build": true, + "**/dist": true, + "**/test-results": true, + "**/playwright-report": true, + "**/sonar": true, + "**/.husky": true, + "**/.yarn": true, + "**/.turbo": true + } +} diff --git a/README.md b/README.md index 64bd134ce..c579428bd 100644 --- a/README.md +++ b/README.md @@ -76,13 +76,13 @@ Ensure that the `verify: { projectID: ... }` field is replaced with your Voicefl s = d.getElementsByTagName(t)[0]; v.onload = function () { window.voiceflow.chat.load({ - verify: { projectID: "XXXXXX..." }, + verify: { projectID: 'XXXXXX...' }, }); }; - v.src = "https://cdn.voiceflow.com/widget/bundle.mjs"; - v.type = "text/javascript"; + v.src = 'https://cdn.voiceflow.com/widget/bundle.mjs'; + v.type = 'text/javascript'; s.parentNode.insertBefore(v, s); - })(document, "script"); + })(document, 'script'); ``` diff --git a/commitlint.config.js b/commitlint.config.js deleted file mode 100644 index 5d959343b..000000000 --- a/commitlint.config.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - extends: ['@voiceflow/commitlint-config'], -}; diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 000000000..905ecf62b --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,14 @@ +import baseConfig from '@voiceflow/eslint-config'; + +/** @type {import('eslint').Linter.FlatConfig[]} */ +export default [ + ...baseConfig, + { + ignores: ['**/storybook-static/**'], + }, + { + rules: { + 'no-console': ['error', { allow: ['info', 'warn', 'error'] }], + }, + }, +]; diff --git a/examples/live-agent/.eslintrc.js b/examples/live-agent/.eslintrc.js deleted file mode 100644 index 11038fe19..000000000 --- a/examples/live-agent/.eslintrc.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - extends: ['@voiceflow/eslint-config', '@voiceflow/eslint-config/frontend', '@voiceflow/eslint-config/typescript'], - rules: { - 'react/react-in-jsx-scope': 'off', - 'no-console': 'off', - }, -}; diff --git a/examples/live-agent/index.html b/examples/live-agent/index.html index 43d8cdae5..40d35f4e2 100644 --- a/examples/live-agent/index.html +++ b/examples/live-agent/index.html @@ -1,16 +1,14 @@ - + + + + + + Example - Live Agent + - - - - - Example - Live Agent - - - -
- - - - \ No newline at end of file + +
+ + + diff --git a/examples/live-agent/package.json b/examples/live-agent/package.json index a63641ee6..23fb5ae91 100644 --- a/examples/live-agent/package.json +++ b/examples/live-agent/package.json @@ -1,13 +1,13 @@ { "name": "@voiceflow-example/live-agent", - "private": true, "version": "1.1.0", + "private": true, "license": "MIT", "scripts": { - "build": "yarn g:tsc -p tsconfig.json --noEmit", "dev": "yarn g:run-p dev:app dev:server", "dev:app": "vite", - "dev:server": "cd server && yarn dev" + "dev:server": "cd server && yarn dev", + "test:types": "yarn g:tsc --noEmit" }, "prettier": "@voiceflow/prettier-config", "dependencies": { @@ -23,13 +23,12 @@ "ts-pattern": "4.3.0" }, "devDependencies": { - "@types/node": "20.2.5", + "@types/node": "20.12.7", "@types/react": "18.2.8", "@types/react-dom": "18.2.4", - "@voiceflow/eslint-config": "7.1.0", - "@voiceflow/prettier-config": "1.3.0", - "eslint": "8.42.0", - "prettier": "2.8.8", "vite": "4.3.9" + }, + "volta": { + "extends": "../../package.json" } } diff --git a/examples/live-agent/server/package.json b/examples/live-agent/server/package.json index ed475af33..1425b4e8d 100644 --- a/examples/live-agent/server/package.json +++ b/examples/live-agent/server/package.json @@ -2,7 +2,8 @@ "name": "@voiceflow-example/live-agent-server", "private": true, "scripts": { - "dev": "tsx --watch src/main.ts" + "dev": "tsx --watch src/main.ts", + "test:types": "yarn g:tsc --noEmit" }, "dependencies": { "body-parser": "1.20.2", @@ -20,6 +21,9 @@ "@types/express": "4.17.17", "@types/express-ws": "3.0.1", "@types/ws": "8.5.5", - "tsx": "3.12.7" + "tsx": "4.7.2" + }, + "volta": { + "extends": "../../../package.json" } } diff --git a/examples/live-agent/server/src/intercom/intercom.routes.ts b/examples/live-agent/server/src/intercom/intercom.routes.ts index ccc8c77bb..e959754e0 100644 --- a/examples/live-agent/server/src/intercom/intercom.routes.ts +++ b/examples/live-agent/server/src/intercom/intercom.routes.ts @@ -1,5 +1,5 @@ /* eslint-disable consistent-return, import/no-relative-packages */ -import { Application } from 'express-ws'; +import type { Application } from 'express-ws'; import { match } from 'ts-pattern'; import { LiveAgentPlatform } from '../../../shared/live-agent-platform.enum'; diff --git a/examples/live-agent/server/src/intercom/intercom.service.ts b/examples/live-agent/server/src/intercom/intercom.service.ts index 091544249..22e9a6a19 100644 --- a/examples/live-agent/server/src/intercom/intercom.service.ts +++ b/examples/live-agent/server/src/intercom/intercom.service.ts @@ -1,4 +1,4 @@ -/* eslint-disable no-await-in-loop, no-restricted-syntax, xss/no-mixed-html */ +/* eslint-disable no-await-in-loop */ import { Client as IntercomClient } from 'intercom-client'; import { stripHtml } from 'string-strip-html'; import { WebSocket } from 'ws'; @@ -75,7 +75,11 @@ export class IntercomService { } } - public async subscribeToConversation(conversationID: string, ws: WebSocket, handler: (event: { type: string; data: any }) => any) { + public async subscribeToConversation( + conversationID: string, + ws: WebSocket, + handler: (event: { type: string; data: any }) => any + ) { const conversation = await this.intercom.conversations.find({ id: conversationID }).catch(() => null); if (!conversation) return; diff --git a/examples/live-agent/server/src/main.ts b/examples/live-agent/server/src/main.ts index 4e33dfa14..bf56ea1ee 100644 --- a/examples/live-agent/server/src/main.ts +++ b/examples/live-agent/server/src/main.ts @@ -15,4 +15,4 @@ app.use(bodyParser.json()); intercomRoutes(app); app.listen(9099); -console.log('server is running on port 9099'); +console.info('server is running on port 9099'); diff --git a/examples/live-agent/server/tsconfig.json b/examples/live-agent/server/tsconfig.json index 04e9eb433..92b5b1035 100644 --- a/examples/live-agent/server/tsconfig.json +++ b/examples/live-agent/server/tsconfig.json @@ -5,4 +5,4 @@ "strict": true, "skipLibCheck": true } -} \ No newline at end of file +} diff --git a/examples/live-agent/src/context.tsx b/examples/live-agent/src/context.tsx index 84574c8bb..966858515 100644 --- a/examples/live-agent/src/context.tsx +++ b/examples/live-agent/src/context.tsx @@ -4,7 +4,8 @@ import { useMemo } from 'react'; import { ASSISTANT, CONFIG } from './config'; import { LiveAgent } from './traces/LiveAgent.trace'; -import { LiveAgentEvents, useLiveAgent } from './use-live-agent.hook'; +import type { LiveAgentEvents } from './use-live-agent.hook'; +import { useLiveAgent } from './use-live-agent.hook'; export const RuntimeProvider: React.FC = ({ children }) => { const emitter = useMemo(() => createNanoEvents(), []); diff --git a/examples/live-agent/src/traces/LiveAgent.trace.ts b/examples/live-agent/src/traces/LiveAgent.trace.ts index b958dadff..15d88eae0 100644 --- a/examples/live-agent/src/traces/LiveAgent.trace.ts +++ b/examples/live-agent/src/traces/LiveAgent.trace.ts @@ -1,6 +1,6 @@ -import { TraceHandler } from '@voiceflow/react-chat'; +import type { TraceHandler } from '@voiceflow/react-chat'; -import { LiveAgentPlatform } from '../../shared/live-agent-platform.enum'; +import type { LiveAgentPlatform } from '../../shared/live-agent-platform.enum'; export const LiveAgent = (handoff: (platform: LiveAgentPlatform) => void): TraceHandler => ({ canHandle: ({ type }) => (type as string) === 'talk_to_agent', diff --git a/examples/live-agent/src/use-live-agent.hook.ts b/examples/live-agent/src/use-live-agent.hook.ts index 4e050a9f9..b86981ddf 100644 --- a/examples/live-agent/src/use-live-agent.hook.ts +++ b/examples/live-agent/src/use-live-agent.hook.ts @@ -1,11 +1,12 @@ import { FetchClient } from '@voiceflow/fetch'; -import { RuntimeState, TurnType } from '@voiceflow/react-chat'; +import type { RuntimeState } from '@voiceflow/react-chat'; +import { TurnType } from '@voiceflow/react-chat'; import { serializeToText } from '@voiceflow/slate-serializer/text'; -import { Emitter } from 'nanoevents'; +import type { Emitter } from 'nanoevents'; import { useMemo } from 'react'; import { match } from 'ts-pattern'; -import { LiveAgentPlatform } from '../shared/live-agent-platform.enum'; +import type { LiveAgentPlatform } from '../shared/live-agent-platform.enum'; import { SocketEvent } from '../shared/socket-event.enum'; const SESSION_USER_ID_KEY = 'session:user_id'; @@ -66,18 +67,22 @@ export const useLiveAgent = (emitter: Emitter) => { }; const subscribeToConversation = (platform: LiveAgentPlatform, userID: string, conversationID: string) => { - socket = new WebSocket(`ws://localhost:9099/${platform}/user/${userID}/conversation/${conversationID}/socket`); + socket = new WebSocket( + `ws://localhost:9099/${platform}/user/${userID}/conversation/${conversationID}/socket` + ); socket.onmessage = (message) => { const event = JSON.parse(message.data); match(event) - .with({ type: SocketEvent.LIVE_AGENT_CONNECT }, () => addSystemTurn(`connecting you with ${event.data.agent.name}`)) + .with({ type: SocketEvent.LIVE_AGENT_CONNECT }, () => + addSystemTurn(`connecting you with ${event.data.agent.name}`) + ) .with({ type: SocketEvent.LIVE_AGENT_MESSAGE }, () => addSystemTurn(event.data.message)) .with({ type: SocketEvent.LIVE_AGENT_DISCONNECT }, () => { addSystemTurn(`${event.data.agent.name} has left the chat`); talkToRobot(); }) - .otherwise(() => console.log('unexpected event', event)); + .otherwise(() => console.error('unexpected event', event)); }; }; diff --git a/examples/live-agent/tsconfig.json b/examples/live-agent/tsconfig.json index 384bac770..7f19d575f 100644 --- a/examples/live-agent/tsconfig.json +++ b/examples/live-agent/tsconfig.json @@ -3,13 +3,11 @@ "target": "esnext", "module": "esnext", "moduleResolution": "node", - "lib": [ - "dom" - ], + "lib": ["dom"], "jsx": "react-jsx", "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true, "skipLibCheck": true } -} \ No newline at end of file +} diff --git a/lerna.json b/lerna.json index a8411aaa5..458ccbb97 100644 --- a/lerna.json +++ b/lerna.json @@ -1,9 +1,5 @@ { - "packages": [ - "packages/*", - "examples/*", - "examples/live-agent/server" - ], + "packages": ["packages/*", "examples/*", "examples/live-agent/server"], "npmClient": "yarn", "useWorkspaces": true, "version": "independent", @@ -13,4 +9,4 @@ "createRelease": "github" } } -} \ No newline at end of file +} diff --git a/package.json b/package.json index e277183b8..9acb6d52a 100644 --- a/package.json +++ b/package.json @@ -1,64 +1,85 @@ { "version": "1.0.0", - "author": "Ben Teichman, Tyler Han", - "bugs": { - "url": "https://github.com/voiceflow/react-chat/issues" - }, - "config": { - "commitizen": { - "path": "./node_modules/cz-conventional-changelog" - } - }, - "devDependencies": { - "@commitlint/cli": "17.0.3", - "@commitlint/config-conventional": "17.0.3", - "@voiceflow/commitlint-config": "2.0.0", - "@voiceflow/git-branch-check": "1.4.1", - "cz-conventional-changelog": "^3.3.0", - "depcheck": "^1.4.3", - "fixpack": "^4.0.0", - "husky": "7.0.0", - "lint-staged": ">=10", - "npm-run-all": "4.1.5", - "turbo": "1.5.5", - "typescript": "4.8.4" - }, - "engines": { - "node": ">=12" - }, - "homepage": "https://github.com/voiceflow/react-chat#readme", + "private": true, "keywords": [ "react", "voiceflow" ], - "license": "ISC", - "packageManager": "yarn@3.2.1", - "private": true, - "publishConfig": { - "access": "public" + "homepage": "https://github.com/voiceflow/react-chat#readme", + "bugs": { + "url": "https://github.com/voiceflow/react-chat/issues" }, + "license": "ISC", + "author": "Ben Teichman, Tyler Han", + "workspaces": [ + "packages/*", + "examples/*", + "examples/live-agent/server" + ], "scripts": { - "//": "Scripts to make binaries available to workspaces", - "build": "turbo run build", + "build": "turbo run build:cmd", "build:all": "yarn build", - "dev": "turbo run dev --parallel", + "clean": "turbo run clean && rimraf node_modules", + "dev": "turbo run dev --no-cache --parallel --continue", + "lint": "run-p -c lint:eslint lint:prettier", + "lint:eslint": "yarn g:eslint", + "lint:fix": "run-p -c \"g:eslint --fix\" \"g:prettier --write\"", + "lint:prettier": "yarn g:prettier --check", + "lint:report": "run-p -c \"lint:eslint --format ./node_modules/@voiceflow/eslint-config/src/formatter.js --quiet\" lint:prettier", + "test": "yarn g:run-p -c test:dependencies test:types test:unit", + "test:types": "turbo run test:types", + "test:dependencies": "turbo run test:dependencies", + "test:unit": "turbo run test:unit", + "prepare": "husky", + "// global": "Scripts to make binaries available to workspaces", + "g:depcruise": "cd $INIT_CWD && depcruise .", + "g:eslint": "cd $INIT_CWD && eslint --config $PROJECT_CWD/eslint.config.mjs", + "g:prettier": "cd $INIT_CWD && prettier --ignore-path $PROJECT_CWD/.prettierignore --log-level warn . '!**/*.{mdx,js,jsx,cjs,mjs,ts,tsx,cts,mts}'", + "g:rimraf": "cd $INIT_CWD && rimraf", "g:run-p": "cd $INIT_CWD && run-p", "g:tsc": "cd $INIT_CWD && tsc", - "lint": "turbo run lint", - "lint:fix": "turbo run lint:fix", - "lint:report": "turbo run lint:report", - "prepare": "husky install", - "setup_github_pages": "./scripts/setup_github_pages.sh", - "test:dependencies": "depcheck && turbo run test:dependencies", - "test:unit": "turbo run test:unit" + "g:tsc-alias": "cd $INIT_CWD && tsc-alias", + "g:turbo": "cd $INIT_CWD && turbo", + "g:vitest": "cd $INIT_CWD && vitest" + }, + "commitlint": { + "extends": [ + "@voiceflow/commitlint-config" + ] + }, + "lint-staged": { + "*.{mdx,js,jsx,cjs,mjs,ts,tsx,cts,mts}": "eslint --fix", + "*.{html,md,json,yml,yaml,toml,css}": "prettier --write" + }, + "prettier": "@voiceflow/prettier-config", + "devDependencies": { + "@commitlint/cli": "19.2.2", + "@voiceflow/commitlint-config": "2.3.1", + "@voiceflow/dependency-cruiser-config": "1.8.2", + "@voiceflow/eslint-config": "7.5.0", + "@voiceflow/git-branch-check": "1.4.1", + "@voiceflow/prettier-config": "1.5.1", + "@voiceflow/tsconfig": "1.7.1", + "@voiceflow/vitest-config": "1.2.2", + "dependency-cruiser": "16.3.1", + "eslint": "9.0.0", + "husky": "9.0.11", + "lint-staged": "15.2.2", + "npm-run-all": "4.1.5", + "prettier": "3.2.5", + "rimraf": "5.0.5", + "source-map-support": "0.5.21", + "tsc-alias": "1.8.8", + "turbo": "1.13.2", + "typescript": "5.4.5", + "vitest": "1.5.0" + }, + "packageManager": "yarn@3.2.1", + "engines": { + "node": "20" }, "volta": { - "node": "20.10.0", + "node": "20.12.1", "yarn": "3.2.1" - }, - "workspaces": [ - "packages/*", - "examples/*", - "examples/live-agent/server" - ] + } } diff --git a/packages/react-chat/.depcheckrc b/packages/react-chat/.depcheckrc deleted file mode 100644 index 0ca6b49eb..000000000 --- a/packages/react-chat/.depcheckrc +++ /dev/null @@ -1,36 +0,0 @@ -{ - "specials": [ - "bin", - "babel", - "eslint", - "lint-staged", - "istanbul", - "commitizen", - "husky", - "prettier", - "ttypescript" - ], - "ignores": [ - "@commitlint/*", - "@storybook/*", - "@types/*", - "@voiceflow/commitlint-config", - "@voiceflow/eslint-config", - "@voiceflow/git-branch-check", - "@voiceflow/tsconfig", - "@svgr/webpack", - "@emotion/core", - "@vitest/coverage-c8", - "storybook-dark-mode", - "eslint-import-resolver-typescript", - "eslint-plugin-mdx", - "eslint-plugin-storybook", - "babel-loader", - "fixpack", - "husky", - "lint-staged", - "slate", - "zod", - "chromatic" - ] -} diff --git a/packages/react-chat/.dependency-cruiser.mjs b/packages/react-chat/.dependency-cruiser.mjs new file mode 100644 index 000000000..0ba028753 --- /dev/null +++ b/packages/react-chat/.dependency-cruiser.mjs @@ -0,0 +1,3 @@ +import { createConfig } from '@voiceflow/dependency-cruiser-config'; + +export default createConfig({ allowTypeCycles: true }); diff --git a/packages/react-chat/.eslintignore b/packages/react-chat/.eslintignore deleted file mode 100644 index 87ed7f9fb..000000000 --- a/packages/react-chat/.eslintignore +++ /dev/null @@ -1,7 +0,0 @@ -coverage -.nyc_output -/build -/dist -/docs -/node_modules -!.storybook diff --git a/packages/react-chat/.eslintoutputrc b/packages/react-chat/.eslintoutputrc deleted file mode 100644 index a75778dcf..000000000 --- a/packages/react-chat/.eslintoutputrc +++ /dev/null @@ -1,13 +0,0 @@ -{ - "formats": [ - { - "name": "stylish", - "output": "console" - }, - { - "name": "json", - "output": "file", - "path": "sonar/report.json" - } - ] -} diff --git a/packages/react-chat/.eslintrc.js b/packages/react-chat/.eslintrc.js deleted file mode 100644 index a79798b81..000000000 --- a/packages/react-chat/.eslintrc.js +++ /dev/null @@ -1,42 +0,0 @@ -const path = require('path'); - -module.exports = { - extends: ['@voiceflow/eslint-config', '@voiceflow/eslint-config/frontend', '@voiceflow/eslint-config/typescript'], - rules: { - // off - '@typescript-eslint/no-unused-vars': 'off', - 'react/react-in-jsx-scope': 'off', - 'no-console': 'off', - }, - settings: { - 'import/resolver': { - typescript: { - project: path.resolve(__dirname, 'tsconfig.json'), - }, - }, - }, - overrides: [ - { - files: ['test/**/*', 'e2e/**/*', 'config/**/*', '.storybook/**/*', '**/*.story.tsx', '**/*.test.*', '**/*.mdx', '*.config.ts'], - extends: ['@voiceflow/eslint-config/utility'], - rules: { - // off - 'no-unused-expressions': 'off', - }, - }, - { - files: ['**/*.story.tsx'], - extends: ['plugin:storybook/recommended'], - }, - { - files: ['**/*.mdx'], - extends: ['plugin:mdx/recommended'], - rules: { - // off - 'no-unused-vars': 'off', - 'import/no-named-as-default-member': 'off', - 'react/jsx-no-undef': 'off', - }, - }, - ], -}; diff --git a/packages/react-chat/.gitignore b/packages/react-chat/.gitignore index 68c5d18f0..12b46b848 100644 --- a/packages/react-chat/.gitignore +++ b/packages/react-chat/.gitignore @@ -1,5 +1 @@ -node_modules/ /test-results/ -/playwright-report/ -/blob-report/ -/playwright/.cache/ diff --git a/packages/react-chat/.storybook/main.ts b/packages/react-chat/.storybook/main.ts index 2cc6cd5fe..ab4e09b40 100644 --- a/packages/react-chat/.storybook/main.ts +++ b/packages/react-chat/.storybook/main.ts @@ -1,5 +1,5 @@ /* eslint-disable sonarjs/prefer-single-boolean-return */ -import { StorybookConfig } from '@storybook/react-vite'; +import type { StorybookConfig } from '@storybook/react-vite'; import { mergeConfig } from 'vite'; import svgr from 'vite-plugin-svgr'; @@ -7,7 +7,12 @@ import { createPlugins } from '../vite.config'; const config: StorybookConfig = { stories: ['../src/**/*.story.@(js|jsx|ts|tsx)'], - addons: ['@storybook/addon-links', '@storybook/addon-essentials', '@storybook/addon-interactions', 'storybook-dark-mode'], + addons: [ + '@storybook/addon-links', + '@storybook/addon-essentials', + '@storybook/addon-interactions', + 'storybook-dark-mode', + ], framework: '@storybook/react-vite', core: { builder: '@storybook/builder-vite', diff --git a/packages/react-chat/.storybook/preview.tsx b/packages/react-chat/.storybook/preview.tsx index a184401c5..6f58331c1 100644 --- a/packages/react-chat/.storybook/preview.tsx +++ b/packages/react-chat/.storybook/preview.tsx @@ -1,4 +1,4 @@ -import { Preview } from '@storybook/react'; +import type { Preview } from '@storybook/react'; import React from 'react'; import { RuntimeProvider } from '../src/contexts/RuntimeContext/index'; diff --git a/packages/react-chat/README.md b/packages/react-chat/README.md index e8747d51a..9f6a623c9 100644 --- a/packages/react-chat/README.md +++ b/packages/react-chat/README.md @@ -11,7 +11,16 @@ yarn add @voiceflow/react-chat For a more complete example see our [demo-react-chat](https://github.com/voiceflow/demo-react-chat) repository. ```tsx -import { Chat, ChatWindow, Launcher, SessionStatus, SystemResponse, TurnType, UserResponse, useRuntime } from '@voiceflow/react-chat'; +import { + Chat, + ChatWindow, + Launcher, + SessionStatus, + SystemResponse, + TurnType, + UserResponse, + useRuntime, +} from '@voiceflow/react-chat'; import { useState } from 'react'; import { match } from 'ts-pattern'; @@ -83,7 +92,12 @@ const MyChat: React.FC = () => { match(turn) .with({ type: TurnType.USER }, ({ id, type: _, ...props }) => ) .with({ type: TurnType.SYSTEM }, ({ id, type: _, ...props }) => ( - + )) .exhaustive() )} diff --git a/packages/react-chat/chromatic.config.json b/packages/react-chat/chromatic.config.json index 13345490b..e7b7ba637 100644 --- a/packages/react-chat/chromatic.config.json +++ b/packages/react-chat/chromatic.config.json @@ -1,3 +1,3 @@ { - "outputDir": "./storybook-static" -} \ No newline at end of file + "outputDir": "./storybook-static" +} diff --git a/packages/react-chat/config/test/setup.ts b/packages/react-chat/config/test/setup.ts index 02bc65712..3036c6331 100644 --- a/packages/react-chat/config/test/setup.ts +++ b/packages/react-chat/config/test/setup.ts @@ -1,4 +1,4 @@ -import '@testing-library/jest-dom'; +import '@testing-library/jest-dom/vitest'; import { vi } from 'vitest'; diff --git a/packages/react-chat/e2e/embedded.html b/packages/react-chat/e2e/embedded.html index 2d9302e48..b744c6088 100644 --- a/packages/react-chat/e2e/embedded.html +++ b/packages/react-chat/e2e/embedded.html @@ -1,41 +1,42 @@ - + + + Embedded Mode + - - - -
- - - + + + + +
- \ No newline at end of file + + + diff --git a/packages/react-chat/e2e/extensions.html b/packages/react-chat/e2e/extensions.html index d3f2815be..1e5710ec1 100644 --- a/packages/react-chat/e2e/extensions.html +++ b/packages/react-chat/e2e/extensions.html @@ -1,125 +1,122 @@ - + + + Embedded Mode + - + font-family: 'Open Sans', sans-serif; + font-size: 20px; + font-weight: 400; + } + + - - -
-
- + + +
+ - - + const confirmation = document.createElement('em'); + confirmation.innerText = `submitted ✅`; - \ No newline at end of file + form.appendChild(confirmation); + }); + }, + }, + ], + }, + }); + }; + v.src = '../dist/bundle.mjs'; + v.type = 'text/javascript'; + s.parentNode.insertBefore(v, s); + })(document, 'script'); + + + diff --git a/packages/react-chat/e2e/extensions.spec.ts b/packages/react-chat/e2e/extensions.spec.ts index f15704762..ee3a9a634 100644 --- a/packages/react-chat/e2e/extensions.spec.ts +++ b/packages/react-chat/e2e/extensions.spec.ts @@ -1,4 +1,3 @@ -/* eslint-disable sonarjs/no-duplicate-string */ import { expect, test } from '@playwright/test'; import { slateMessage } from './utils'; @@ -6,7 +5,11 @@ import { slateMessage } from './utils'; const RUNTIME_URL = 'https://general-runtime.voiceflow.com/public/projectID/state/user/*/interact'; test('trigger effect extension on incoming trace', async ({ page }) => { - const systemMessages = ['Welcome to the pizza palace!', 'What kind of pizza do you want?', 'One cheese pizza coming right up']; + const systemMessages = [ + 'Welcome to the pizza palace!', + 'What kind of pizza do you want?', + 'One cheese pizza coming right up', + ]; const userMessages = ['I want to order a pizza', 'Cheese please']; const traceType = 'update_order_status'; let count = 0; @@ -109,5 +112,7 @@ test('render response extension from incoming trace', async ({ page }) => { await extensionMessage.locator('[name="name"]').fill('Alex'); await extensionMessage.locator('[name="hair"][id="curly"]').click(); await extensionMessage.getByRole('button').click(); - await page.locator('.vfrc-message--extension-onboarding_form', { hasText: `submitted ✅` }).waitFor({ state: 'visible' }); + await page + .locator('.vfrc-message--extension-onboarding_form', { hasText: 'submitted ✅' }) + .waitFor({ state: 'visible' }); }); diff --git a/packages/react-chat/e2e/overlay.html b/packages/react-chat/e2e/overlay.html index e713a0791..e8bbeb3c9 100644 --- a/packages/react-chat/e2e/overlay.html +++ b/packages/react-chat/e2e/overlay.html @@ -1,28 +1,29 @@ - + - - - Overlay mode - - - - - - + + - \ No newline at end of file + + + + diff --git a/packages/react-chat/e2e/proactive.html b/packages/react-chat/e2e/proactive.html index 946cc1781..60cd68a72 100644 --- a/packages/react-chat/e2e/proactive.html +++ b/packages/react-chat/e2e/proactive.html @@ -1,29 +1,30 @@ - + - - - Overlay mode - proactive messages - - - - - - + + - \ No newline at end of file + + + + diff --git a/packages/react-chat/e2e/proactive.spec.ts b/packages/react-chat/e2e/proactive.spec.ts index e01401236..bd9449126 100644 --- a/packages/react-chat/e2e/proactive.spec.ts +++ b/packages/react-chat/e2e/proactive.spec.ts @@ -1,5 +1,5 @@ import { test } from '@playwright/test'; -import { Trace } from '@voiceflow/base-types'; +import type { Trace } from '@voiceflow/base-types'; test('renders launcher and widget appears on click', async ({ page }) => { const message = 'Welcome to our chat'; diff --git a/packages/react-chat/examples/index.html b/packages/react-chat/examples/index.html index b15484018..7df86a8c9 100644 --- a/packages/react-chat/examples/index.html +++ b/packages/react-chat/examples/index.html @@ -1,5 +1,5 @@ - + Example Page diff --git a/packages/react-chat/package.json b/packages/react-chat/package.json index 579fadbde..40bb669c4 100644 --- a/packages/react-chat/package.json +++ b/packages/react-chat/package.json @@ -1,128 +1,116 @@ { "name": "@voiceflow/react-chat", - "description": "voiceflow chat ui kit", "version": "1.57.0", - "author": "Ben Teichman, Tyler Han", + "description": "voiceflow chat ui kit", + "keywords": [ + "chat widget", + "iframe", + "voiceflow" + ], + "homepage": "https://github.com/voiceflow/react-chat#readme", "bugs": { "url": "https://github.com/voiceflow/react-chat/issues" }, + "license": "MIT", + "author": "Ben Teichman, Tyler Han", + "main": "build/index.es.js", + "types": "build/src/package.entry.d.ts", + "files": [ + "build", + "dist" + ], + "scripts": { + "build": "yarn g:turbo run build:cmd --filter=@voiceflow/react-chat...", + "build:bundle": "NODE_ENV=production vite build", + "build:cmd": "yarn g:run-p build:package build:bundle", + "build:package": "NODE_ENV=production vite --config vite.package.config.ts build && yarn g:tsc-alias -p tsconfig.build.json", + "build:storybook": "storybook build -o docs", + "clean": "yarn g:rimraf build dist", + "dev": "storybook dev -p 6006", + "lint": "yarn g:run-p -c lint:eslint lint:prettier", + "lint:eslint": "yarn g:eslint", + "lint:fix": "yarn g:run-p -c \"lint:eslint --fix\" \"lint:prettier --write\"", + "lint:prettier": "yarn g:prettier --check", + "start:e2e": "http-server -o e2e", + "tdd": "yarn g:vitest", + "test": "yarn g:run-p -c test:dependencies test:types test:unit", + "test:dependencies": "yarn g:depcruise", + "test:e2e": "yarn playwright test", + "test:types": "yarn g:tsc --noEmit", + "test:unit": "yarn g:vitest run --coverage" + }, "dependencies": { - "@storybook/react": "^8.0.2", "@voiceflow/base-types": "2.97.3", "@voiceflow/dtos": "1.10.0", "@voiceflow/sdk-runtime": "1.7.0", "@voiceflow/slate-serializer": "1.5.5", "@voiceflow/stitches-react": "2.3.1", "@voiceflow/voiceflow-types": "3.26.21", - "bowser": "^2.11.0", + "bowser": "2.11.0", "chroma-js": "2.4.2", "clsx": "1.2.1", "csstype": "3.1.0", - "cuid": "^2.1.8", - "dayjs": "^1.11.5", + "cuid": "2.1.8", + "dayjs": "1.11.5", "react": "18.2.0", "react-dom": "18.2.0", "react-markdown": "9.0.0", "react-textarea-autosize": "8.5.3", "rehype-raw": "7.0.0", - "rehype-sanitize": "^6.0.0", + "rehype-sanitize": "6.0.0", "remark-gfm": "4.0.0", - "remeda": "^1.0.1", - "slate": "^0.94.1", + "remeda": "1.0.1", + "slate": "0.94.1", "ts-pattern": "4.3.0", "type-fest": "2.18.1", "zod": "3.22.4" }, "devDependencies": { - "@babel/core": "^7.18.10", - "@babel/preset-env": "^7.24.1", - "@babel/preset-react": "^7.24.1", - "@babel/preset-typescript": "^7.24.1", + "@babel/core": "7.18.10", + "@babel/preset-env": "7.24.1", + "@babel/preset-react": "7.24.1", + "@babel/preset-typescript": "7.24.1", "@emotion/core": "10.1.1", - "@playwright/test": "^1.41.2", + "@playwright/test": "1.43.1", "@storybook/addon-actions": "8.0.2", "@storybook/addon-essentials": "8.0.2", "@storybook/addon-interactions": "8.0.2", "@storybook/addon-links": "8.0.2", "@storybook/builder-vite": "8.0.2", - "@storybook/eslint-config-storybook": "^3.1.2", + "@storybook/eslint-config-storybook": "3.1.2", + "@storybook/react": "8.0.2", "@storybook/react-vite": "8.0.2", - "@storybook/testing-library": "^0.0.13", - "@testing-library/jest-dom": "^5.16.5", - "@testing-library/react": "12.1.4", - "@types/chroma-js": "^2.1.4", - "@types/node": "^20.11.19", + "@storybook/testing-library": "0.0.13", + "@testing-library/jest-dom": "6.4.2", + "@testing-library/react": "15.0.2", + "@types/chroma-js": "2.1.4", + "@types/node": "20.12.7", "@types/react": "18.2.8", "@types/react-dom": "18.2.4", - "@vitejs/plugin-react": "^2.0.1", - "@vitest/coverage-c8": "^0.23.1", - "@voiceflow/eslint-config": "7.1.0", - "@voiceflow/prettier-config": "1.3.0", - "@voiceflow/tsconfig": "1.4.8", + "@vitejs/plugin-react": "4.2.1", + "@voiceflow/test-common": "1.10.3", "chromatic": "11.2.0", - "depcheck": "1.4.3", - "eslint": "8.42.0", - "eslint-output": "3.0.1", "eslint-plugin-mdx": "3.1.5", "eslint-plugin-storybook": "0.8.0", - "fixpack": "^4.0.0", - "happy-dom": "^6.0.4", + "happy-dom": "14.7.1", "http-server": "14.1.1", - "husky": "^8.0.0", - "lint-staged": "13.0.3", - "prettier": "2.8.8", "react": "18.2.0", "react-dom": "18.2.0", - "rimraf": "3.0.2", "storybook": "8.0.2", - "storybook-dark-mode": "^1.1.0", - "tsc-alias": "1.8.6", - "vite": "3.2.2", - "vite-plugin-dts": "^1.6.6", - "vite-plugin-fonts": "^0.6.0", - "vite-plugin-html": "^3.2.0", - "vite-plugin-svgr": "4.1.0", - "vite-tsconfig-paths": "^3.5.0", - "vitest": "0.23.1" + "storybook-dark-mode": "1.1.0", + "tsc-alias": "1.8.8", + "vite": "5.2.9", + "vite-plugin-dts": "3.8.3", + "vite-plugin-fonts": "0.7.0", + "vite-plugin-html": "3.2.2", + "vite-plugin-svgr": "4.2.0", + "vite-tsconfig-paths": "4.3.2" }, - "files": [ - "build/", - "dist/" - ], - "homepage": "https://github.com/voiceflow/react-chat#readme", - "keywords": [ - "chat widget", - "iframe", - "voiceflow" - ], - "license": "MIT", - "main": "build/index.es.js", "peerDependencies": { "react": "^18", "react-dom": "^18" }, - "prettier": "@voiceflow/prettier-config", - "scripts": { - "build": "yarn clean && yarn g:run-p \"types\" \"build:package\" \"build:bundle\"", - "build:bundle": "NODE_ENV=production vite build", - "build:docs": "NODE_OPTIONS=--openssl-legacy-provider STORYBOOK_BASE_HREF=react-chat storybook build -o docs", - "build-storybook": "storybook build -o docs", - "build:package": "NODE_ENV=production vite --config vite.package.config.ts build && tsc-alias -p tsconfig.build.json", - "clean": "rimraf build dist", - "dev": "NODE_ENV=development vite", - "eslint-output": "eslint-output", - "lint": "eslint '**/*.{js,ts,tsx,mdx}'", - "lint:output": "yarn run eslint-output --quiet \"**/*.{js,ts,tsx,mdx}\"", - "lint:quiet": "yarn lint --quiet", - "lint:report": "yarn lint:output", - "prepublishOnly": "yarn build", - "start:e2e": "http-server -o e2e", - "storybook": "storybook dev -p 6006", - "test": "yarn test:run", - "test:dependencies": "depcheck", - "test:e2e": "yarn playwright test", - "test:unit": "NODE_ENV=test vitest run --coverage", - "types": "yarn g:tsc --project tsconfig.build.json --noEmit" - }, - "types": "build/src/package.entry.d.ts" + "volta": { + "extends": "../../package.json" + } } diff --git a/packages/react-chat/playwright.config.ts b/packages/react-chat/playwright.config.ts index e3ce7de34..61470cf0d 100644 --- a/packages/react-chat/playwright.config.ts +++ b/packages/react-chat/playwright.config.ts @@ -8,12 +8,14 @@ export default defineConfig({ forbidOnly: !!process.env.CI, retries: 0, workers: process.env.CI ? 1 : cpus().length - 1, - reporter: 'html', + reporter: [['junit', { outputFile: 'e2e.report.xml' }]], timeout: 5000, use: { baseURL: 'http://127.0.0.1:8080/e2e/', trace: 'retain-on-failure', + screenshot: 'only-on-failure', + video: 'on', }, projects: [ diff --git a/packages/react-chat/sonar-project.properties b/packages/react-chat/sonar-project.properties new file mode 100644 index 000000000..c61c72df6 --- /dev/null +++ b/packages/react-chat/sonar-project.properties @@ -0,0 +1,8 @@ +sonar.projectName=react-chat-react-chat +sonar.sources=src/ +sonar.tests=src/ +sonar.exclusions=src/**/*.test.*,src/**/*.story.tsx +sonar.test.inclusions=src/**/*.test.* +sonar.cpd.exclusions=src/**/*.test.*,src/**/*.story.tsx +sonar.typescript.tsconfigPath=tsconfig.json +sonar.javascript.lcov.reportPaths=sonar/coverage/lcov.info diff --git a/packages/react-chat/src/common/index.ts b/packages/react-chat/src/common/index.ts index 6d5a6ef49..04bca77e0 100644 --- a/packages/react-chat/src/common/index.ts +++ b/packages/react-chat/src/common/index.ts @@ -1,2 +1 @@ -export * from './types'; export * from './utils'; diff --git a/packages/react-chat/src/common/utils.ts b/packages/react-chat/src/common/utils.ts index 8d981a56a..f6fb563aa 100644 --- a/packages/react-chat/src/common/utils.ts +++ b/packages/react-chat/src/common/utils.ts @@ -1,6 +1 @@ export { isObject } from 'remeda'; - -export const isEnumValue = (value: any, enumObject: T): value is T[keyof T] => - typeof value === 'string' && Object.values(enumObject).includes(value); - -export { default as cuid } from 'cuid'; diff --git a/packages/react-chat/src/components/AssistantInfo/AssistantInfo.story.tsx b/packages/react-chat/src/components/AssistantInfo/AssistantInfo.story.tsx index b2f1c4885..88da45461 100644 --- a/packages/react-chat/src/components/AssistantInfo/AssistantInfo.story.tsx +++ b/packages/react-chat/src/components/AssistantInfo/AssistantInfo.story.tsx @@ -1,9 +1,10 @@ -import { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react'; import Chat from '@/components/Chat'; import { VF_ICON } from '@/fixtures'; -import AssistantInfo, { AssistantInfoProps } from '.'; +import type { AssistantInfoProps } from '.'; +import AssistantInfo from '.'; type Story = StoryObj; diff --git a/packages/react-chat/src/components/Avatar/Avatar.story.tsx b/packages/react-chat/src/components/Avatar/Avatar.story.tsx index c0b9c6844..b4a789c76 100644 --- a/packages/react-chat/src/components/Avatar/Avatar.story.tsx +++ b/packages/react-chat/src/components/Avatar/Avatar.story.tsx @@ -1,4 +1,4 @@ -import { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react'; import { VF_ICON } from '@/fixtures'; diff --git a/packages/react-chat/src/components/Avatar/index.tsx b/packages/react-chat/src/components/Avatar/index.tsx index b4d5e60dc..7c12b740a 100644 --- a/packages/react-chat/src/components/Avatar/index.tsx +++ b/packages/react-chat/src/components/Avatar/index.tsx @@ -1,4 +1,4 @@ -import { VariantProp } from '@/types'; +import type { VariantProp } from '@/types'; import { AvatarContainer } from './styled'; diff --git a/packages/react-chat/src/components/Bubble/Bubble.story.tsx b/packages/react-chat/src/components/Bubble/Bubble.story.tsx index 94bc4e350..8c30b76df 100644 --- a/packages/react-chat/src/components/Bubble/Bubble.story.tsx +++ b/packages/react-chat/src/components/Bubble/Bubble.story.tsx @@ -1,4 +1,4 @@ -import { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react'; import * as SVGs from '@/assets/svg'; diff --git a/packages/react-chat/src/components/Bubble/index.tsx b/packages/react-chat/src/components/Bubble/index.tsx index b2ff036de..8fc5aa946 100644 --- a/packages/react-chat/src/components/Bubble/index.tsx +++ b/packages/react-chat/src/components/Bubble/index.tsx @@ -1,5 +1,6 @@ -import Icon, { IconProps } from '@/components/Icon'; -import { VariantProp } from '@/types'; +import type { IconProps } from '@/components/Icon'; +import Icon from '@/components/Icon'; +import type { VariantProp } from '@/types'; import { Container } from './styled'; diff --git a/packages/react-chat/src/components/Button/Button.story.tsx b/packages/react-chat/src/components/Button/Button.story.tsx index e6d37123d..9f0ec741b 100644 --- a/packages/react-chat/src/components/Button/Button.story.tsx +++ b/packages/react-chat/src/components/Button/Button.story.tsx @@ -1,4 +1,4 @@ -import { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react'; import Button from '.'; diff --git a/packages/react-chat/src/components/Button/Button.test.tsx b/packages/react-chat/src/components/Button/Button.test.tsx index e1ba74323..b28cb0a9c 100644 --- a/packages/react-chat/src/components/Button/Button.test.tsx +++ b/packages/react-chat/src/components/Button/Button.test.tsx @@ -1,4 +1,4 @@ -import { render } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import { describe, expect, it } from 'vitest'; import Button from '.'; @@ -7,9 +7,9 @@ describe('Button', () => { it('should render a button with a label', async () => { const label = 'Button Label'; - const { getByText, getByRole } = render(); + render(); - expect(getByText(label)).toBeInTheDocument(); - expect(getByRole('button')).toBeInTheDocument(); + expect(screen.getByText(label)).toBeInTheDocument(); + expect(screen.getByRole('button')).toBeInTheDocument(); }); }); diff --git a/packages/react-chat/src/components/Card/Card.story.tsx b/packages/react-chat/src/components/Card/Card.story.tsx index 5febece94..c2c69374c 100644 --- a/packages/react-chat/src/components/Card/Card.story.tsx +++ b/packages/react-chat/src/components/Card/Card.story.tsx @@ -1,4 +1,4 @@ -import { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react'; import { MOCK_IMAGE } from '@/fixtures'; @@ -12,7 +12,8 @@ const meta: Meta = { args: { title: 'Card Header', image: '', - description: 'Lorem ipsum dolor sit amet consectetur, adipisicing elit. Culpa et aliquam sunt necessitatibus molestiae amet ipsum ut.', + description: + 'Lorem ipsum dolor sit amet consectetur, adipisicing elit. Culpa et aliquam sunt necessitatibus molestiae amet ipsum ut.', actions: [], }, }; diff --git a/packages/react-chat/src/components/Card/index.tsx b/packages/react-chat/src/components/Card/index.tsx index eea4773ee..b81e742a4 100644 --- a/packages/react-chat/src/components/Card/index.tsx +++ b/packages/react-chat/src/components/Card/index.tsx @@ -5,7 +5,7 @@ import Image from '@/components/Image'; import { RuntimeStateAPIContext } from '@/contexts'; import { Container, Content, Description, Header, Link } from './styled'; -import { CardProps } from './types'; +import type { CardProps } from './types'; import { isValidHttpUrl } from './utils'; export type { CardProps } from './types'; diff --git a/packages/react-chat/src/components/Card/types.ts b/packages/react-chat/src/components/Card/types.ts index 54f695b56..ee459b381 100644 --- a/packages/react-chat/src/components/Card/types.ts +++ b/packages/react-chat/src/components/Card/types.ts @@ -1,4 +1,4 @@ -import type { RuntimeAction } from '@/common'; +import type { RuntimeAction } from '@voiceflow/sdk-runtime'; import type { Link } from './styled'; diff --git a/packages/react-chat/src/components/Carousel/Carousel.story.tsx b/packages/react-chat/src/components/Carousel/Carousel.story.tsx index f10c65483..3cf84f272 100644 --- a/packages/react-chat/src/components/Carousel/Carousel.story.tsx +++ b/packages/react-chat/src/components/Carousel/Carousel.story.tsx @@ -1,4 +1,4 @@ -import { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react'; import { useRef } from 'react'; import Avatar from '@/components/Avatar'; @@ -33,7 +33,8 @@ const MULTIPLE_CARDS = [ FIRST_CARD, { title: 'Second Card', - description: 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Exercitationem voluptas perspiciatis est quis dolores!', + description: + 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Exercitationem voluptas perspiciatis est quis dolores!', image: IMAGE, }, { diff --git a/packages/react-chat/src/components/Carousel/CarouselButton.tsx b/packages/react-chat/src/components/Carousel/CarouselButton.tsx index 3cb0b136a..dce7e4a96 100644 --- a/packages/react-chat/src/components/Carousel/CarouselButton.tsx +++ b/packages/react-chat/src/components/Carousel/CarouselButton.tsx @@ -1,4 +1,5 @@ -import { forwardRef, MouseEventHandler } from 'react'; +import type { MouseEventHandler } from 'react'; +import { forwardRef } from 'react'; import Icon from '@/components/Icon'; @@ -29,18 +30,20 @@ export interface CarouselButtonProps { /** * A button used to scroll to the previous or next Card in a Carousel. */ -const CarouselButton = forwardRef(({ onClick, alignment, visible, containerEl }, ref) => ( - - - -)); +const CarouselButton = forwardRef( + ({ onClick, alignment, visible, containerEl }, ref) => ( + + + + ) +); export default CarouselButton; diff --git a/packages/react-chat/src/components/Carousel/hooks.ts b/packages/react-chat/src/components/Carousel/hooks.ts index 4b82a302c..0b1410dc1 100644 --- a/packages/react-chat/src/components/Carousel/hooks.ts +++ b/packages/react-chat/src/components/Carousel/hooks.ts @@ -1,6 +1,7 @@ -import { RefObject, useEffect, useRef, useState } from 'react'; +import type { RefObject } from 'react'; +import { useEffect, useRef, useState } from 'react'; -import { CardProps } from '../Card'; +import type { CardProps } from '../Card'; import { CARD_WITH_GUTTER_WIDTH, NEXT_CONTROL_BOUNDARY, PREVIOUS_CONTROL_BOUNDARY } from './constants'; import { CAROUSEL_GUTTER_WIDTH } from './styled'; diff --git a/packages/react-chat/src/components/Carousel/index.tsx b/packages/react-chat/src/components/Carousel/index.tsx index a2060109f..2ece7ea07 100644 --- a/packages/react-chat/src/components/Carousel/index.tsx +++ b/packages/react-chat/src/components/Carousel/index.tsx @@ -1,7 +1,8 @@ -import { RefObject } from 'react'; +import type { RefObject } from 'react'; import { createPortal } from 'react-dom'; -import Card, { CardProps } from '@/components/Card'; +import type { CardProps } from '@/components/Card'; +import Card from '@/components/Card'; import CarouselButton from './CarouselButton'; import { CARD_WITH_GUTTER_WIDTH } from './constants'; @@ -26,7 +27,11 @@ export interface CarouselProps { } const Carousel: React.FC = ({ cards, containerRef, controlsRef }) => { - const { previousButtonRef, nextButtonRef, showPreviousButton, showNextButton } = useScrollObserver(containerRef, controlsRef, cards); + const { previousButtonRef, nextButtonRef, showPreviousButton, showNextButton } = useScrollObserver( + containerRef, + controlsRef, + cards + ); const containerEl = containerRef?.current; const controlsEl = controlsRef?.current; const showControls = containerEl && controlsEl; @@ -51,7 +56,13 @@ const Carousel: React.FC = ({ cards, containerRef, controlsRef }) containerEl={containerEl} onClick={scrollToPrevious} /> - + , controlsEl )} diff --git a/packages/react-chat/src/components/Carousel/styled.ts b/packages/react-chat/src/components/Carousel/styled.ts index c59dc78ed..fd219f589 100644 --- a/packages/react-chat/src/components/Carousel/styled.ts +++ b/packages/react-chat/src/components/Carousel/styled.ts @@ -34,11 +34,11 @@ export const ButtonContainer = styled(tag('span', 'button'), { trans: ['color'], }, - [`&:hover`]: { + '&:hover': { boxShadow: '0 1px 4px 1px $shadow4, 0 0 0 1px $shadow4, 0 2px 4px -3px $shadow12, 0 5px 8px -8px $shadow12', }, - [`&:active`]: { + '&:active': { boxShadow: '0 1px 4px 1px $shadow8, 0 0 0 1px $shadow4, 0 2px 4px -3px $shadow12, 0 5px 8px -8px $shadow12', }, diff --git a/packages/react-chat/src/components/Chat/Chat.story.tsx b/packages/react-chat/src/components/Chat/Chat.story.tsx index 6677998d1..73e3b4287 100644 --- a/packages/react-chat/src/components/Chat/Chat.story.tsx +++ b/packages/react-chat/src/components/Chat/Chat.story.tsx @@ -1,7 +1,9 @@ -import { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from '@storybook/react'; -import SystemResponse, { SystemResponseProps } from '@/components/SystemResponse'; -import UserResponse, { UserResponseProps } from '@/components/UserResponse'; +import type { SystemResponseProps } from '@/components/SystemResponse'; +import SystemResponse from '@/components/SystemResponse'; +import type { UserResponseProps } from '@/components/UserResponse'; +import UserResponse from '@/components/UserResponse'; import { MOCK_IMAGE, VF_ICON } from '@/fixtures'; import Chat from '.'; @@ -56,7 +58,8 @@ export const Exhaustive: Story = { { type: 'card', title: 'Card Message', - description: 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Exercitationem voluptas perspiciatis est quis dolores!', + description: + 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Exercitationem voluptas perspiciatis est quis dolores!', image: MOCK_IMAGE, }, ]} diff --git a/packages/react-chat/src/components/Chat/hooks.ts b/packages/react-chat/src/components/Chat/hooks.ts index 202758704..ed5816df8 100644 --- a/packages/react-chat/src/components/Chat/hooks.ts +++ b/packages/react-chat/src/components/Chat/hooks.ts @@ -2,7 +2,7 @@ import dayjs from 'dayjs'; import relativeTime from 'dayjs/plugin/relativeTime'; import { useMemo } from 'react'; -import { Nullish } from '@/types'; +import type { Nullish } from '@/types'; dayjs.extend(relativeTime); diff --git a/packages/react-chat/src/components/Chat/index.tsx b/packages/react-chat/src/components/Chat/index.tsx index b9cd1e986..4916bcb76 100644 --- a/packages/react-chat/src/components/Chat/index.tsx +++ b/packages/react-chat/src/components/Chat/index.tsx @@ -1,13 +1,16 @@ import React, { memo, useContext, useMemo, useRef, useState } from 'react'; -import AssistantInfo, { AssistantInfoProps } from '@/components/AssistantInfo'; -import Footer, { FooterProps } from '@/components/Footer'; -import Header, { HeaderActionProps, HeaderProps } from '@/components/Header'; +import type { AssistantInfoProps } from '@/components/AssistantInfo'; +import AssistantInfo from '@/components/AssistantInfo'; +import type { FooterProps } from '@/components/Footer'; +import Footer from '@/components/Footer'; +import type { HeaderActionProps, HeaderProps } from '@/components/Header'; +import Header from '@/components/Header'; import Loader from '@/components/Loader'; import Prompt from '@/components/Prompt'; import { AutoScrollProvider, RuntimeStateAPIContext, RuntimeStateContext } from '@/contexts'; import { RenderMode } from '@/dtos/RenderOptions.dto'; -import { Nullish } from '@/types'; +import type { Nullish } from '@/types'; import { chain } from '@/utils/functional'; import { useTimestamp } from './hooks'; @@ -107,9 +110,18 @@ const Chat: React.FC = ({ {hasEnded && !!state.session.turns.length && The chat has ended} -