diff --git a/plugins/vite/README.md b/plugins/vite/README.md
new file mode 100644
index 0000000..60eec6a
--- /dev/null
+++ b/plugins/vite/README.md
@@ -0,0 +1,131 @@
+# @rep-protocol/vite
+
+Vite plugin for the [Runtime Environment Protocol (REP)](https://github.com/RuachTech/rep). Injects REP environment variables during development without needing the Go gateway.
+
+In production, this plugin does nothing — the REP gateway handles variable injection (and, in `embedded` mode, also serves your built static files).
+
+## Install
+
+```bash
+pnpm add -D @rep-protocol/vite
+# or
+npm install -D @rep-protocol/vite
+```
+
+Peer dependency: `vite >= 4`.
+
+## Setup
+
+### 1. Add the plugin to `vite.config.ts`
+
+```ts
+// vite.config.ts
+import { defineConfig } from 'vite';
+import { repPlugin } from '@rep-protocol/vite';
+
+export default defineConfig({
+ plugins: [repPlugin()],
+});
+```
+
+The plugin is dev-only by construction: it injects the `` injection.
+- The dev session-key endpoint has no rate limiting or single-use semantics —
+ production deployments must use the REP gateway.
+
+## Troubleshooting
+
+### `404` / no `#__rep__` script in development
+
+Ensure `repPlugin()` is in your `vite.config.ts` `plugins` array and that your
+env file exists at the configured path (default `.env.local`, relative to the
+project root).
+
+### `REPError: SENSITIVE variable "X" not found in payload`
+
+The variable isn't set in your `.env.local`. If it's optional, catch the error:
+
+```ts
+const getOptionalKey = (): Promise =>
+ rep.getSecure('OPTIONAL_KEY').catch(() => '');
+```
+
+## License
+
+Apache-2.0
diff --git a/plugins/vite/package.json b/plugins/vite/package.json
index 6f5ddbb..c26e5db 100644
--- a/plugins/vite/package.json
+++ b/plugins/vite/package.json
@@ -34,7 +34,7 @@
"dist"
],
"scripts": {
- "build": "tsup src/index.ts --format cjs,esm --dts",
+ "build": "tsup",
"test": "vitest run",
"test:watch": "vitest",
"typecheck": "tsc --noEmit"
diff --git a/plugins/vite/src/index.ts b/plugins/vite/src/index.ts
index 26175cb..e26258f 100644
--- a/plugins/vite/src/index.ts
+++ b/plugins/vite/src/index.ts
@@ -1,12 +1,21 @@
-import { resolve, dirname } from 'node:path';
-import { readFileSync } from 'node:fs';
-import { fileURLToPath } from 'node:url';
+import { resolve } from 'node:path';
import type { Plugin, ViteDevServer, HtmlTagDescriptor } from 'vite';
import { generateKeys, type Keys } from './crypto.js';
import { readAndClassify, type ClassifiedVars } from './env.js';
import { scanValue } from './guardrails.js';
import { buildPayload, type PayloadResult } from './payload.js';
+// Injected at build time by tsup (see tsup.config.ts). Reading package.json at
+// runtime via import.meta.url is unreliable here: consumers import this plugin
+// inside vite.config.ts, which Vite bundles with esbuild — that rewrites
+// import.meta.url, so the runtime read fails and the version falls back to
+// 0.0.0. Baking the version in at build time avoids that entirely.
+declare const __REP_VITE_VERSION__: string;
+
+function getPackageVersion(): string {
+ return typeof __REP_VITE_VERSION__ === 'string' ? __REP_VITE_VERSION__ : '0.0.0';
+}
+
export interface RepPluginOptions {
/** Path to env file, relative to project root. Default: '.env.local' */
env?: string;
@@ -14,16 +23,6 @@ export interface RepPluginOptions {
strict?: boolean;
}
-function getPackageVersion(): string {
- try {
- const pkgPath = resolve(dirname(fileURLToPath(import.meta.url)), '..', 'package.json');
- const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
- return pkg.version;
- } catch {
- return '0.0.0';
- }
-}
-
export function repPlugin(options: RepPluginOptions = {}): Plugin {
const envFile = options.env ?? '.env.local';
const strict = options.strict ?? false;
diff --git a/plugins/vite/tsup.config.ts b/plugins/vite/tsup.config.ts
new file mode 100644
index 0000000..0fd756a
--- /dev/null
+++ b/plugins/vite/tsup.config.ts
@@ -0,0 +1,15 @@
+import { defineConfig } from 'tsup';
+import { readFileSync } from 'node:fs';
+
+const { version } = JSON.parse(readFileSync(new URL('./package.json', import.meta.url), 'utf-8'));
+
+export default defineConfig({
+ entry: ['src/index.ts'],
+ format: ['cjs', 'esm'],
+ dts: true,
+ // Bake the package version in at build time so it survives consumers that
+ // bundle their vite.config (which would otherwise rewrite import.meta.url).
+ define: {
+ __REP_VITE_VERSION__: JSON.stringify(version),
+ },
+});