> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/mercuryworkshop/scramjet/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> Get a working Scramjet proxy setup in minutes

# Quickstart

This guide will walk you through setting up a basic Scramjet proxy. You'll learn how to register a service worker, initialize the controller, and create a proxied iframe.

## Setup overview

A Scramjet proxy requires two main components:

1. **Service worker** - Intercepts and rewrites network requests
2. **Controller** - Manages frames and communicates with the service worker

<Steps>
  <Step title="Create the service worker">
    Create a file called `sw.js` in your static directory:

    ```javascript sw.js theme={null}
    importScripts("/scramjet/scramjet.all.js");

    const { ScramjetServiceWorker } = $scramjetLoadWorker();
    const scramjet = new ScramjetServiceWorker();

    async function handleRequest(event) {
      await scramjet.loadConfig();
      
      if (scramjet.route(event)) {
        return scramjet.fetch(event);
      }
      
      return fetch(event.request);
    }

    self.addEventListener("fetch", (event) => {
      event.respondWith(handleRequest(event));
    });
    ```

    <Note>
      This service worker intercepts all fetch requests. If a request matches Scramjet's routing (based on the configured prefix), it's proxied. Otherwise, it's passed through normally.
    </Note>
  </Step>

  <Step title="Set up your HTML page">
    Create an HTML page that will load Scramjet and register the service worker:

    ```html index.html theme={null}
    <!DOCTYPE html>
    <html>
      <head>
        <title>Scramjet Proxy</title>
      </head>
      <body>
        <div id="container"></div>
        <script src="/scramjet/scramjet.bundle.js"></script>
        <script src="/app.js"></script>
      </body>
    </html>
    ```
  </Step>

  <Step title="Initialize Scramjet controller">
    Create `app.js` to register the service worker and set up the controller:

    ```javascript app.js theme={null}
    // Load the Scramjet controller
    const { ScramjetController } = $scramjetLoadController();

    // Create a new controller instance
    const scramjet = new ScramjetController({
      prefix: "/scramjet/",
      codec: {
        encode: (url) => encodeURIComponent(url),
        decode: (url) => decodeURIComponent(url)
      },
      flags: {
        captureErrors: true,
        strictRewrites: true
      }
    });

    async function init() {
      // Register the service worker
      if ("serviceWorker" in navigator) {
        await navigator.serviceWorker.register("/sw.js", {
          scope: "/"
        });
        
        // Wait for the service worker to be ready
        await navigator.serviceWorker.ready;
      }
      
      // Initialize Scramjet
      await scramjet.init();
      
      // Create a proxied iframe
      const frame = scramjet.createFrame();
      document.getElementById("container").appendChild(frame.frame);
      
      // Navigate to a URL
      frame.go("https://example.com");
    }

    init();
    ```

    <Tip>
      The `prefix` option determines which URL paths are handled by Scramjet. In this example, any request to `/scramjet/*` will be proxied.
    </Tip>
  </Step>

  <Step title="Serve the static files">
    Make sure the Scramjet static files are available at the configured paths:

    * `/scramjet/scramjet.bundle.js`
    * `/scramjet/scramjet.all.js`
    * `/scramjet/scramjet.wasm.wasm`

    These files are in the `dist` directory of the `@mercuryworkshop/scramjet` package.
  </Step>

  <Step title="Test your setup">
    Start your web server and open the page in a browser. You should see example.com loaded in the iframe through the Scramjet proxy.
  </Step>
</Steps>

## Configuration options

The `ScramjetController` accepts several configuration options:

### Basic options

```javascript theme={null}
const scramjet = new ScramjetController({
  prefix: "/scramjet/",  // URL prefix for proxied requests
  codec: {
    encode: (url) => encodeURIComponent(url),
    decode: (url) => decodeURIComponent(url)
  },
  files: {
    wasm: "/scramjet.wasm.wasm",
    all: "/scramjet.all.js",
    sync: "/scramjet.sync.js"
  }
});
```

### Feature flags

Control Scramjet's behavior with flags:

<CodeGroup>
  ```javascript Recommended flags theme={null}
  const scramjet = new ScramjetController({
    prefix: "/scramjet/",
    flags: {
      strictRewrites: true,      // Enforce strict URL rewriting
      captureErrors: true,        // Capture and clean errors
      sourcemaps: true,          // Enable source map support
      allowInvalidJs: true       // Allow pages with invalid JS
    }
  });
  ```

  ```javascript All available flags theme={null}
  const scramjet = new ScramjetController({
    prefix: "/scramjet/",
    flags: {
      serviceworkers: false,         // Enable nested service workers
      syncxhr: false,                // Enable synchronous XHR
      strictRewrites: true,          // Enforce strict URL rewriting
      rewriterLogs: false,           // Enable rewriter debug logs
      captureErrors: true,           // Capture and clean errors
      cleanErrors: false,            // Clean error messages
      scramitize: false,             // Enable scramitize mode
      sourcemaps: true,              // Enable source map support
      destructureRewrites: false,    // Use destructuring in rewrites
      interceptDownloads: false,     // Intercept file downloads
      allowInvalidJs: true,          // Allow pages with invalid JS
      allowFailedIntercepts: true    // Continue on failed intercepts
    }
  });
  ```
</CodeGroup>

<Warning>
  Some flags like `syncxhr` and `serviceworkers` enable experimental features that may impact performance or compatibility.
</Warning>

## Working with frames

Scramjet provides a `ScramjetFrame` class for managing proxied iframes:

```javascript theme={null}
// Create a frame (Scramjet creates the iframe element)
const frame = scramjet.createFrame();
document.body.appendChild(frame.frame);

// Or use an existing iframe element
const existingIframe = document.getElementById("myframe");
const frame = scramjet.createFrame(existingIframe);

// Navigate to a URL
frame.navigate("https://example.com");
```

## URL encoding and decoding

You can encode and decode URLs using the controller:

```javascript theme={null}
// Encode a URL for use in the proxy
const proxiedUrl = scramjet.encodeUrl("https://example.com");
// Returns: "/scramjet/https%3A%2F%2Fexample.com"

// Decode a proxied URL back to the original
const originalUrl = scramjet.decodeUrl(proxiedUrl);
// Returns: "https://example.com"
```

## Using Workbox (optional)

For more advanced service worker routing, you can use Workbox:

```javascript sw.js theme={null}
importScripts("/scramjet/scramjet.all.js");
import { registerRoute } from "workbox-routing";

const { ScramjetServiceWorker } = $scramjetLoadWorker();
const scramjet = new ScramjetServiceWorker();

registerRoute(
  ({ request }) => {
    return scramjet.route({ request });
  },
  async ({ event }) => {
    await scramjet.loadConfig();
    return scramjet.fetch(event);
  }
);
```

<Tip>
  Workbox routing is useful if you're building a PWA with offline support alongside your proxy functionality.
</Tip>

## Next steps

Now that you have a working Scramjet setup, you can:

* Customize the codec to implement custom URL encoding schemes
* Add event listeners to handle navigation and downloads
* Configure site-specific flags for better compatibility
* Explore the TypeScript API documentation for advanced features

## Common issues

<Warning>
  If CAPTCHAs aren't working, make sure you're not hosting on a datacenter IP. Residential IPs work best for CAPTCHA-heavy sites like Google and YouTube.
</Warning>

<Note>
  Service workers require HTTPS in production environments (except for localhost). Make sure your site is served over HTTPS.
</Note>
