Skip to content
CAI
Software that uses CAICheck a score

exposedev/expose

50.1

Adequate · 19 September 2026

206.8k

lines of production code

PHP

primary language

1

measurement over time

CAI band scale
CAI lens gauges

What this system is

Expose is an open-source ngrok alternative that creates secure tunnels to expose local development servers to the internet. It provides a local dashboard for real-time inspection, search, and replay of HTTP and TCP traffic, enriched with structured data from webhook plugins. The system supports magic link authentication, custom domain management, and extensible plugin architectures for request handling.

How it got here

2020 — Expose v3.2.4 initial release and rebrand

18 changes.

This period marks the initial release of the project rebranded from 'phunnel' to 'Expose', featuring a major architectural overhaul that removes legacy client and server modules in favor of a modular, Laravel Zero-based CLI. The update introduces official Docker support, a new internal dashboard with magic login authentication, and a refactored logging system with dedicated storage handlers.

2024 — internal dashboard and logging overhaul

12 changes.

This period focused on building a comprehensive internal dashboard for inspecting and replaying web requests, featuring a new Vue.js frontend and extensive backend logging infrastructure. The work introduced a plugin system for enriching request data, centralized platform interaction, and robust client-side connection handling with persistent SQLite logging.

2025 — observability and developer tooling

4 changes.

This period focused on enhancing application observability by implementing comprehensive request and response logging tables and dedicated API resources for structured data exposure. It also expanded developer tooling by introducing a Laravel Zero Tinkerwell driver for interactive debugging and adding automatic detection for Valet/Herd sites and Vite server sharing.

Features

Add Laravel Zero Tinkerwell driver

A new Tinkerwell driver for Laravel Zero applications has been added, enabling interactive code execution and debugging within the Tinkerwell IDE. This driver bootstraps the Laravel Zero application, displays the application version, and integrates a panel to show general application information. It also includes logic to inject query logging, allowing users to monitor database queries executed during their interactive sessions.

.tinkerwell · high confidence

Added stub for custom request plugins

A new stub file (CustomRequestPlugin.php.stub) has been added to the resources/stubs directory, providing a template for creating custom request plugins. This stub defines a class extending BasePlugin with methods for identifying requests (matchesRequest) and extracting plugin data (getPluginData), enabling users to generate custom plugin implementations via CLI commands.

resources/stubs · high confidence

Client restructured with new authentication and logging capabilities

The app client has been reorganized into a new namespace (Expose\\Client) with dedicated classes for configuration, connection management, and proxy handling. This change introduces magic link authentication, allowing users to secure shared sites with email-based access control via a configurable secret key and optional email domain patterns. Additionally, the client now supports persistent request logging to a local SQLite database, enabling features such as log search, replay, and modification through new API endpoints. Basic authentication support has also been added for proxying requests.

app · high confidence

Define TypeScript types for internal dashboard data structures

Added TypeScript declaration files to the internal dashboard to provide type safety for frontend data models. The new \types.d.ts\ file defines interfaces for request and response data, log entries, list items, user information, banner configuration, and plugin details, while \packages.d.ts\ adds type declarations for the vue3-json-viewer library.

resources/js/internal-dashboard/src/types · high confidence

Initial release of Expose server with Docker support and renamed binary

The project is rebranded from 'phunnel' to 'Expose' (an open-source ngrok alternative), with the main executable binary renamed from \phunnel\ to \expose\. This release introduces official Docker support, including a \Dockerfile\ based on PHP 8.1, a \docker-compose.yml\ for easy deployment, and a \docker-entrypoint.sh\ script to handle configuration injection. The PHAR build configuration (\box.json\) has been updated to include necessary directories like \database\ and \resources\, and the main script now suppresses PHP 8.1 deprecation warnings. Documentation has been updated to reflect the new branding and managed service offerings.

(repo-wide) · high confidence

Introduce FetchesPlatformData trait for centralized platform interaction

Added the new FetchesPlatformData trait to handle communication with the Expose platform. This trait centralizes token validation logic, including caching and error handling for invalid tokens, and provides methods to fetch server network data, available servers, and team domains. It also introduces a configurable platform endpoint (defaulting to https://expose.dev) to allow users to specify alternative platform URLs.

app/Traits · high confidence

Introduce client-side connection handling and validation

The application now includes a new ControlConnection class to manage WebSocket communication with the server, handling authentication for HTTP and TCP proxies, proxy creation, and keep-alive pings. Additionally, a new InvalidServerProvided exception has been added to handle cases where an invalid server is specified, improving error feedback for users.

app/Connections, app/Exceptions · high confidence

Introduce extensible plugin system for logging webhook and API requests

The logger now supports a plugin architecture that automatically detects and enriches logged requests from specific services. Built-in plugins are provided for GitHub webhooks, Stripe payments, Paddle billing, and Magic Login links, each parsing relevant headers and payloads to display structured details (such as repository info, event types, or email addresses) in the UI and CLI. A PluginManager handles loading these default plugins alongside user-defined custom plugins from a local directory, allowing for extensible request inspection without modifying core logging logic.

app/Logger/Plugins · high confidence

New CLI commands for configuration, plugins, and server management

The CLI now includes dedicated commands to manage Expose configuration and features: \default-domain:clear\ and \default-server:clear\ reset the default domain and server settings; \default-domain\ and \default-server\ set or retrieve these values; \token:get\ displays the current authentication token; \token:rollback\ reverts the setup to a previous state saved in \previous\_setup.json\; \info\ shows the current configuration, available servers, and custom domains (with \--json\, \--servers\, and \--custom-domains\ flags); \servers\ lists available remote servers; \plugins\ lists active request plugins, while \plugins:manage\ activates or deactivates them and \make:plugin\ creates new custom plugins; \publish\ outputs the default configuration file to the user's home directory; \login\ triggers browser-based authentication; \share-cwd\ shares the current working directory with optional YAML config support; \share-port\ shares a local TCP port; and \catch-all\ shares a catch-all site. The legacy \ServeCommand\ has been removed.

app/Commands · high confidence

New internal dashboard API endpoints for log management and tunnel control

The client now exposes a set of HTTP controllers to power the internal dashboard, enabling users to manage and inspect traffic directly from the local interface. This includes endpoints to list and search logged requests (GetLogsController, SearchLogsController), view individual request details (GetLogController), and replay requests either as-is (ReplayLogController) or with modifications (ReplayModifiedLogController). Additionally, users can clear stored logs (ClearLogsController), view active tunnel information (GetTunnelsController), create new tunnels (CreateTunnelController), and receive real-time log updates via WebSocket push (PushLogsToDashboardController). The DashboardController serves the main UI, while FileController handles static asset delivery.

app/Http/Controllers · high confidence

New internal dashboard and magic login authentication views

The application now includes a new internal dashboard view (\resources/views/client/internal\_dashboard.blade.php\) that serves as a container for a frontend application via injected CSS and JS files, and a new magic login authentication view (\resources/views/client/magic\_login.blade.php\) that allows users to access protected sites by entering their email address. The previous static index view (\resources/views/index.html\) has been removed, indicating a shift from the old Vue-based log viewer to these new Blade templates for internal tooling and access control.

resources/views · high confidence

New internal dashboard for inspecting and replaying web requests

A new Vue-based internal dashboard has been added to the project, providing a dedicated interface for monitoring incoming HTTP requests. Users can view a real-time list of requests via WebSocket, inspect detailed request and response data (including headers, query parameters, and JSON bodies), and replay captured requests or modify them before replaying. The dashboard includes features such as dark/light mode switching, QR code generation for mobile access, and search functionality to filter logs.

resources/js/internal-dashboard/src/components · high confidence

New internal dashboard with dynamic banners and keyboard navigation

The internal dashboard has been rebuilt as a new Vue application, introducing a dynamic banner system that fetches promotional content from the platform API for authenticated users while displaying a fallback message for free users. The interface now supports keyboard shortcuts for navigating through request logs (arrow keys), copying subdomains, and toggling follow mode, alongside a redesigned layout featuring a sidebar and log detail view.

resources/js/internal-dashboard/src · high confidence

New request and response logging tables added

The application now includes database migrations to create \request\_logs\ and \response\_logs\ tables. The \request\_logs\ table stores details about incoming requests, including a primary \request\_id\, subdomain, raw request body, HTTP method, URI, start/stop times (stored as integers), a \performed\_at\ timestamp, duration, and optional plugin data. The \response\_logs\ table stores the corresponding response status code and raw response body, linked to the request via a foreign key on \request\_id\ with cascade deletion. A basic database seeder is also added.

database · high confidence

New support classes for config management and CLI output

The app/Support directory now includes several new classes: ExposeConfig handles loading and merging configuration from environment variables, local files, and global defaults; ConsoleSectionOutput provides enhanced terminal output capabilities with section-based clearing and overwriting; and multiple NodeVisitor classes (ClearDomainNodeVisitor, ClearServerNodeVisitor, DefaultDomainNodeVisitor, DefaultServerNodeVisitor, InsertDefaultDomainNodeVisitor, InsertDefaultServerNodeVisitor, InsertRequestPluginsNodeVisitor, TokenNodeVisitor) manipulate PHP configuration arrays to set default domains, servers, auth tokens, and request plugins.

app/Support · high confidence

Support for Valet/Herd local site detection and Vite server sharing

The CLI now automatically detects local development sites managed by Laravel Valet or Herd by reading their configuration files, allowing it to resolve shared URLs from hostnames and linked site paths. Additionally, the tool can now share the local Vite HMR server with remote visitors by detecting the Vite hot file, replacing the local URL with the shared public URL, and monitoring for changes, while also skipping this detection on Windows where non-blocking child processes are not supported.

app/Commands/Concerns · high confidence

Removals

Removal of legacy Client module and HTTP tunneling logic

The \app/Client\ directory has been completely removed, deleting the \Client\, \Connection\, \Factory\, \ProxyManager\, and \TunnelConnection\ classes. This eliminates the previous implementation of the local HTTP dashboard (previously served on port 4040), the socket-based connection handling, and the raw HTTP request tunneling logic that relied on \React/socket\ and \GuzzleHttp/Psr7\. Users will no longer have access to the internal dashboard or the specific legacy tunneling mechanism provided by this module.

app/Client · high confidence

Removal of legacy HTTP server controllers and utilities

The HTTP server implementation in the app/HttpServer directory has been removed, deleting the abstract Controller base class and all specific route handlers (DashboardController, LogController, ReplayLogController, StoreLogController) along with the QueryParameters helper. This eliminates the previous WebSocket-based HTTP interface that served the dashboard, logged requests, replayed logs, and accepted new log entries, indicating a shift away from this specific server architecture.

app/HttpServer · high confidence

Removal of legacy WebSocket message handling classes

The \ControlMessage\, \MessageFactory\, and \TunnelMessage\ classes in \app/Server/Messages\ have been removed. This eliminates the previous logic for parsing JSON control events (such as authentication and proxy registration) and handling raw HTTP tunnel data via the Ratchet library, indicating a shift in how server-side WebSocket communication and proxy connections are managed.

app/Server/Messages · high confidence

Removal of legacy server implementation files

The server-specific classes Factory.php, IoServer.php, and Shaft.php have been deleted from the app/Server directory. This removes the local implementation of the server factory, I/O server wrapper, and message handling logic (including JSON control and tunnel message processing), aligning with the shift to use shared expose-commons components.

app/Server · high confidence

Removed local server connection management classes

The \Connection\, \ConnectionManager\, and \IoConnection\ classes in \app/Server/Connections\ have been deleted. This removes the local implementation for managing TCP connections, storing them by subdomain or client ID, and rewriting HTTP host headers, indicating a shift away from this specific server-side connection handling logic.

app/Server/Connections · high confidence

Behavioural changes

Introduce dedicated HTTP resources for CLI and list log data

Added CliLogResource and LogListResource classes to structure log data for API responses. CliLogResource formats individual CLI log entries, including request details, duration, color-coded status indicators, and optional status codes. LogListResource structures log list items, exposing ID, duration, method, URI, plugin data, and status code. These resources ensure only required fields are exposed to the frontend, improving data consistency and reducing payload size.

app/Http/Resources · high confidence

Introduction of logging contracts and restructuring of platform data interface

The application now defines specific contracts for logging operations via the new LogStorageContract and LoggerContract interfaces, establishing a standardized way to handle logged requests and responses. Additionally, the previous server-side Message interface has been relocated to the client contracts namespace and refactored into FetchesPlatformDataContract, changing its primary responsibility from a generic respond method to specifically retrieving a token.

app/Contracts · high confidence

Migrate to Laravel Zero 10 with new configuration structure

The application has been upgraded to Laravel Zero 10, introducing a new configuration structure. The app name is now 'Expose' (previously 'Phunnel') and the version is hardcoded to 3.2.4. New configuration files have been added for database (defaulting to SQLite in-memory), logging (using Monolog with stderr default), and views (with Phar-aware compiled path). The main expose configuration now includes settings for servers, DNS, auth token, default domain/TLD/HTTPS, request logging limits, and request plugins. Command configuration has been updated to use Expose-specific commands.

config · high confidence

Refactor HTTP server components and add client-side routing and authentication modifiers

The HTTP server components have been moved from the \App\\HttpServer\ namespace to \Expose\\Client\\Http\, with \HttpServer\ renamed to \Server\ and its request body size limit increased from approximately 15 MB to 15 GB. A new \ClientRouteGenerator\ has been added to expose public filesystem routes via a \FileController\. The \HttpClient\ now integrates \CheckBasicAuthentication\ and \CheckMagicAuthentication\ modifiers to handle authentication checks before requests are sent, and it explicitly removes the \Expect\ header to prevent 100-continue response issues.

app/Http · high confidence

Refactored logging architecture with dedicated storage and output handlers

The monolithic logging system has been replaced by a modular architecture featuring separate handlers for CLI output (CliLogger), database persistence (DatabaseLogger), and the frontend dashboard (FrontendLogger). This change introduces a new LoggedResponse class that intelligently skips logging binary or oversized response bodies based on configuration, and updates LoggedRequest to store timestamps in milliseconds for higher precision. The RequestLogger now delegates synchronization to these specific handlers, ensuring that logs are consistently available in the terminal, the local database, and the web UI.

app/Logger · high confidence

Register chrome-extension URI scheme and refactor service bindings

The application now registers 'chrome-extension' as a valid URI scheme, enabling proper handling of Chrome extension URLs. Additionally, the service provider has been refactored to use the Expose\\Client namespace, switching from the deprecated React EventLoop Factory to the static Loop::get method, and updating the RequestLogger to accept separate CLI, Frontend, and database log storage instances instead of a single browser instance.

app/Providers · high confidence

Vue.js runtime updated to v3.5.6

The internal dashboard's client-side JavaScript bundle now uses Vue.js version 3.5.6. This update brings the latest changes to the Vue runtime-core, reactivity, and shared utilities, which may affect how components render, handle reactivity, or manage lifecycle hooks within the dashboard interface.

public · high confidence

Test coverage

Added async test infrastructure and removed outdated command test; Added feature tests for the Expose Client dashboard and HTTP client; Added unit tests for request logging and storage; Test suite now uses in-memory SQLite and rebinds log storage contract.

Dependencies

Internal dashboard dependencies and PHP environment updates

The internal dashboard now uses a new set of JavaScript dependencies including Vue 3, Vite, Tailwind CSS, and Radix Vue, replacing the previous setup. On the PHP side, the project has upgraded to Laravel Zero 11, bumped the minimum PHP version to 8.2, and updated various Symfony and Guzzle libraries, while also removing the old phar-updater dependency in favor of the new Laravel Zero phar-updater package.

(dependencies) · high confidence

Housekeeping

Exclude build artifacts from version control

A .gitignore file has been added to the builds directory to ensure that generated build artifacts are not tracked in the repository, keeping the version control history clean.

builds · high confidence

Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.

How this codebase got here

Baseline

  • First survey — no prior run to compare against. CAI 50.

Lenses

  • Code Health 85
  • Architecture 70
  • Maturity 67
  • Readiness 53
  • Security 70
  • Accessibility 37

Changes since last survey

  • 300 commits — 276 feature/other, 24 fixes

By area

  • app/Commands — 71 commits
  • (repo) — 40 commits
  • app/Logger — 36 commits
  • (root) — 25 commits
  • builds/expose — 20 commits
  • app/Client — 14 commits
  • public/build — 14 commits
  • resources/js — 14 commits
  • app/Factory.php — 8 commits
  • app/Client.php — 7 commits
  • app/Http — 7 commits
  • resources/views — 6 commits
  • tests/Feature — 6 commits
  • .github/workflows — 4 commits
  • app/Server — 4 commits
  • database/migrations — 3 commits
  • docs/getting-started — 3 commits
  • tests/Unit — 3 commits
  • .github/ISSUE_TEMPLATE — 2 commits
  • app/Contracts — 2 commits

Notable commits

  • fix: Add Stripe request plugin and fix request logger issue
  • fix: Add link; fix border opacity in Safari
  • fix: Apply fixes from StyleCI
  • fix: Apply fixes from StyleCI
  • fix: FIX: Use "git" instead of "vcs" in composer.json (#353)
  • fix: Fix binary response error
  • fix: Fix bug when there's no server message
  • fix: Fix catch-all command
  • fix: Fix clear logs
  • fix: Fix dev dependencies
  • fix: Fix duplicate output of remaining time (#28)
  • fix: Fix installation.md (#352)
  • fix: Fix issues when the Expect header is present
  • fix: Fix match checks
  • fix: Fix optional plugin data
  • fix: Fix types
  • fix: Fixed scrolling of non-breaking lines (edge case)
  • fix: Fixed wrong url (#359)
  • fix: Properly close connections when max connection length is reached. Fixes https://github.com/beyondcode/expose-v3/issues/42
  • fix: Rendering fix
  • …and 280 more

Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.

Survey your own repository

exposedev/expose was measured the same way every project in this corpus was: the same rubric, at a pinned commit, with the result published in full. Point a surveyor at a repository you know and see whether you agree with it.

About this page

  • The score is its most recent published measurement, taken on 19 September 2026 at a pinned commit. It is not a live figure and does not change until the project is measured again.
  • Measured at commit d364f8d921f7072c20b782f92d9f919b5513adb2 — the exact code this score is about.
  • Scored under rubric-2026.09.15 — the same rubric and the same method as every other entry in this index.
  • Measured by watchdog.canine.dev using codehealth-analyzer preprod-13a154b7f5d1.