diff --git a/README.md b/README.md
index e0b13ab9..d6cae839 100644
--- a/README.md
+++ b/README.md
@@ -10,11 +10,7 @@
- [Platforms Supported](#platforms-supported)
- [Requirements](#requirements)
- [Running Locally](#running-locally)
- - [Config](#config)
- - [Running the project](#running-the-project)
- - [Installing dependencies](#installing-dependencies)
- - [Dev mode](#dev-mode)
- - [Production mode](#production-mode)
+- [Testing on Multiple Devices](#testing-on-multiple-devices)
- [Deployment to Vonage Cloud Runtime](#deployment-to-vonage-cloud-runtime)
- [Testing](#testing)
- [Integration Tests](#integration-tests)
@@ -114,49 +110,112 @@ The Vonage Video API Reference App for React is currently supported on the lates
## Running Locally
-### Config
+- **Ensure You Have a Vonage Account**
- In project directory, create the environment variables for the project.
+ You can create one at the [Vonage API Dashboard](https://dashboard.vonage.com/applications).
-```console
-cp backend/.env.example backend/.env
-```
-[Click here](backend/.env.example) to learn more about config variables used in the backend.
+- **Create an Application in the Dashboard**
-Add your Vonage Video API credentials to the newly created .env file.
+ Once logged in, navigate to the [Applications page](https://dashboard.vonage.com/applications) via the main dashboard menu:
-```console
-cp frontend/.env.example frontend/.env
-```
-[Click here](frontend/.env.example) to learn more about config variables used in the frontend.
+
+ Applications dashboard view
+
+
-### Running the project
+ If you don’t already have an application, create a new one:
-#### Installing dependencies
+
+ Create new app
+
+
-```console
-yarn
-```
-This command installs all appropriate dependencies for the project. If you would like more information on the packages we use, please refer to the [Dependencies](./docs/DEPENDENCIES.md) document.
+ During the setup process, make sure to:
-#### Dev mode
+ - Provide a name for your application.
+ - Generate and download the public and private keys.
+ - Enable **Video** capabilities.
-```console
-yarn dev
-```
+ Refer to the following image for visual guidance:
-This command builds and watches both the backend server (:3345) and frontend vite dev server (:5173)
-You should now see the app running at [http://localhost:5173/](http://localhost:5173/)
+
+ Configuring a new app
+
+
+
-#### Production mode
+- **Environment Variables**
-This command builds a production bundle of the app frontend and `cp`s it to the backend to be served by the express server.
+ In the root project directory, create the environment files by running:
-```console
-yarn start
-```
+ ``` bash
+ cp backend/.env.example backend/.env && cp frontend/.env.example frontend/.env
+ ```
+
+ Then, open **backend/.env** and fill in the required configuration:
+
+ - **VONAGE_APP_ID** – This is the ID of your Vonage application. You can find it on the [Applications page](https://dashboard.vonage.com/applications).
+ - **VONAGE_PRIVATE_KEY** – If you've already generated a private key, use that. Otherwise, use the key you downloaded when creating the app.
+
+
+
+- **Install Dependencies:**
+
+ ``` bash
+ yarn
+ ```
+
+ This command installs all appropriate dependencies for the project. If you would like more information on the packages we use, please refer to the [Dependencies](./docs/DEPENDENCIES.md) document.
+
+
+
+- **Start in Development Mode**
+
+ ``` bash
+ yarn dev
+ ```
+
+ This starts both the backend server (port **3345**) and the frontend Vite dev server (port **5173**). You can now access the app at [http://localhost:5173](http://localhost:5173).
+
+## Testing on Multiple Devices
+
+To test the video API across multiple devices on your local network, you can use **ngrok** to expose your frontend publicly.
+
+1. Create an account at [ngrok](https://dashboard.ngrok.com/signup) if you haven’t already.
+
+2. Follow the [Setup and Installation instructions](https://dashboard.ngrok.com/get-started/setup/) for your operating system to install and configure ngrok.
+
+3. Create a secure tunnel to your frontend using:
+
+ ``` bash
+ yarn forward:frontend
+ ```
+
+ This command creates a publicly accessible HTTPS URL for your frontend. It will appear in your terminal, similar to the image below:
+
+
+ ngrok output example
+
+
+
+
+
+4. Copy the domain from the output and update your **frontend/.env** file:
+
+ ``` ini
+ # example
+ VITE_TUNNEL_DOMAIN=GENERIC_DOMAIN
+ ```
+
+ **Note:** ngrok assigns a temporary domain. You’ll need to update your environment variable each time the domain changes.
+
+
+
+5. Open the provided **Forwarding** URL in your browser. This exposes your Vite app publicly. However, keep in mind that the backend server is still local, so the devices accessing the app must be on the same local network.
+
+
-The app and API are both served on [http://localhost:3345/](http://localhost:3345/)
+Enjoy testing!
## Deployment to Vonage Cloud Runtime
diff --git a/backend/package.json b/backend/package.json
index 2de10905..f90c37bd 100644
--- a/backend/package.json
+++ b/backend/package.json
@@ -5,8 +5,9 @@
"main": "index.js",
"type": "module",
"scripts": {
- "dev": "tsx watch --ignore ./tests/**/*.test.ts index.ts",
+ "dev": "tsx watch index.ts",
"start": "node --import tsx index.ts",
+ "debug": "node --inspect --watch --import tsx index.ts",
"test": "NODE_OPTIONS=\"--experimental-vm-modules\" jest --maxWorkers=1 --coverage",
"test:watch": "yarn test --watch",
"ts-check": "tsc -p tsconfig.json"
diff --git a/docs/assets/readme/1-dashboard-applications.png b/docs/assets/readme/1-dashboard-applications.png
new file mode 100644
index 00000000..bed76591
Binary files /dev/null and b/docs/assets/readme/1-dashboard-applications.png differ
diff --git a/docs/assets/readme/2-create-app.png b/docs/assets/readme/2-create-app.png
new file mode 100644
index 00000000..7710d8cc
Binary files /dev/null and b/docs/assets/readme/2-create-app.png differ
diff --git a/docs/assets/readme/3-create-app-form.png b/docs/assets/readme/3-create-app-form.png
new file mode 100644
index 00000000..953d367c
Binary files /dev/null and b/docs/assets/readme/3-create-app-form.png differ
diff --git a/docs/assets/readme/4-forwarding front-end.png b/docs/assets/readme/4-forwarding front-end.png
new file mode 100644
index 00000000..d85799a8
Binary files /dev/null and b/docs/assets/readme/4-forwarding front-end.png differ
diff --git a/frontend/.env.example b/frontend/.env.example
index d1dfd3f1..45983d17 100644
--- a/frontend/.env.example
+++ b/frontend/.env.example
@@ -9,3 +9,8 @@ VITE_ENABLE_REPORT_ISSUE=false
# This is meant for development only.
# Note: this only works when opening a room url directly, not when navigating via the landing page.
VITE_BYPASS_WAITING_ROOM=false
+
+# For testing with multiple devices, you can use ngrok to expose your vite server to the internet.
+# Please refer to https://ngrok.com/docs/ for more information.
+VITE_TUNNEL_DOMAIN=''
+# VITE_TUNNEL_DOMAIN=1e1d-217-9-247-214.ngrok-free.app
\ No newline at end of file
diff --git a/frontend/package.json b/frontend/package.json
index 2b04921d..a2f839d1 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -7,7 +7,7 @@
"scripts": {
"build": "vite build && yarn cp-build",
"cp-build": "mkdir -p ../backend/dist && cp -r dist ../backend",
- "dev": "vite",
+ "dev": "vite --host",
"docs": "typedoc",
"docs:watch": "typedoc --watch",
"lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts
index dffb432b..797db3e7 100644
--- a/frontend/vite.config.ts
+++ b/frontend/vite.config.ts
@@ -1,5 +1,5 @@
///
-import { defineConfig, mergeConfig } from 'vite';
+import { defineConfig, loadEnv, mergeConfig } from 'vite';
import type { UserConfig as VitestUserConfigInterface } from 'vitest/config';
import { defineConfig as defineVitestConfig } from 'vitest/config';
import react from '@vitejs/plugin-react';
@@ -26,17 +26,23 @@ const vitestConfig: VitestUserConfigInterface = defineVitestConfig({
});
// https://vitejs.dev/config/
-const viteConfig = defineConfig({
- optimizeDeps: {
- include: ['@emotion/react', '@emotion/styled', '@mui/material/Tooltip'],
- },
- plugins: [
- react(),
- replace({
- 'process.env.CI': process.env.CI,
- preventAssignment: true,
- }),
- ],
-});
+export default defineConfig(({ mode }) => {
+ const env = loadEnv(mode, process.cwd());
-export default mergeConfig(vitestConfig, viteConfig);
+ return mergeConfig(vitestConfig, {
+ server: {
+ host: true,
+ allowedHosts: ['*', env.VITE_TUNNEL_DOMAIN],
+ },
+ optimizeDeps: {
+ include: ['@emotion/react', '@emotion/styled', '@mui/material/Tooltip'],
+ },
+ plugins: [
+ react(),
+ replace({
+ 'process.env.CI': process.env.CI,
+ preventAssignment: true,
+ }),
+ ],
+ });
+});
diff --git a/integration-tests/playwright.config.ts b/integration-tests/playwright.config.ts
index 7d002746..03d056d4 100644
--- a/integration-tests/playwright.config.ts
+++ b/integration-tests/playwright.config.ts
@@ -145,7 +145,7 @@ export default defineConfig({
/* Run your local dev server before starting the tests */
webServer: {
- command: 'cd .. && yarn start',
+ command: 'cd .. && yarn workspace frontend build && yarn start',
url: 'http://127.0.0.1:3345',
reuseExistingServer: true,
},
diff --git a/package.json b/package.json
index 0cb88f3a..b951c9d3 100644
--- a/package.json
+++ b/package.json
@@ -15,7 +15,7 @@
"scripts": {
"build": "yarn workspace frontend build",
"deploy-vcr": "vcr deploy",
- "dev": "yarn && yarn workspace frontend dev & yarn workspace backend dev",
+ "dev": "yarn && concurrently 'yarn workspace frontend dev' 'yarn workspace backend dev'",
"docs": "yarn workspace frontend docs",
"docs:watch": "yarn workspace frontend docs:watch",
"lint": "ESLINT_USE_FLAT_CONFIG=false yarn eslint . --ext .ts,.tsx",
@@ -23,9 +23,11 @@
"lint:fix": "yarn prettier --write . && yarn lint --fix",
"postinstall": "husky",
"run-server": "yarn workspace backend start",
- "start": "yarn workspace frontend build && yarn workspace backend start",
+ "start": "yarn workspace backend start",
"start:backend": "yarn workspace backend dev",
+ "debug:backend": "yarn workspace backend debug",
"start:frontend": "yarn workspace frontend dev",
+ "forward:frontend": "npx ngrok http 5173",
"test": "yarn test:backend && yarn test:frontend",
"test:backend": "yarn workspace backend test",
"test:backend:watch": "yarn workspace backend test:watch",
@@ -68,6 +70,7 @@
"husky": "^9.0.11",
"license-checker": "^25.0.1",
"lint-staged": "^15.2.2",
+ "concurrently": "^9.1.2",
"prettier": "^3.2.5",
"typescript": "^5.8.3"
},
diff --git a/yarn.lock b/yarn.lock
index a081b21b..36866e43 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3357,7 +3357,7 @@ chalk@^3.0.0:
ansi-styles "^4.1.0"
supports-color "^7.1.0"
-chalk@^4.0.0, chalk@^4.1.0:
+chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2:
version "4.1.2"
resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz"
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
@@ -3548,6 +3548,19 @@ concat-map@0.0.1:
resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
+concurrently@^9.1.2:
+ version "9.1.2"
+ resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-9.1.2.tgz#22d9109296961eaee773e12bfb1ce9a66bc9836c"
+ integrity sha512-H9MWcoPsYddwbOGM6difjVwVZHl63nwMEwDJG/L7VGtuaJhb12h2caPG2tVPWs7emuYix252iGfqOyrz1GczTQ==
+ dependencies:
+ chalk "^4.1.2"
+ lodash "^4.17.21"
+ rxjs "^7.8.1"
+ shell-quote "^1.8.1"
+ supports-color "^8.1.1"
+ tree-kill "^1.2.2"
+ yargs "^17.7.2"
+
confbox@^0.1.7:
version "0.1.7"
resolved "https://registry.npmjs.org/confbox/-/confbox-0.1.7.tgz"
@@ -7701,6 +7714,13 @@ run-parallel@^1.1.9:
dependencies:
queue-microtask "^1.2.2"
+rxjs@^7.8.1:
+ version "7.8.2"
+ resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.2.tgz#955bc473ed8af11a002a2be52071bf475638607b"
+ integrity sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==
+ dependencies:
+ tslib "^2.1.0"
+
safe-array-concat@^1.1.2:
version "1.1.2"
resolved "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz"
@@ -7842,6 +7862,11 @@ shebang-regex@^3.0.0:
resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz"
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
+shell-quote@^1.8.1:
+ version "1.8.2"
+ resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.2.tgz#d2d83e057959d53ec261311e9e9b8f51dcb2934a"
+ integrity sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==
+
shiki@^1.16.2:
version "1.22.2"
resolved "https://registry.yarnpkg.com/shiki/-/shiki-1.22.2.tgz#ed109a3d0850504ad5a1edf8496470a2121c5b7b"
@@ -8271,9 +8296,9 @@ supports-color@^7.1.0:
dependencies:
has-flag "^4.0.0"
-supports-color@^8.0.0:
+supports-color@^8.0.0, supports-color@^8.1.1:
version "8.1.1"
- resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c"
integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
dependencies:
has-flag "^4.0.0"
@@ -8424,6 +8449,11 @@ tr46@~0.0.3:
resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz"
integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
+tree-kill@^1.2.2:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc"
+ integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==
+
treeify@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/treeify/-/treeify-1.1.0.tgz#4e31c6a463accd0943879f30667c4fdaff411bb8"
@@ -8473,7 +8503,7 @@ tsconfig-paths@^3.15.0:
minimist "^1.2.6"
strip-bom "^3.0.0"
-tslib@^2.3.0:
+tslib@^2.1.0, tslib@^2.3.0:
version "2.8.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f"
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
@@ -9036,9 +9066,9 @@ yargs-parser@^21.0.1, yargs-parser@^21.1.1:
resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz"
integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==
-yargs@^17.3.1:
+yargs@^17.3.1, yargs@^17.7.2:
version "17.7.2"
- resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269"
integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==
dependencies:
cliui "^8.0.1"