Security Classification
Three tiers: PUBLIC (plaintext), SENSITIVE (encrypted), SERVER (never sent). Prefix-based — no ambiguity.
Every frontend framework resolves environment variables at build time via static string replacement. The resulting bundle is environment-specific — a bundle built for staging cannot be reused in production without rebuilding.
Containers are designed to be environment-agnostic artifacts, but frontend builds are environment-specific artifacts.
This means: one image per environment, broken CI/CD promotion, config changes require redeployment, and no security model for variables.
REP operates at the infrastructure layer — no build-tool plugins, no framework coupling. A lightweight Go gateway binary reads environment variables at container startup, classifies them by security tier, and injects them into HTML responses.
Security Classification
Three tiers: PUBLIC (plaintext), SENSITIVE (encrypted), SERVER (never sent). Prefix-based — no ambiguity.
Encrypted Variables
Sensitive vars are AES-256-GCM encrypted. Decrypted via single-use, rate-limited session keys.
Integrity Verification
HMAC-SHA256 integrity token + SRI hashing on every payload. Detect tampering in transit.
Hot Reload
Config changes push to the browser via SSE — no page reload, no redeployment.
| Approach | Security Model | Encrypted Vars | Integrity Check | Framework Agnostic | Standalone Binary |
|---|---|---|---|---|---|
envsubst / sed on bundles | — | — | — | Yes | — |
Fetch /config.json | — | — | — | Yes | — |
window.__ENV__ via shell script | — | — | — | Partial | — |
| Build-tool plugins | — | — | — | — | — |
| REP | 3-tier | AES-256-GCM | HMAC + SRI | Yes | ~3MB Go |
Container boot → Gateway reads REP_* env vars → Classifies → Encrypts sensitive → Signs payload
Request: Browser → [REP Gateway :8080] → [Upstream :80] HTML responses get <script id="__rep__"> injected before </head> All other responses pass through unmodifiedimport { rep } from '@rep-protocol/sdk';
// Synchronous — no loading state neededconst apiUrl = rep.get('API_URL');const flags = rep.get('FEATURE_FLAGS');
// Encrypted — decrypted on demandconst key = await rep.getSecure('ANALYTICS_KEY');
// Hot reload — react to config changesrep.onChange('FEATURE_FLAGS', (newValue) => { console.log('Flags updated:', newValue);});# Same image, different configservices: frontend-staging: image: myapp:latest environment: REP_PUBLIC_API_URL: "https://api.staging.example.com" REP_SENSITIVE_ANALYTICS_KEY: "UA-XXXXX-staging" REP_SERVER_INTERNAL_SECRET: "never-reaches-browser"
frontend-prod: image: myapp:latest # SAME IMAGE environment: REP_PUBLIC_API_URL: "https://api.example.com" REP_SENSITIVE_ANALYTICS_KEY: "UA-XXXXX-prod" REP_SERVER_INTERNAL_SECRET: "also-never-reaches-browser"# PUBLIC — plaintext in page source, rep.get()REP_PUBLIC_API_URL=https://api.example.com
# SENSITIVE — encrypted, await rep.getSecure()REP_SENSITIVE_ANALYTICS_KEY=UA-12345-1
# SERVER — never leaves the gateway processREP_SERVER_DB_PASSWORD=never-reaches-browserGateway
Go binary (~3MB). Zero dependencies. FROM scratch compatible. Proxy or embedded mode.
SDK
TypeScript. Zero runtime deps. ~1.5KB gzipped. Synchronous get(), async getSecure().
CLI
rep validate, rep typegen, rep lint, rep dev. Full development workflow.
Adapters
First-party React, Vue, and Svelte adapters with hot-reload-aware hooks/stores.
| Document | Status | Version |
|---|---|---|
| REP-RFC-0001 | Active | 0.1.0 |
| Security Model | Active | 0.1.0 |
| Conformance | Active | 0.1.0 |
Specification documents are licensed under CC BY 4.0. Code is licensed under Apache 2.0.