<!-- Markdown mirror of https://justscale.sh/docs/advanced/plugins -->

# Plugins

Extend JustScale with custom transports and plugins

JustScale's plugin system allows you to extend the framework with custom route factories, transports, and integrations. The core framework is transport-agnostic - HTTP, gRPC, WebSockets, and other protocols are implemented as plugins.

## Understanding the Plugin System

JustScale uses TypeScript's module augmentation and a registry-based approach to extend functionality. Plugins can:

- Add new route factory methods (like Get, Post, etc.)
- Extend the route context with transport-specific properties
- Register as cluster transports for protocol-specific serving
- Hook into the app lifecycle for initialization

## Creating Custom Route Factories

Route factories provide the DSL for defining routes. The HTTP plugin provides `Get`, `Post`, etc. You can create your own.

Files

srcpluginssse.ts

controllersevents.ts

srcpluginssse.ts

controllersevents.ts

src/plugins/sse.tsTypeScript

```typescript
import type { RouteHandler, RouteMethod } from "@justscale/core/plugin";
import { registerRouteFactory } from "@justscale/core/plugin";

// Step 1: Augment the RouteFactories interface
declare module "@justscale/core/plugin" {
  interface RouteFactories<TDeps> {
    // Add your custom route factory method
    SSE(path: string): SseRouteBuilder<TDeps>;
  }
}

// Step 2: Create the factory implementation
function createSseFactory() {
  return function SSE<TDeps, TPath extends string>(
    path: TPath
  ): SseRouteBuilder<TDeps, TPath> {
    return {
      handle(handler) {
        return {
          method: "GET",
          path,
          middlewares: [],
          guards: [],
          handler: async (ctx) => {
            // Set up SSE headers
            ctx.res.setHeader("Content-Type", "text/event-stream");
            ctx.res.setHeader("Cache-Control", "no-cache");
            ctx.res.setHeader("Connection", "keep-alive");

            // Create event stream
            const stream = new EventStream(ctx.res);
            await handler({ ...ctx, stream });
          },
        };
      },
    };
  };
}

// Register the factory
registerRouteFactory("SSE", createSseFactory());
```

## Extending Route Context

Plugins can add transport-specific properties to route handlers by augmenting the `RouteContext` interface.

http-context.tsTypeScript

```typescript
import type { ServerResponse, IncomingMessage } from "http";

declare module "@justscale/core/plugin" {
  interface RouteContext<TDeps, TParams> {
    // Add HTTP-specific properties
    res: ServerResponse;
    req: IncomingMessage;
    // These are now available in all route handlers
  }
}
```

The HTTP plugin uses this to add `res` and `req`. Your handlers can then access these properties with full type safety.

## Creating Cluster Transports

Cluster transports integrate with `JustScale().build()` to handle protocol-specific serving. The HTTP transport is a good example.

Files

srcpluginsgrpc-transport.ts

index.ts

srcpluginsgrpc-transport.ts

index.ts

src/plugins/grpc-transport.tsTypeScript

```typescript
import { registerClusterTransport } from "@justscale/core/cluster";
import type { ClusterTransportPlugin } from "./types";

const GrpcTransport: ClusterTransportPlugin = {
  name: "grpc",

  beforeControllerResolution(container, controllers) {
    // Register gRPC-specific services
    // e.g., reflection service, interceptors
  },

  onAppCreated(app) {
    // Optional: post-creation setup
  },

  async serve(app, config) {
    const server = new GrpcServer();

    // Register routes from app.controllers
    for (const controller of app.controllers) {
      for (const route of controller.routes) {
        server.register(route);
      }
    }

    await server.listen(config.port);

    return {
      stop: async () => {
        await server.close();
      },
    };
  },
};

// Register the transport
registerClusterTransport("grpc", GrpcTransport);
```

## Real-World Example: HTTP Plugin

The `@justscale/http` package is a complete plugin implementation. Here's how it's structured:

http-plugin.tsTypeScript

```typescript
import { registerRouteFactory } from "@justscale/core/plugin";
import { registerClusterTransport } from "@justscale/core/cluster";
import { Get, Post, Put, Delete, Patch } from "./factory";
import { HttpTransport } from "./transport";

// 1. Augment route factories
declare module "@justscale/core/plugin" {
  interface RouteFactories<TDeps> {
    Get: HttpFactory<TDeps>;
    Post: HttpFactory<TDeps>;
    Put: HttpFactory<TDeps>;
    Delete: HttpFactory<TDeps>;
    Patch: HttpFactory<TDeps>;
  }
}

// 2. Augment route context
declare module "@justscale/core/plugin" {
  interface RouteContext<TDeps, TParams> {
    res: JsonResponse;
    req: IncomingMessage;
  }
}

// 3. Register factories
registerRouteFactory("Get", Get);
registerRouteFactory("Post", Post);
registerRouteFactory("Put", Put);
registerRouteFactory("Delete", Delete);
registerRouteFactory("Patch", Patch);

// 4. Register as cluster transport
registerClusterTransport("http", HttpTransport);
```

## Plugin Best Practices

- Use module augmentation for type safety - Always augment interfaces rather than using any
- Register early - Import and register plugins before creating your app
- Namespace your additions - Prefix custom context properties to avoid conflicts
- Document your plugin - Provide clear examples and type definitions
- Test in isolation - Use createStandaloneApp for plugin testing

ℹ️Info

**Pro Tip:** Study the source code of `@justscale/http` and `@justscale/datastar` for complete plugin examples. They demonstrate route factories, context augmentation, and cluster transport integration.

## Next Steps

- Type Utilities
- Debugging
- Request Handling
