Skip to content
Merged
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
31 changes: 24 additions & 7 deletions cli/src/commands/typegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,19 +77,23 @@ function generateTypeDefinition(publicVars: string[], sensitiveVars: string[]):
lines.push(' export interface REP {');
lines.push(' /**');
lines.push(' * Get a PUBLIC tier variable value synchronously.');
lines.push(' * When called with a defaultValue the return type narrows to string.');
lines.push(' */');

if (publicVars.length > 0) {
lines.push(' get(key: ' + publicVars.map(v => `"${v}"`).join(' | ') + '): string | undefined;');
const keyUnion = publicVars.map(v => `"${v}"`).join(' | ');
lines.push(' get(key: ' + keyUnion + ', defaultValue: string): string;');
lines.push(' get(key: ' + keyUnion + ', defaultValue?: undefined): string | undefined;');
} else {
lines.push(' get(key: string): string | undefined;');
lines.push(' get(key: string, defaultValue: string): string;');
lines.push(' get(key: string, defaultValue?: undefined): string | undefined;');
}

lines.push('');
lines.push(' /**');
lines.push(' * Get a SENSITIVE tier variable value asynchronously.');
lines.push(' */');

if (sensitiveVars.length > 0) {
lines.push(' getSecure(key: ' + sensitiveVars.map(v => `"${v}"`).join(' | ') + '): Promise<string>;');
} else {
Expand Down Expand Up @@ -131,8 +135,21 @@ function generateTypeDefinition(publicVars: string[], sensitiveVars: string[]):
lines.push(' }');
lines.push('');
lines.push(' export const rep: REP;');
lines.push(' export function get(key: string): string | undefined;');
lines.push(' export function getSecure(key: string): Promise<string>;');

if (publicVars.length > 0) {
const keyUnion = publicVars.map(v => `"${v}"`).join(' | ');
lines.push(' export function get(key: ' + keyUnion + ', defaultValue: string): string;');
lines.push(' export function get(key: ' + keyUnion + ', defaultValue?: undefined): string | undefined;');
} else {
lines.push(' export function get(key: string, defaultValue: string): string;');
lines.push(' export function get(key: string, defaultValue?: undefined): string | undefined;');
}

if (sensitiveVars.length > 0) {
lines.push(' export function getSecure(key: ' + sensitiveVars.map(v => `"${v}"`).join(' | ') + '): Promise<string>;');
} else {
lines.push(' export function getSecure(key: string): Promise<string>;');
}
lines.push(' export function getAll(): Readonly<Record<string, string>>;');
lines.push(' export function onChange(key: string, callback: (newValue: string, oldValue: string | undefined) => void): () => void;');
lines.push(' export function onAnyChange(callback: (key: string, newValue: string, oldValue: string | undefined) => void): () => void;');
Expand Down
12 changes: 11 additions & 1 deletion docs/src/content/docs/reference/cli.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,23 @@ rep typegen [--manifest <path>] [--output <path>]
```typescript
declare module "@rep-protocol/sdk" {
export interface REP {
get(key: "API_URL" | "FEATURE_FLAGS"): string | undefined;
// Overloaded: passing a defaultValue narrows the return type to string.
get(key: "API_URL" | "FEATURE_FLAGS", defaultValue: string): string;
get(key: "API_URL" | "FEATURE_FLAGS", defaultValue?: undefined): string | undefined;
getSecure(key: "ANALYTICS_KEY"): Promise<string>;
// ... other methods
}
export function get(key: "API_URL" | "FEATURE_FLAGS", defaultValue: string): string;
export function get(key: "API_URL" | "FEATURE_FLAGS", defaultValue?: undefined): string | undefined;
export function getSecure(key: "ANALYTICS_KEY"): Promise<string>;
// ...
}
```

**Strict by design** — the key unions are closed. Calling `rep.get('UNDECLARED_KEY')` is a TypeScript error if that variable is not declared in `.rep.yaml`. This is intentional: it forces every variable the app reads to be explicitly declared in the manifest, keeping the manifest the single source of truth. The fix is always to add the missing variable to `.rep.yaml` and re-run `rep typegen`, not to widen the types.

If you don't want strict type enforcement, skip `rep typegen` and rely on the base SDK types (`key: string`).

## `rep lint`

Scan built JavaScript bundles for accidentally leaked secrets. Uses the same guardrail detection as the gateway (Shannon entropy, known secret formats).
Expand Down
Loading