An open API service indexing awesome lists of open source software.

https://github.com/openzeppelin/ui-builder

UI Builder is an open-source blockchain development tool that helps developers and non-developers create user-friendly interfaces for smart contract interaction by providing a chain-agnostic form builder that generates standalone "mini apps" without requiring backend infrastructure.
https://github.com/openzeppelin/ui-builder

blockchain builder evm forms midnight solana stellar web3

Last synced: 25 days ago
JSON representation

UI Builder is an open-source blockchain development tool that helps developers and non-developers create user-friendly interfaces for smart contract interaction by providing a chain-agnostic form builder that generates standalone "mini apps" without requiring backend infrastructure.

Awesome Lists containing this project

README

          

# UI Builder 🧩

> Spin up a front-end for any contract call in seconds. Select the function, auto-generate a React UI with wallet connect and multi-network support, and export a complete app.

## Project Status

This project is currently in development.

[![CI](https://github.com/OpenZeppelin/ui-builder/actions/workflows/ci.yml/badge.svg)](https://github.com/OpenZeppelin/ui-builder/actions/workflows/ci.yml)
[![Coverage](https://github.com/OpenZeppelin/ui-builder/actions/workflows/coverage.yml/badge.svg)](https://github.com/OpenZeppelin/ui-builder/actions/workflows/coverage.yml)
[![Dependencies](https://github.com/OpenZeppelin/ui-builder/actions/workflows/dependencies.yml/badge.svg)](https://github.com/OpenZeppelin/ui-builder/actions/workflows/dependencies.yml)
[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/OpenZeppelin/ui-builder/badge)](https://api.securityscorecards.dev/projects/github.com/OpenZeppelin/ui-builder)
[![License: AGPL v3](https://img.shields.io/badge/License-AGPL_v3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0)

[![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-brightgreen.svg)](https://conventionalcommits.org)
[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/)
[![TypeScript](https://img.shields.io/badge/TypeScript-007ACC?logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
[![React](https://img.shields.io/badge/React-20232A?logo=react&logoColor=61DAFB)](https://reactjs.org/)
[![Tailwind CSS](https://img.shields.io/badge/Tailwind_CSS-38B2AC?logo=tailwind-css&logoColor=white)](https://tailwindcss.com/)
[![Vite](https://img.shields.io/badge/Vite-B73BFE?logo=vite&logoColor=FFD62E)](https://vitejs.dev/)
[![pnpm](https://img.shields.io/badge/pnpm-F69220?logo=pnpm&logoColor=white)](https://pnpm.io/)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](http://makeapullrequest.com)

## Table of Contents

- [Repository Structure](#repository-structure)
- [Packages](#packages)
- [Builder Package](#builder-package)
- [Adapter Packages](#adapter-packages)
- [Shared Packages (External)](#shared-packages-external)
- [Features](#features)
- [Tech Stack](#tech-stack)
- [Getting Started](#getting-started)
- [Prerequisites](#prerequisites)
- [Installation](#installation)
- [Running with Docker (Recommended)](#running-with-docker-recommended)
- [Available Scripts](#available-scripts)
- [Project Structure](#project-structure)
- [Local Application](#local-application)
- [External Package Repositories](#external-package-repositories)
- [Configuration Structure](#configuration-structure)
- [Architecture](#architecture)
- [Project Constitution](#project-constitution)
- [Build System](#build-system)
- [Component Architecture](#component-architecture)
- [Renderer Components](#renderer-components)
- [Code Style](#code-style)
- [Git Hooks](#git-hooks)
- [CSS Class Name Sorting](#css-class-name-sorting)
- [Shared Prettier Configuration](#shared-prettier-configuration)
- [Import Sorting](#import-sorting)
- [Dependency Management](#dependency-management)
- [Exported Package Versions](#exported-package-versions)
- [Checking for Outdated Dependencies](#checking-for-outdated-dependencies)
- [Updating Dependencies](#updating-dependencies)
- [Automated Updates](#automated-updates)
- [Adding New Adapters](#adding-new-adapters)
- [Commit Convention](#commit-convention)
- [Contributing](#contributing)
- [Security](#security)
- [License](#license)
- [CI/CD Pipeline](#cicd-pipeline)
- [Package Publishing](#package-publishing)
- [Monorepo Configuration](#monorepo-configuration)
- [Shared Configurations](#shared-configurations)
- [Runtime Configuration](#runtime-configuration)
- [Builder Application Configuration (Development)](#builder-application-configuration-development)
- [Exported Application Configuration](#exported-application-configuration)

## Repository Structure

This repository contains the Builder application plus repository-level tooling,
workflows, and export scripts.

- **apps/builder**: The main application with the builder UI and export logic.

### Shared Packages (External)

Core UI packages are maintained in the [openzeppelin-ui](https://github.com/OpenZeppelin/openzeppelin-ui)
monorepo:

- **react**: Core React context providers and hooks (AdapterProvider, WalletStateProvider, useWalletState) for managing global wallet/network state and adapter interactions.
- **renderer**: React components for rendering blockchain transaction forms, contract state displays, execution configuration, and transaction status tracking.
- **components**: Shared React UI components, including basic primitives (buttons, inputs, cards) and specialized form field components.
- **storage**: Local storage services built on IndexedDB for persisting contract UI configurations, providing history, auto-save, and import/export capabilities.
- **types**: Shared TypeScript type definitions for all packages.
- **styles**: Centralized styling system with shared CSS variables and configurations.
- **utils**: Shared, framework-agnostic utility functions (e.g., logger, app configuration service).

## Packages

### Builder Package

The main application with the builder UI, export system, and core logic.

For more details, see the [Builder README](./apps/builder/README.md).

### Adapter Packages

Adapter implementations live in the
[openzeppelin-adapters](https://github.com/OpenZeppelin/openzeppelin-adapters) repository and are
published under the `@openzeppelin/adapter-*` namespace. Shared Vite/Vitest
integration for consuming apps is provided by `@openzeppelin/adapters-vite`.

#### Public Adapter Packages

- `@openzeppelin/adapter-evm`
- `@openzeppelin/adapter-midnight`
- `@openzeppelin/adapter-polkadot`
- `@openzeppelin/adapter-solana`
- `@openzeppelin/adapter-stellar`
- `@openzeppelin/adapters-vite` (shared build-time integration helper)

#### Internal Adapter Package

- `@openzeppelin/adapter-evm-core` is an internal package bundled by the public EVM-oriented
adapters rather than consumed directly by Builder applications.

## Features

- Chain-agnostic architecture supporting multiple blockchain ecosystems
- Adapter pattern for easily adding support for new blockchains
- Modern React components for building transaction forms
- Customizable UI with Tailwind CSS and shadcn/ui
- **Local Storage & History**: Complete auto-save system with IndexedDB-based persistence for contract UI configurations
- **Import/Export**: Save and share configurations as JSON files with built-in validation
- **Multi-tab Synchronization**: Real-time synchronization of saved configurations across browser tabs
- Handles wallet connection state consistently in both builder app and exported forms
- Configure transaction execution methods (EOA, Relayer, Multisig) via a powerful Execution Strategy pattern
- Type-safe with TypeScript
- Fast development with Vite
- Comprehensive test suite with Vitest
- Automated dependency management and security checks

## Tech Stack

- **React**: UI library supporting both React 18 and 19 with modern hooks API
- **TypeScript 5.8+**: Enhanced type safety with template literal types
- **Vite 6**: Fast, modern build tool and dev server with standardized library builds
- **Tailwind CSS v4**: Next-gen utility-first CSS framework with OKLCH color format
- **shadcn/ui**: Unstyled, accessible component system built on Radix UI
- **pnpm (v9 or higher)**: Fast, disk-efficient package manager
- **Vitest**: Testing framework integrated with Vite
- **Zustand**: Lightweight, performant state management for React
- **GitHub Actions**: CI plus Docker deploys for staging and production (see `.github/workflows`)
- **ESLint 9**: Modern linting with improved TypeScript support
- **tsup**: Used for root/tooling bundles where applicable
- **Vite**: Builder application dev server and production build
- **Dexie.js**: Modern IndexedDB wrapper for local storage and offline capabilities
- **@openzeppelin/relayer-sdk**: For gasless transaction support via the Relayer execution method.

## Getting Started

### Prerequisites

- Node.js (v20.11.1 or higher)
- pnpm (v9 or higher)

### Installation

1. Clone the repository:

```bash
git clone https://github.com/OpenZeppelin/ui-builder.git
cd ui-builder
```

2. Install dependencies:

```bash
pnpm install
```

3. Build all packages:

```bash
pnpm build
```

4. Start the development server:

```bash
pnpm dev
```

5. Open your browser and navigate to `http://localhost:5173`

### Running with Docker (Recommended)

For a consistent and reliable development environment, it is highly recommended to run the application using Docker. This avoids potential issues with local Node.js, pnpm, or operating system configurations.

1. **Prerequisites**: Make sure you have Docker and Docker Compose installed on your system.

2. **Build and Run the Container**:

```bash
docker-compose up --build
```

This command will build the Docker image and start the application. Once it's running, you can access it at `http://localhost:3000`.

## Available Scripts

- `pnpm dev` - Start the development server
- `pnpm build` - Build for production
- `pnpm lint` - Run ESLint
- `pnpm lint:fix` - Fix ESLint issues
- `pnpm lint:all-fix` - Fix ESLint issues across all file types
- `pnpm lint:config-files` - Lint Vite/Vitest config files (read-only; fails on issues)
- `pnpm lint:config-files:fix` - Auto-fix lint issues in configuration files (builder app only; run via `pnpm --filter=@openzeppelin/ui-builder-app lint:config-files:fix`)
- `pnpm format` - Format code with Prettier
- `pnpm format:check` - Check formatting without making changes
- `pnpm fix-all` - Run Prettier first, then ESLint to avoid conflicts with CSS class sorting
- `pnpm preview` - Preview the production build
- `pnpm ui:add` - Add shadcn/ui components
- `pnpm test` - Run tests
- `pnpm test:watch` - Run tests in watch mode
- `pnpm test:coverage` - Run tests with coverage report
- `pnpm commit` - Run commitizen for guided commits
- `pnpm update-deps` - Update all monorepo dependencies to their latest versions
- `pnpm update-deps:major` - Update dependencies including major versions
- `pnpm check-deps` - Check for deprecated dependencies
- `pnpm outdated` - List outdated dependencies across the monorepo
- `pnpm export-app [cmd] [opts]` - Export a standalone form project (see `pnpm export-app --help`)
- `pnpm update-export-versions` - Update the hardcoded versions of internal packages used in exported forms

## Project Structure

This repository contains the Builder application and repository-level tooling.

### Local Application

- **[apps/builder/](./apps/builder/README.md)** - Main application with builder UI, export system,
and runtime integration code

### External Package Repositories

- **[openzeppelin-adapters](https://github.com/OpenZeppelin/openzeppelin-adapters)** - Adapter
implementations published as `@openzeppelin/adapter-*`
- **[openzeppelin-ui](https://github.com/OpenZeppelin/openzeppelin-ui)** - Shared renderer, React,
components, storage, types, styles, and utils packages

### Configuration Structure

```text
ui-builder/
├── .github/ # GitHub workflows and templates
├── .husky/ # Git hooks
├── test/ # Shared test setup and utilities
├── packages/ # Monorepo packages (see individual READMEs for detailed structure)
├── scripts/ # Utility scripts
├── tailwind.config.cjs # Central Tailwind CSS configuration
├── postcss.config.cjs # Central PostCSS configuration
├── components.json # Central shadcn/ui configuration
├── tsconfig.base.json # Base TypeScript configuration for all packages
├── pnpm-workspace.yaml # PNPM workspace configuration
└── ... # Other configuration files
```

For detailed application structure, see the Builder README linked above.

## Architecture

The application uses a modular, domain-driven adapter pattern to support multiple blockchain ecosystems. For the adapter source-of-truth, please see the **[Adapter Architecture Guide](https://github.com/OpenZeppelin/openzeppelin-adapters/blob/main/docs/ADAPTER_ARCHITECTURE.md)** in the `openzeppelin-adapters` repository.

**Key Components:**

- **Builder**: Chain-agnostic application logic, UI components, and the export system. It includes:
- The `ecosystemManager.ts` for discovering network configurations and adapter capabilities.
- **Modular State Management**: Decomposed hook architecture with specialized responsibilities.
- **Application Sidebar**: Complete UI for managing saved configurations with import/export capabilities

- **Storage System (`@openzeppelin/ui-storage`)**: IndexedDB-based persistence layer built on
Dexie.js providing:
- **Auto-Save Engine**: Debounced saving with in-memory caching and global coordination
- **Multi-Tab Synchronization**: Real-time updates across browser tabs
- **Import/Export**: JSON-based configuration sharing with validation
- **CRUD Operations**: Complete lifecycle management for contract UI configurations
- **Performance Optimization**: Efficient handling of 1000+ records with reactive updates

- **Adapters (`@openzeppelin/adapter-*`)**: Individual packages maintained in
`openzeppelin-adapters` containing chain-specific implementations (for example `adapter-evm` and
`adapter-stellar`). Each adapter conforms to the common `ContractAdapter` interface defined in
`@openzeppelin/ui-types`. Adapters are instantiated with a specific `NetworkConfig`, making them
network-aware. The Builder app (via providers from `@openzeppelin/ui-react`) dynamically loads and
uses these adapters. Furthermore, adapters can optionally provide UI-specific functionalities:
- **React UI Context Provider** (e.g., for `wagmi/react` on EVM): `WalletStateProvider` (from `@openzeppelin/ui-react`) consumes this to set up the necessary app-wide context for the active adapter.
- **Facade Hooks** (e.g., `useAccount`, `useSwitchChain`): These are exposed by `WalletStateProvider` (via `useWalletState().walletFacadeHooks` from `@openzeppelin/ui-react`) for UI components to interact with wallet functionalities reactively and agnostically.
- **Standardized UI Components** (e.g., `ConnectButton`): These components are retrieved via `activeAdapter.getEcosystemWalletComponents()` and are expected to internally use the facade hooks.

- **Renderer (`@openzeppelin/ui-renderer`)**: Shared library containing app rendering components
and common utilities (like logging).

- **React Core (`@openzeppelin/ui-react`)**: Centralized React state management providing:
- **Adapter Provider**: Singleton pattern for adapter instance management
- **Wallet State Provider**: Global wallet/network state coordination
- **Context Hooks**: `useWalletState()` and `useAdapterContext()` for consistent state access

- **UI Components (`@openzeppelin/ui-components`)**: Comprehensive component library including:
- **Basic Primitives**: Buttons, inputs, cards, dialogs following shadcn/ui patterns
- **Form Fields**: Specialized components for React Hook Form integration
- **Field Utilities**: Validation, accessibility, and layout helpers

- **Types**: Shared TypeScript type definitions across all packages, including the crucial `ContractAdapter` interface and types for adapter UI enhancements.

- **Styling System**: Centralized CSS variables and styling approach used across all packages.

This architecture allows for easy extension to support additional blockchain ecosystems without modifying the builder application logic. The `builder` package dynamically loads and uses adapters via `ecosystemManager.ts` and the provider model (from `@openzeppelin/ui-react`) and the export system includes the specific adapter package needed for the target chain in exported forms. It utilizes **custom Vite plugins** to create **virtual modules**, enabling reliable loading of shared assets (like configuration files between packages) across package boundaries, ensuring consistency between development, testing, and exported builds.

## Project Constitution

This project is governed by the UI Builder Constitution. Please read it before contributing changes that affect architecture, adapters, or tooling:

- [./.specify/memory/constitution.md](./.specify/memory/constitution.md)

## Build System

The primary build target in this repository is the Builder app, while adapter package builds and
adapter-specific validation live in `openzeppelin-adapters`.

For more detailed documentation about the adapter pattern, implementation guidelines, and validation rules, see the documentation within the [`packages/types/src/adapters/base.ts`](https://github.com/OpenZeppelin/openzeppelin-ui/blob/main/packages/types/src/adapters/base.ts) file where the `ContractAdapter` interface is defined.

## Component Architecture

The project follows a structured component architecture centered around app rendering:

### Renderer Components

The [`@openzeppelin/ui-renderer`](https://github.com/OpenZeppelin/openzeppelin-ui/tree/main/packages/renderer) package (maintained in the external openzeppelin-ui repo) provides:

- **TransactionForm**: Core component for rendering blockchain transaction forms with dynamic field generation
- **ContractStateWidget**: Widget for querying and displaying contract state through view functions
- **ExecutionConfigDisplay**: Configuration UI for transaction execution methods (EOA/Relayer)
- **TransactionStatusDisplay**: Shows transaction progress, hash display with explorer links
- **DynamicFormField**: Renders form fields dynamically based on field type configuration

The actual UI primitives (like `TextField`, `AddressField`, `Button`, `Input`) are sourced from the `@openzeppelin/ui-components` package and work exclusively with React Hook Form.

## Code Style

### Git Hooks

This project uses Husky to enforce code quality using Git hooks:

- **pre-commit**: Runs lint-staged to format and lint staged files (Prettier first, then ESLint)
- **pre-push**: Runs comprehensive linting and formatting before pushing to remote
- **commit-msg**: Enforces conventional commit message format

These hooks ensure that code pushed to the repository maintains consistent quality and style.

### CSS Class Name Sorting

For consistent CSS class name sorting in Tailwind CSS, always run Prettier first, then ESLint:

```bash
# Recommended approach (runs formatting, then linting)
pnpm fix-all
```

This approach ensures that Tailwind CSS classes are consistently sorted by the prettier-plugin-tailwindcss plugin and prevents conflicts between formatting and linting tools.

### Shared Prettier Configuration

This project uses a single, shared Prettier configuration at the root of the monorepo. Individual packages **should not** include their own `.prettierrc` files. The root configuration includes:

- Common code style settings (single quotes, semi-colons, etc.)
- Tailwind CSS class sorting via prettier-plugin-tailwindcss
- Configuration for special utility functions like `cva`, `cn`, `clsx`, and `twMerge`

To format all packages:

```bash
pnpm format
```

### Import Sorting

Imports are automatically sorted in the following order:

1. React and related packages
2. External packages
3. Internal packages (alias imports starting with `@/`)
4. Parent imports (starting with `..`)
5. Other relative imports (starting with `.`)
6. Style imports
7. Type imports

This ordering is enforced by ESLint and automatically fixed on commit.

## Dependency Management

This project uses several tools to manage dependencies effectively:

- **pnpm**: Fast, disk space efficient package manager
- **check-deps script**: Custom utility to identify deprecated dependencies
- **update-deps script**: Easily update all dependencies to their latest versions
- **Dependencies workflow**: Regular checks for outdated dependencies
- **Update Dependencies workflow**: Weekly automated updates

### Exported Package Versions

The versions of internal `@openzeppelin/` packages used in exported forms are centrally managed in the `apps/builder/src/export/versions.ts` file. This ensures that all exported projects use stable, tested, and reproducible dependency versions.

To update these versions to the latest published releases, run the following command from the root of the monorepo:

```bash
pnpm update-export-versions
```

This script will fetch the latest versions from the npm registry and update the `versions.ts` file automatically.

### Checking for Outdated Dependencies

To see which dependencies are outdated:

```bash
pnpm outdated
```

### Updating Dependencies

For regular updates (respecting semver):

```bash
pnpm update-deps
```

For major version updates (may include breaking changes):

```bash
pnpm update-deps:major
```

### Automated Updates

The project is configured with:

1. **Update Dependencies workflow**: Runs weekly to check for and apply updates

## Adding New Adapters

New adapter packages should be created in
[openzeppelin-adapters](https://github.com/OpenZeppelin/openzeppelin-adapters), not in this
repository.

To add support for a new ecosystem end-to-end:

1. Implement and publish the adapter from `openzeppelin-adapters` under `@openzeppelin/adapter-*`.
2. Register the new package in `apps/builder/src/core/ecosystemManager.ts`.
3. Update export configuration and tests so generated apps include the new package correctly.
4. Verify the Builder app still builds and exports successfully.

## Commit Convention

This project follows [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/). See [COMMIT_CONVENTION.md](./COMMIT_CONVENTION.md) for
more details.

Example:

```text
feat(ui): add button component
```

## Contributing

Please read [CONTRIBUTING.md](./CONTRIBUTING.md) for details on our code of conduct and the process for submitting pull requests.

## Security

Please read [SECURITY.md](./SECURITY.md) for details on our security policy and how to report vulnerabilities.

## License

This project is licensed under the GNU Affero General Public License v3.0 - see the [LICENSE](./LICENSE) file for details.

## CI/CD Pipeline

This project uses GitHub Actions for continuous integration and delivery:

- **CI Workflow**: Runs tests, linting, and type checking
- **Coverage Workflow**: Generates and uploads test coverage reports
- **Staging / production**: Docker images are built and deployed via `.github/workflows/docker-stg.yaml` and `docker-prod.yaml`
- **Security Workflow**: Checks for security vulnerabilities
- **Dependencies Workflow**: Checks for outdated dependencies

Shared libraries (`@openzeppelin/ui-*`, `@openzeppelin/adapter-*`, etc.) are published from their own repositories; this repo ships the Builder web app only.

## Monorepo Configuration

This project uses a centralized configuration approach to maintain consistency across all packages:

### Shared Configurations

- **tailwind.config.cjs**: Root configuration for Tailwind CSS, used by all packages
- **postcss.config.cjs**: Root configuration for PostCSS, used by all packages
- **components.json**: Root configuration for shadcn/ui components, referenced by packages

Packages consume these root configs via:

- JS proxy files (`packages/*/tailwind.config.cjs` and `packages/*/postcss.config.cjs`) that require the root configs
- Per-package `components.json` files (regular JSON) that reference the package CSS entry (e.g., `../styles/global.css`)

During the export process, proxy configs and JSON are included to create standalone configuration files for the exported project.

## Runtime Configuration

Both the main UI Builder application and its exported forms support runtime configuration for certain parameters. This is primarily managed via an `AppConfigService` and allows customization without rebuilding the application code.

### Builder Application Configuration (Development)

During development of the builder application, configurations are typically provided via Vite environment variables defined in `.env` files (e.g., `.env.local`). These variables usually follow a prefix like `VITE_APP_CFG_...`.

Key configurable items include:

- **Explorer API Keys:** For services like Etherscan, PolygonScan, Routescan, etc., used by adapters to fetch ABIs. Two patterns are supported:
- Per-network keys: `VITE_APP_CFG_API_KEY_="your_key"` (e.g., `VITE_APP_CFG_API_KEY_ETHERSCAN_MAINNET`)
- Global service keys: `VITE_APP_CFG_SERVICE__API_KEY="your_key"` (e.g., `VITE_APP_CFG_SERVICE_ETHERSCANV2_API_KEY` for unified Etherscan V2, or `VITE_APP_CFG_SERVICE_ROUTESCAN_API_KEY` for Routescan)
- **WalletConnect Project ID:** For EVM adapter's WalletConnect functionality. Example: `VITE_APP_CFG_SERVICE_WALLETCONNECT_PROJECT_ID="your_id"`.
- **RPC URL Overrides:** To use custom RPC endpoints instead of public defaults for specific networks. Example: `VITE_APP_CFG_RPC_ENDPOINT_ETHEREUM_MAINNET="https://your_custom_rpc.com"`.
- **Indexer Endpoint Overrides:** To configure GraphQL indexer endpoints for historical blockchain data queries (e.g., access control events). Example: `VITE_APP_CFG_INDEXER_ENDPOINT_STELLAR_TESTNET="https://your_indexer.com/graphql"`.

### Exported Application Configuration

Exported forms include a `public/app.config.json` file. Users of the exported form should edit this file to provide their own API keys and RPC URLs.

The structure of this JSON file includes sections for:

- `networkServiceConfigs`: For per-network explorer API keys, keyed by a service identifier (e.g., `"etherscan-mainnet"`).
- `globalServiceConfigs`: For global service parameters (e.g., `walletconnect.projectId`) and unified explorer API keys (e.g., `etherscanv2.apiKey` for Etherscan V2, `routescan.apiKey` for Routescan).
- `rpcEndpoints`: For RPC URL overrides, keyed by the network ID (e.g., `"ethereum-mainnet"`).
- `indexerEndpoints`: For indexer endpoint overrides, keyed by the network ID (e.g., `"stellar-testnet"`). Values can be strings (HTTP URL) or objects with `http` and `ws` properties.

Refer to the README included with the exported application for detailed instructions on configuring `public/app.config.json`.