Development vs Production

Understand passthrough mode for development and production mode with 4Quays

The 4Quays SDK operates in two modes, determined entirely by configuration. This makes local development simple while ensuring production security.

The Two Modes

Passthrough Mode (Development)

When no 4Quays endpoint is configured, the SDK operates in passthrough mode:

  • protect() returns the payload unchanged
  • unprotect() returns the payload unchanged
  • No network calls to 4Quays
  • No API key required
// No endpoint configured = passthrough mode
const fourq = new FourQ({
  endpoint: undefined,  // or omit entirely
  apiKey: undefined,
});

const payload = { amount: 1000 };
const result = await fourq.protect(payload, 'ANY-POLICY');

console.log(result === payload); // true (in passthrough mode)

Production Mode

When a 4Quays endpoint is configured, the SDK routes operations through the platform:

  • protect() calls 4Quays API and returns encrypted payload
  • unprotect() calls 4Quays API and returns decrypted payload
  • Requires valid API key
  • All operations are audited
// Endpoint configured = production mode
const fourq = new FourQ({
  endpoint: 'https://api.4quays.com',
  apiKey: 'sk_live_xxxxx',
});

const payload = { amount: 1000 };
const result = await fourq.protect(payload, 'BANK-POLICY');

console.log(result === payload); // false (encrypted)

Why Passthrough Mode?

Passthrough mode enables:

  1. Local development without infrastructure — No 4Quays platform needed during development
  2. Write once, run anywhere — Same code works in dev and prod
  3. Test business logic first — Focus on application logic, add crypto later
  4. Team independence — Developers don't need security team for local work

Configuration Patterns

Environment-Based Switching

Use environment variables to switch modes:

# .env.development
# FOURQ_ENDPOINT= (not set = passthrough)
# FOURQ_API_KEY= (not set = passthrough)

# .env.production
FOURQ_ENDPOINT=https://api.4quays.com
FOURQ_API_KEY=sk_live_xxxxx
const fourq = new FourQ({
  endpoint: process.env.FOURQ_ENDPOINT,
  apiKey: process.env.FOURQ_API_KEY,
});

Explicit Mode Checking

Check which mode is active:

const health = await fourq.checkHealth();

if (health.mode === 'passthrough') {
  console.log('Running in development mode');
} else {
  console.log('Connected to 4Quays:', health.latencyMs, 'ms');
}

Development Workflow

Step 1: Write Code with SDK

During development, write your integration using the SDK:

async function processTransfer(transferData) {
  // Protect payload (passthrough in dev)
  const protected = await fourq.protect(
    transferData,
    'BANK-TRANSFER-POLICY'
  );

  // Send to bank API
  const response = await bankApi.submitTransfer(protected);

  return response;
}

Step 2: Test Without 4Quays

Run your tests without any 4Quays infrastructure:

test('transfer processing', async () => {
  const result = await processTransfer({
    amount: 1000,
    destination: 'CA1234567890'
  });

  expect(result.status).toBe('accepted');
});

In passthrough mode, the bank API receives plaintext — this may result in rejections from services that require encryption. That's expected during development.

Step 3: Deploy to Staging

Configure staging environment with 4Quays:

# staging.env
FOURQ_ENDPOINT=https://staging-api.4quays.com
FOURQ_API_KEY=sk_test_xxxxx

Now the same code protects payloads properly.

Step 4: Deploy to Production

Configure production environment:

# production.env
FOURQ_ENDPOINT=https://api.4quays.com
FOURQ_API_KEY=sk_live_xxxxx

Zero code changes between environments.

Testing Considerations

Unit Tests

For unit tests, passthrough mode is usually sufficient:

// fourq.mock.js
export const fourq = new FourQ({
  endpoint: undefined,  // passthrough
});

Integration Tests

For integration tests against external services, you may need a test 4Quays environment:

// fourq.test.js
export const fourq = new FourQ({
  endpoint: process.env.FOURQ_TEST_ENDPOINT,
  apiKey: process.env.FOURQ_TEST_API_KEY,
});

Mocking 4Quays

You can also mock the SDK entirely:

jest.mock('@4quays/sdk', () => ({
  FourQ: jest.fn().mockImplementation(() => ({
    protect: jest.fn().mockResolvedValue({ encrypted: true }),
    unprotect: jest.fn().mockResolvedValue({ decrypted: true }),
    checkHealth: jest.fn().mockResolvedValue({ mode: 'mock' }),
  })),
}));

Debugging Mode Behavior

When debugging, log the current mode:

const fourq = new FourQ({
  endpoint: process.env.FOURQ_ENDPOINT,
  apiKey: process.env.FOURQ_API_KEY,
});

const health = await fourq.checkHealth();
console.log(`4Quays mode: ${health.mode}`);
console.log(`Latency: ${health.latencyMs}ms`);

Common Patterns

Conditional Logging

const result = await fourq.protect(payload, 'POLICY');

if (process.env.NODE_ENV === 'development') {
  // Safe to log in dev (passthrough = plaintext)
  console.log('Payload:', result);
} else {
  // Don't log encrypted content in prod
  console.log('Payload protected');
}

Fallback Behavior

async function protectWithFallback(payload, policy) {
  try {
    return await fourq.protect(payload, policy);
  } catch (error) {
    if (process.env.NODE_ENV === 'development') {
      console.warn('4Quays unavailable, using passthrough');
      return payload;
    }
    throw error;
  }
}

What's Next