Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node-linker=hoisted
4 changes: 2 additions & 2 deletions examples/astro-example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@
"@astrojs/node": "^9.5.0",
"@astrojs/vercel": "^9.0.0",
"@astrojs/vue": "^5.1.2",
"@varlock/astro-integration": "^0.1.0",
"@varlock/astro-integration": "^0.2.3",
"astro": "^5.15.3",
"typescript": "^5.9.3",
"varlock": "^0.1.3",
"varlock": "^0.4.0",
"vue": "^3.5.22",
"wrangler": "^4.45.3"
}
Expand Down
2 changes: 1 addition & 1 deletion examples/basic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"license": "ISC",
"dependencies": {
"dotenv": "^17.2.3",
"varlock": "^0.1.3"
"varlock": "^0.4.0"
},
"packageManager": "pnpm@10.14.0",
"devDependencies": {
Expand Down
4 changes: 2 additions & 2 deletions examples/cf-worker-basic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
},
"devDependencies": {
"@cloudflare/vite-plugin": "^1.16.0",
"@varlock/vite-integration": "^0.1.0",
"varlock": "^0.1.3",
"@varlock/vite-integration": "^0.2.3",
"varlock": "^0.4.0",
"vite": "^7.2.6",
"wrangler": "^4.52.0"
}
Expand Down
8 changes: 8 additions & 0 deletions examples/expo/.env.schema
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# @defaultSensitive=false
# ---

APP_NAME=Varlock Expo Example
API_URL=https://api.example.com

# @sensitive
SECRET_KEY=super-secret-key-12345
5 changes: 5 additions & 0 deletions examples/expo/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.expo
dist
node_modules
expo-env.d.ts
.yalc
32 changes: 32 additions & 0 deletions examples/expo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Varlock + Expo Example

A minimal [Expo](https://expo.dev) app demonstrating [varlock](https://varlock.dev) integration with:

- **Babel plugin** — replaces non-sensitive `ENV.xxx` references at compile time
- **Metro config wrapper** — initializes the `ENV` proxy for server routes (`+api` files)
- **Sensitive value protection** — `@sensitive` values are only accessible in server routes, never inlined into the client bundle
- **Console log redaction** — sensitive values are automatically redacted from logs

## Setup

```bash
npm install
npx expo start --web
```

> **Note:** Expo's Metro bundler does not work well with pnpm's default `isolated` linker. If using pnpm, add `node-linker=hoisted` to your `.npmrc`. See the [Expo docs on monorepos](https://docs.expo.dev/guides/monorepos/) for details.

## What's inside

| File | Purpose |
|---|---|
| `.env.schema` | Defines `APP_NAME`, `API_URL` (non-sensitive) and `SECRET_KEY` (sensitive) |
| `babel.config.js` | Registers the varlock Babel plugin |
| `metro.config.js` | Wraps Metro config with `withVarlockMetroConfig` |
| `app/index.tsx` | Home screen showing inlined values and interactive demos |
| `app/env+api.ts` | Server route that accesses sensitive values via the `ENV` proxy |

## Learn more

- [Varlock Expo integration docs](https://varlock.dev/integrations/expo/)
- [Expo Router API routes](https://docs.expo.dev/router/reference/api-routes/)
14 changes: 14 additions & 0 deletions examples/expo/app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"expo": {
"name": "varlock-expo-example",
"slug": "varlock-expo-example",
"scheme": "varlock-expo-example",
"web": {
"bundler": "metro",
"output": "server"
},
"experiments": {
"typedRoutes": true
}
}
}
5 changes: 5 additions & 0 deletions examples/expo/app/_layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { Stack } from 'expo-router';

export default function RootLayout() {
return <Stack screenOptions={{ title: 'Varlock Expo Example' }} />;
}
37 changes: 37 additions & 0 deletions examples/expo/app/env+api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { ENV } from 'varlock/env';

/**
* Server-only API route that demonstrates sensitive ENV access.
*
* GET — returns env metadata (sensitive values available but not exposed)
* POST — logs SECRET_KEY via console.log and captures the redacted output
*
* Try it: curl http://localhost:8081/env
*/
export function GET() {
return Response.json({
apiUrl: ENV.API_URL,
secretKeyAvailable: !!ENV.SECRET_KEY,
secretKeyPreview: ENV.SECRET_KEY
? `${String(ENV.SECRET_KEY).slice(0, 6)}...`
: null,
});
}

export function POST() {
const logged: string[] = [];
const origLog = console.log;
console.log = (...args: unknown[]) => {
logged.push(args.map(String).join(' '));
origLog(...args);
};

console.log('The secret key is:', ENV.SECRET_KEY);

console.log = origLog;

return Response.json({
rawValue: `${String(ENV.SECRET_KEY).slice(0, 4)}**** (truncated for demo)`,
consoleOutput: logged,
});
}
107 changes: 107 additions & 0 deletions examples/expo/app/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { useState } from 'react';
import { View, Text, Pressable, StyleSheet } from 'react-native';
import { ENV } from 'varlock/env';

export default function HomeScreen() {
const [serverResponse, setServerResponse] = useState<string | null>(null);
const [clientError, setClientError] = useState<string | null>(null);
const [logResult, setLogResult] = useState<string | null>(null);

async function callServerRoute() {
try {
const res = await fetch('/env');
const data = await res.json();
setServerResponse(JSON.stringify(data, null, 2));
} catch (err) {
setServerResponse(`Error: ${err}`);
}
}

async function tryLogSensitiveVar() {
try {
const res = await fetch('/env', { method: 'POST' });
const data = await res.json();
setLogResult(JSON.stringify(data, null, 2));
} catch (err) {
setLogResult(`Error: ${err}`);
}
}

function tryAccessSensitiveVar() {
try {
const value = ENV.SECRET_KEY;
setClientError(`Unexpectedly got: ${value}`);
} catch (err) {
setClientError(String(err));
}
}

return (
<View style={styles.container}>
<Text style={styles.title}>{ENV.APP_NAME}</Text>

<View style={styles.section}>
<Text style={styles.heading}>Non-sensitive (inlined at build time)</Text>
<Text style={styles.value}>APP_NAME: {ENV.APP_NAME}</Text>
<Text style={styles.value}>API_URL: {ENV.API_URL}</Text>
</View>

<View style={styles.section}>
<Text style={styles.heading}>Sensitive (server route only)</Text>
<Text style={styles.hint}>
SECRET_KEY is @sensitive — it is NOT available in native code.
Tap below to fetch it from the +api server route.
</Text>
<Pressable style={styles.button} onPress={callServerRoute}>
<Text style={styles.buttonText}>Fetch /env from server</Text>
</Pressable>
{serverResponse && (
<Text style={styles.code}>{serverResponse}</Text>
)}
</View>

<View style={styles.section}>
<Text style={styles.heading}>Console log redaction</Text>
<Text style={styles.hint}>
varlock patches console.log to redact sensitive values. Tap below
to log SECRET_KEY on the server and see the redacted output.
</Text>
<Pressable style={[styles.button, styles.purpleButton]} onPress={tryLogSensitiveVar}>
<Text style={styles.buttonText}>Log SECRET_KEY on server</Text>
</Pressable>
{logResult && (
<Text style={styles.code}>{logResult}</Text>
)}
</View>

<View style={styles.section}>
<Text style={styles.heading}>What happens if you try on the client?</Text>
<Text style={styles.hint}>
Accessing a @sensitive var in client code throws at runtime.
Tap below to see the error.
</Text>
<Pressable style={[styles.button, styles.dangerButton]} onPress={tryAccessSensitiveVar}>
<Text style={styles.buttonText}>Try ENV.SECRET_KEY on client</Text>
</Pressable>
{clientError && (
<Text style={styles.errorCode}>{clientError}</Text>
)}
</View>
</View>
);
}

const styles = StyleSheet.create({
container: { flex: 1, padding: 24, backgroundColor: '#f8f9fa' },
title: { fontSize: 24, fontWeight: '700', marginBottom: 24 },
section: { marginBottom: 24, padding: 16, backgroundColor: '#fff', borderRadius: 8 },
heading: { fontSize: 16, fontWeight: '600', marginBottom: 8 },
value: { fontSize: 14, fontFamily: 'monospace', color: '#333', marginBottom: 4 },
hint: { fontSize: 13, color: '#666', marginBottom: 12 },
button: { backgroundColor: '#0066ff', paddingVertical: 10, paddingHorizontal: 16, borderRadius: 6, alignSelf: 'flex-start' },
buttonText: { color: '#fff', fontWeight: '600' },
code: { marginTop: 12, fontSize: 12, fontFamily: 'monospace', backgroundColor: '#f0f0f0', padding: 12, borderRadius: 4 },
purpleButton: { backgroundColor: '#7c3aed' },
dangerButton: { backgroundColor: '#cc3333' },
errorCode: { marginTop: 12, fontSize: 12, fontFamily: 'monospace', backgroundColor: '#fff0f0', color: '#cc0000', padding: 12, borderRadius: 4 },
});
9 changes: 9 additions & 0 deletions examples/expo/babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module.exports = function (api) {
api.cache(true);
return {
presets: ['babel-preset-expo'],
plugins: [
require('@varlock/expo-integration/babel-plugin'),
],
};
};
6 changes: 6 additions & 0 deletions examples/expo/metro.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const { getDefaultConfig } = require('expo/metro-config');
const { withVarlockMetroConfig } = require('@varlock/expo-integration/metro-config');

const config = getDefaultConfig(__dirname);

module.exports = withVarlockMetroConfig(config);
31 changes: 31 additions & 0 deletions examples/expo/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"name": "varlock-expo-example",
"private": true,
"version": "0.0.0",
"main": "expo-router/entry",
"scripts": {
"start": "expo start",
"start:web": "expo start --web"
},
"dependencies": {
"@varlock/expo-integration": "^0.0.0",
"expo": "~52.0.0",
"expo-constants": "~17.0.0",
"expo-linking": "~7.0.0",
"expo-router": "~4.0.0",
"expo-status-bar": "~2.0.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-native": "~0.76.0",
"react-native-safe-area-context": "~4.12.0",
"react-native-screens": "~4.4.0",
"react-native-web": "~0.19.0",
"varlock": "^0.4.0"
},
"devDependencies": {
"@babel/core": "^7.25.0",
"@babel/runtime": "^7.25.0",
"@types/react": "~18.3.0",
"typescript": "~5.6.0"
}
}
12 changes: 12 additions & 0 deletions examples/expo/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"extends": "expo/tsconfig.base",
"compilerOptions": {
"strict": true
},
"include": [
"**/*.ts",
"**/*.tsx",
".expo/types/**/*.ts",
"expo-env.d.ts"
]
}
2 changes: 1 addition & 1 deletion examples/init-sample-test/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"license": "ISC",
"dependencies": {
"@clack/prompts": "^0.11.0",
"varlock": "^0.1.3"
"varlock": "^0.4.0"
},
"packageManager": "pnpm@10.14.0"
}
2 changes: 1 addition & 1 deletion examples/init-test/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"license": "ISC",
"dependencies": {
"@clack/prompts": "^0.11.0",
"varlock": "^0.1.3"
"varlock": "^0.4.0"
},
"packageManager": "pnpm@10.14.0"
}
4 changes: 2 additions & 2 deletions examples/next-with-turbopack/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@
"lint": "eslint"
},
"dependencies": {
"@varlock/nextjs-integration": "^0.1.1",
"@varlock/nextjs-integration": "^0.2.2",
"next": "16.0.4",
"react": "19.2.0",
"react-dom": "19.2.0",
"varlock": "^0.1.3"
"varlock": "^0.4.0"
},
"devDependencies": {
"@tailwindcss/postcss": "^4",
Expand Down
4 changes: 2 additions & 2 deletions examples/qwik/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"@builder.io/qwik-city": "^1.15.0",
"@eslint/js": "latest",
"@types/node": "24.1.0",
"@varlock/vite-integration": "^0.1.0",
"@varlock/vite-integration": "^0.2.3",
"eslint": "9.32.0",
"eslint-plugin-qwik": "^1.15.0",
"globals": "16.3.0",
Expand All @@ -36,7 +36,7 @@
"typescript-eslint": "8.38.0",
"typescript-plugin-css-modules": "latest",
"undici": "*",
"varlock": "^0.1.3",
"varlock": "^0.4.0",
"vite": "7.0.6",
"vite-tsconfig-paths": "^5.1.4"
}
Expand Down
4 changes: 2 additions & 2 deletions examples/sveltekit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"test": "npm run test:unit -- --run"
},
"dependencies": {
"varlock": "^0.1.3"
"varlock": "^0.4.0"
},
"devDependencies": {
"@eslint/compat": "^1.4.0",
Expand All @@ -25,7 +25,7 @@
"@sveltejs/kit": "^2.48.5",
"@sveltejs/vite-plugin-svelte": "^6.2.1",
"@types/node": "^24",
"@varlock/vite-integration": "^0.1.0",
"@varlock/vite-integration": "^0.2.3",
"@vitest/browser-playwright": "^4.0.10",
"eslint": "^9.39.1",
"eslint-plugin-svelte": "^3.13.0",
Expand Down
4 changes: 2 additions & 2 deletions examples/vite-basic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
"preview": "APP_ENV=production vite preview"
},
"devDependencies": {
"@varlock/vite-integration": "^0.1.0",
"@varlock/vite-integration": "^0.2.3",
"typescript": "^5.9.3",
"varlock": "^0.1.3",
"varlock": "^0.4.0",
"vite": "^7.0.6"
},
"dependencies": {
Expand Down
Loading