Skip to content

Latest commit

 

History

History
288 lines (226 loc) · 5.49 KB

File metadata and controls

288 lines (226 loc) · 5.49 KB

Getting Started

Installation

npm install @nightnetwork/enigma

Dependencies

npm install @mercuryworkshop/bare-mux @mercuryworkshop/epoxy-transport

Setup

HTML

<!DOCTYPE html>
<html>
<head>
  <title>Enigma Demo</title>
</head>
<body>
  <script src="/baremux/bare-mux.js"></script>
  <script type="module" src="app.js"></script>
</body>
</html>

Initialize

const connection = new window.BareMux.BareMuxConnection('/baremux/worker.js');

await connection.setTransport('/enigma/index.mjs', [{
  base: '/epoxy/index.mjs',
  wisp: 'wss://wisp.example.com/',
  modules: []
}]);

Load Modules

By Path

await connection.setTransport('/enigma/index.mjs', [{
  base: '/epoxy/index.mjs',
  wisp: 'wss://wisp.example.com/',
  modules: ['/modules/logger.mjs']
}]);

With Options

await connection.setTransport('/enigma/index.mjs', [{
  base: '/epoxy/index.mjs',
  wisp: 'wss://wisp.example.com/',
  modules: [
    {
      path: '/modules/logger.mjs',
      options: { verbose: true }
    }
  ]
}]);

Multiple Modules

await connection.setTransport('/enigma/index.mjs', [{
  base: '/epoxy/index.mjs',
  wisp: 'wss://wisp.example.com/',
  modules: [
    '/modules/auth.mjs',
    { path: '/modules/logger.mjs', options: { verbose: true } },
    '/modules/cache.mjs'
  ]
}]);

Create a Module

Create modules/logger.mjs:

export const MODULE_ID = 'com.example.logger';

export function createLoggerModule(options = {}) {
  const verbose = options.verbose ?? false;

  return {
    id: MODULE_ID,
    name: 'Request Logger',
    version: '1.0.0',
    priority: 20,
    
    capabilities: {
      requestInterception: true,
      responseInterception: true
    },
    
    hooks: {
      onBeforeRequest: async (ctx, next) => {
        console.log('→', ctx.method, ctx.remote.href);
        return await next();
      },

      onAfterResponse: async (ctx, next) => {
        const response = await next();
        console.log('←', response.status, ctx.remote.href);
        return response;
      }
    }
  };
}

export default createLoggerModule;

Module Structure

export const MODULE_ID = 'com.company.module';

export function createModule(options = {}) {
  return {
    id: MODULE_ID,
    name: 'Module Name',
    version: '1.0.0',
    priority: 50,
    
    capabilities: {
      requestInterception: boolean,
      responseInterception: boolean,
      websocketInterception: boolean,
      protocolModification: boolean
    },
    
    hooks: {
      onModuleInit: async () => {},
      onTransportInit: async (innerTransport) => {},
      onBeforeRequest: async (ctx, next) => await next(),
      onAfterResponse: async (ctx, next) => await next(),
      onWebSocketConnect: async (ctx, handlers, next) => next(),
      onWebSocketMessage: (data, direction, url) => data,
      provideMeta: () => ({})
    }
  };
}

export default createModule;

Hook Reference

onModuleInit()

Called when module loads.

onModuleInit: async () => {
  console.log('Module initialized');
}

onTransportInit(innerTransport)

Called when base transport is ready.

onTransportInit: async (innerTransport) => {
  console.log('Transport ready');
}

onBeforeRequest(ctx, next)

Intercept requests. Context has:

  • ctx.remote - URL object
  • ctx.method - HTTP method
  • ctx.body - Request body
  • ctx.headers - BareHeaders
  • ctx.signal - AbortSignal
onBeforeRequest: async (ctx, next) => {
  ctx.headers.set('X-Custom', 'value');
  return await next();
}

onAfterResponse(ctx, next)

Intercept responses. Context has:

  • ctx.remote - URL object
  • ctx.body - ReadableStream | ArrayBuffer | Blob | string
  • ctx.headers - BareHeaders
  • ctx.status - Status code
  • ctx.statusText - Status text
onAfterResponse: async (ctx, next) => {
  const response = await next();
  console.log('Status:', response.status);
  return response;
}

onWebSocketConnect(ctx, handlers, next)

Intercept WebSocket connections. Context has:

  • ctx.url - URL object
  • ctx.protocols - string[]
  • ctx.requestHeaders - BareHeaders
onWebSocketConnect: async (ctx, handlers, next) => {
  console.log('WS connecting:', ctx.url.href);
  return next();
}

onWebSocketMessage(data, direction, url)

Transform WebSocket messages.

onWebSocketMessage: (data, direction, url) => {
  console.log(`WS ${direction}:`, data);
  return data;
}

provideMeta()

Expose module metadata.

provideMeta: () => ({
  requestCount: 42
})

Priority System

Priority Use Case
90-100 Protocol modification
80-89 Security
50-79 Middleware
40-49 Caching
10-39 Logging

Complete Example

<!DOCTYPE html>
<html>
<head>
  <title>Enigma Demo</title>
</head>
<body>
  <button id="test">Test</button>
  
  <script src="/baremux/bare-mux.js"></script>
  <script type="module">
    const connection = new window.BareMux.BareMuxConnection('/baremux/worker.js');
    
    await connection.setTransport('/enigma/index.mjs', [{
      base: '/epoxy/index.mjs',
      wisp: 'wss://wisp.example.com/',
      modules: ['/modules/logger.mjs']
    }]);
    
    console.log('Ready!');
    
    document.getElementById('test').onclick = async () => {
      const res = await fetch('https://example.com');
      console.log('Response:', res.status);
    };
  </script>
</body>
</html>