Skip to content

Commit 7983061

Browse files
committed
docs(vite): add plugin README
1 parent 883d452 commit 7983061

1 file changed

Lines changed: 131 additions & 0 deletions

File tree

plugins/vite/README.md

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
# @rep-protocol/vite
2+
3+
Vite plugin for the [Runtime Environment Protocol (REP)](https://github.com/RuachTech/rep). Injects REP environment variables during development without needing the Go gateway.
4+
5+
In production, this plugin does nothing — the REP gateway handles variable injection (and, in `embedded` mode, also serves your built static files).
6+
7+
## Install
8+
9+
```bash
10+
pnpm add -D @rep-protocol/vite
11+
# or
12+
npm install -D @rep-protocol/vite
13+
```
14+
15+
Peer dependency: `vite >= 4`.
16+
17+
## Setup
18+
19+
### 1. Add the plugin to `vite.config.ts`
20+
21+
```ts
22+
// vite.config.ts
23+
import { defineConfig } from 'vite';
24+
import { repPlugin } from '@rep-protocol/vite';
25+
26+
export default defineConfig({
27+
plugins: [repPlugin()],
28+
});
29+
```
30+
31+
The plugin is dev-only by construction: it injects the `<script id="__rep__">`
32+
payload into `index.html` and serves the `/rep/session-key` endpoint while the
33+
Vite dev server runs. It does nothing during `vite build`.
34+
35+
#### Options
36+
37+
| Option | Type | Default | Description |
38+
| -------- | --------- | -------------- | ------------------------------------------- |
39+
| `env` | `string` | `".env.local"` | Path to env file, relative to project root. |
40+
| `strict` | `boolean` | `false` | Promote guardrail warnings to errors. |
41+
42+
### 2. Configure your `.env.local`
43+
44+
```env
45+
# PUBLIC tier — injected as plaintext in the <script> tag
46+
REP_PUBLIC_API_URL=http://localhost:8080
47+
REP_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
48+
49+
# SENSITIVE tier — AES-256-GCM encrypted in the <script> tag
50+
REP_SENSITIVE_SUPABASE_ANON_KEY=your_supabase_anon_key
51+
```
52+
53+
Variables are classified by prefix:
54+
55+
| Prefix | Tier | Client access |
56+
| ---------------- | --------- | ------------------------------------ |
57+
| `REP_PUBLIC_` | public | Plaintext in HTML |
58+
| `REP_SENSITIVE_` | sensitive | Encrypted, decrypted via session key |
59+
| `REP_SERVER_` | server | Never reaches the client |
60+
61+
### 3. Read variables on the client
62+
63+
Use [`@rep-protocol/sdk`](https://github.com/RuachTech/rep/tree/main/sdk):
64+
65+
```ts
66+
import { rep } from '@rep-protocol/sdk';
67+
68+
const apiUrl = rep.get('API_URL'); // PUBLIC — synchronous
69+
const anonKey = await rep.getSecure('SUPABASE_ANON_KEY'); // SENSITIVE — async
70+
```
71+
72+
## How it works
73+
74+
1. **`transformIndexHtml`** reads `.env.local`, classifies variables by prefix,
75+
encrypts sensitive vars with AES-256-GCM, and injects a
76+
`<script id="__rep__" type="application/json">` tag into `<head>`.
77+
2. **`@rep-protocol/sdk`** (`rep.get()` / `rep.getSecure()`) reads that script tag
78+
on the client to access variables.
79+
3. **The `/rep/session-key` middleware** serves the ephemeral decryption key so
80+
the SDK can decrypt sensitive vars in the browser. Both the payload and the
81+
session key use the same ephemeral keys generated when the dev server starts.
82+
4. **Env hot reload** — the plugin watches the env file and triggers a full page
83+
reload when it changes, so new values take effect without restarting Vite.
84+
5. **Guardrails** scan `PUBLIC` values for patterns that look like secrets (known
85+
prefixes like `ghp_`, `sk_live_`, high Shannon entropy, long opaque strings)
86+
and warn at dev time (or throw, with `strict: true`).
87+
88+
## Production
89+
90+
This plugin is for development only. In production, run the REP gateway in front
91+
of (or serving) your built `dist/`:
92+
93+
```sh
94+
# Embedded mode — the gateway serves the static SPA itself, injects the payload,
95+
# and serves /rep/session-key. No separate static server needed.
96+
rep-gateway --mode embedded --static-dir ./dist --port 8080
97+
```
98+
99+
The gateway reads `REP_PUBLIC_*` / `REP_SENSITIVE_*` from the container
100+
environment at request time, so the same build runs against any environment.
101+
102+
## Security
103+
104+
- `SERVER` tier variables never leave the server process.
105+
- `SENSITIVE` vars are AES-256-GCM encrypted with an ephemeral key regenerated on
106+
each dev-server restart.
107+
- JSON payloads are Go-escaped (`<` `>` `&``<` `>` `&`) to
108+
prevent `</script>` injection.
109+
- The dev session-key endpoint has no rate limiting or single-use semantics —
110+
production deployments must use the REP gateway.
111+
112+
## Troubleshooting
113+
114+
### `404` / no `#__rep__` script in development
115+
116+
Ensure `repPlugin()` is in your `vite.config.ts` `plugins` array and that your
117+
env file exists at the configured path (default `.env.local`, relative to the
118+
project root).
119+
120+
### `REPError: SENSITIVE variable "X" not found in payload`
121+
122+
The variable isn't set in your `.env.local`. If it's optional, catch the error:
123+
124+
```ts
125+
const getOptionalKey = (): Promise<string> =>
126+
rep.getSecure('OPTIONAL_KEY').catch(() => '');
127+
```
128+
129+
## License
130+
131+
Apache-2.0

0 commit comments

Comments
 (0)