# How Server-Side Providers Are Exposed in God’s Eye View: A Vite Plugin Architecture

> Learn how God's Eye View exposes server-side providers via Vite plugins. Discover route aggregation and injection into the Vite dev server.

- Repository: [Bilawal Sidhu/gods-eye-view](https://github.com/bilawalsidhu/gods-eye-view)
- Tags: architecture
- Published: 2026-09-13

---

**God’s Eye View exposes server-side providers as Vite plugins that register HTTP routes through the `configureServer` hook, aggregating them in [`server/providers/local.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/server/providers/local.js) and injecting them into the Vite dev server configuration.**

God’s Eye View (bilawalsidhu/gods-eye-view) implements a modular plugin system to expose server-side data sources. Instead of traditional route handlers, the application bundles providers as **Vite plugins** that proxy external APIs and internal data to the client. This architecture ensures clean separation between data sources and the application core while leveraging Vite's native server configuration hooks.

## The Provider Plugin Architecture

Providers in God's Eye View follow a consistent proxy pattern. Each **server-side provider** lives under `server/providers/` and exports a function that returns a Vite plugin object. This object implements the `configureServer` hook to register HTTP endpoints.

### Directory Structure and Provider Location

Individual providers are organized by domain under `server/providers/`. For example, aviation data resides in [`server/providers/aircraft/opensky.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/server/providers/aircraft/opensky.js), while traffic data might live in `server/providers/traffic/`. Each file exports a proxy function (e.g., `openSkyProxy()`, `tomtomProxy()`) that encapsulates the data fetching logic and route registration.

### The Central Aggregation Pattern

The file **[`server/providers/local.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/server/providers/local.js)** serves as the central registry. It exports `localProviderPlugins()`, an aggregation function that imports every individual provider module and returns them as an ordered array:

```javascript
function localProviderPlugins() {
  return [
    openSkyProxy(),
    celestrakProxy(),
    tomtomProxy(),
    firmsProxy(),
    /* … additional providers … */
    keySetupEndpoint(),
  ];
}
export { localProviderPlugins };

```

The **order of providers matters**. Later plugins may depend on configuration or tokens established by earlier plugins in the array.

## Vite Integration and Route Registration

The Vite development and production server is configured in **[`server/standalone/vite.config.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/server/standalone/vite.config.js)**. This file consumes the provider array and integrates it into the Vite plugin pipeline.

### Bootstrap Configuration in Vite

The configuration calls `createBrowserViteConfig` and spreads the `localProviderPlugins()` array into the `plugins` property:

```javascript
export default defineConfig(({ mode }) => {
  /* … environment variable loading … */
  return createBrowserViteConfig({
    plugins: [
      ...localProviderPlugins(),   // ← server-side providers injected here
      apiNotFoundPlugin(),
    ],
    googleApiKey: process.env.GOOGLE_MAPS_API_KEY,
    cesiumToken: process.env.CESIUM_ION_TOKEN,
    host: process.env.HOST,
    port: process.env.PORT,
  });
});

```

Vite treats each element of the `plugins` array as a plugin object. When the dev server starts, it executes the `configureServer` hook on each provider in sequence.

### Route Registration Implementation

Within a provider, the proxy function returns an object with a `name` and the `configureServer` method. This method receives the Vite server instance and attaches middleware routes. For example, in **[`server/providers/aircraft/opensky.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/server/providers/aircraft/opensky.js)**:

```javascript
export function openSkyProxy() {
  return {
    name: 'opensky-proxy',
    configureServer(server) {
      server.middlewares.use('/api/opensky', async (req, res) => {
        // fetch and process OpenSky data
        const result = await fetchOpenSkyData();
        res.setHeader('Content-Type', 'application/json');
        res.end(JSON.stringify(result));
      });
    },
  };
}

```

A request to `http://localhost:<port>/api/opensky` is now handled by this provider's middleware. Each provider defines its own base path (e.g., `/api/traffic`, `/api/cctv`) using `server.middlewares.use()`.

## Adding Custom Server-Side Providers

To expose a new data source, create a proxy module and register it in the aggregation array.

First, create the provider file (e.g., [`server/providers/example.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/server/providers/example.js)):

```javascript
export function exampleProxy() {
  return {
    name: 'example-proxy',
    configureServer(server) {
      server.middlewares.use('/api/example', async (req, res) => {
        const data = { hello: 'world', timestamp: Date.now() };
        res.setHeader('Content-Type', 'application/json');
        res.end(JSON.stringify(data));
      });
    },
  };
}

```

Then import and add it to **[`server/providers/local.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/server/providers/local.js)**:

```javascript
import { exampleProxy } from './example.js';

function localProviderPlugins() {
  return [
    openSkyProxy(),
    celestrakProxy(),
    exampleProxy(),           // ← custom provider added here
    keySetupEndpoint(),
  ];
}

```

After rebuilding the application, the endpoint `/api/example` will be live and accessible to the client.

## Summary

- **Provider Location**: Server-side providers are located in `server/providers/` and organized by domain (aircraft, traffic, cctv, etc.).
- **Aggregation Pattern**: [`server/providers/local.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/server/providers/local.js) exports `localProviderPlugins()`, which returns an ordered array of all provider proxy functions.
- **Vite Integration**: The Vite config in [`server/standalone/vite.config.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/server/standalone/vite.config.js) spreads the provider array into the `plugins` configuration.
- **Route Registration**: Each provider uses the `configureServer` hook to register routes via `server.middlewares.use()`, exposing endpoints like `/api/opensky`.
- **Ordering**: The sequence of providers in `localProviderPlugins()` determines middleware execution order and dependency resolution.

## Frequently Asked Questions

### What file controls the order of server-side providers in God's Eye View?

The file **[`server/providers/local.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/server/providers/local.js)** controls the order through its `localProviderPlugins` function. This function returns an array where the sequence matters—providers that set up shared configuration or tokens should appear before those that depend on them.

### How does a provider register HTTP endpoints in God's Eye View?

Providers register endpoints by returning a Vite plugin object with a **`configureServer`** hook. Inside this hook, they call `server.middlewares.use('/api/route', handler)` to attach Express-style middleware handlers to specific paths.

### Can I add custom data sources to God's Eye View?

Yes. Create a new file in `server/providers/` that exports a proxy function returning a plugin object with `configureServer`. Then import and add this function to the array returned by `localProviderPlugins()` in [`server/providers/local.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/server/providers/local.js).

### What happens if two providers register the same API route?

Vite processes middleware in the order defined by the `plugins` array. If two providers register identical routes, the **last registered provider** in the `localProviderPlugins()` array will handle the request, effectively overriding earlier registrations. Avoid duplicate routes to prevent unexpected behavior.