@ojolowoblue/lamba 1.0.4 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -27,7 +27,7 @@ Deployed via CDN or installed via NPM, `lamba` injects a non-intrusive floating
27
27
  Include the script tag in your `index.html` file before your application bundle:
28
28
 
29
29
  ```html
30
- <script src="https://unpkg.com/@ojolowoblue/lamba"></script>
30
+ <script src="https://unpkg.com/@ojolowoblue/lamba" data-lamba-auto></script>
31
31
  ```
32
32
 
33
33
  That's it! A floating settings button (⚙️) will automatically appear in the bottom-right corner of your web page.
@@ -52,11 +52,11 @@ import lamba from '@ojolowoblue/lamba';
52
52
  lamba.init({
53
53
  position: 'bottom-right',
54
54
  env: {
55
- // Supports any env prefix (VITE_, NEXT_PUBLIC_, REACT_APP_, VUE_APP_, PUBLIC_) or custom keys:
55
+ // Supports any data type (strings, numbers, booleans, objects) & any prefix:
56
56
  NEXT_PUBLIC_API_URL: 'https://api.dev.example.com',
57
- REACT_APP_FEATURE_FLAG: 'false',
58
- VITE_ENABLE_ANALYTICS: 'true',
59
- API_BASE_URL: 'https://api.dev.example.com',
57
+ PORT: 3000,
58
+ VITE_ENABLE_ANALYTICS: true,
59
+ FEATURE_FLAGS: { newCheckout: true },
60
60
  },
61
61
  });
62
62
  ```
@@ -88,7 +88,7 @@ Wrap your existing `import.meta.env` (Vite) or `process.env` (Webpack/Next.js) o
88
88
  // src/config.ts
89
89
  import lamba from '@ojolowoblue/lamba';
90
90
 
91
- // Wrap your env object in a dynamic ES Proxy
91
+ // Wrap your env object in a dynamic ES Proxy (preserves primitive boolean & number types!)
92
92
  export const env = lamba.wrap(import.meta.env);
93
93
 
94
94
  // Access keys anywhere in your application:
@@ -121,15 +121,15 @@ import React from 'react';
121
121
  import { useLambaEnv } from '@ojolowoblue/lamba/react';
122
122
 
123
123
  export function UserDashboard() {
124
- const apiBase = useLambaEnv('VITE_API_BASE_URL', 'https://api.dev.com');
125
- const showBetaFeature = useLambaEnv('VITE_FEATURE_BETA_UI', 'false');
124
+ const apiBase = useLambaEnv<string>('VITE_API_BASE_URL', 'https://api.dev.com');
125
+ const isBetaEnabled = useLambaEnv<boolean>('VITE_FEATURE_BETA_UI', false);
126
126
 
127
127
  return (
128
128
  <div style={{ padding: '24px' }}>
129
129
  <h1>Dashboard</h1>
130
130
  <p>Connected Environment: <code>{apiBase}</code></p>
131
131
 
132
- {showBetaFeature === 'true' && (
132
+ {isBetaEnabled && (
133
133
  <div className="beta-banner">
134
134
  🚀 Beta UI Enabled Live via lamba!
135
135
  </div>
@@ -147,14 +147,14 @@ Import `useLambaEnv` from `lamba/vue` as a reactive composition Vue Ref:
147
147
  <script setup lang="ts">
148
148
  import { useLambaEnv } from '@ojolowoblue/lamba/vue';
149
149
 
150
- const apiBase = useLambaEnv('VITE_API_BASE_URL', 'https://api.dev.com');
151
- const featureFlag = useLambaEnv('VITE_NEW_HEADER', 'false');
150
+ const apiBase = useLambaEnv<string>('VITE_API_BASE_URL', 'https://api.dev.com');
151
+ const isNewHeader = useLambaEnv<boolean>('VITE_NEW_HEADER', false);
152
152
  </script>
153
153
 
154
154
  <template>
155
155
  <div class="container">
156
156
  <h2>Current Backend: {{ apiBase }}</h2>
157
- <header v-if="featureFlag === 'true'">
157
+ <header v-if="isNewHeader">
158
158
  <h3>✨ New Header Component</h3>
159
159
  </header>
160
160
  </div>
@@ -167,27 +167,29 @@ const featureFlag = useLambaEnv('VITE_NEW_HEADER', 'false');
167
167
 
168
168
  ### `lamba.init(options?: LambaOptions): LambaManager`
169
169
 
170
- Initializes the lamba manager, hydrates saved overrides from `localStorage`, enables network interceptors, and mounts the floating Shadow DOM UI.
170
+ Initializes the lamba manager, hydrates saved overrides from the configured storage backend, enables network interceptors, and mounts the floating Shadow DOM UI.
171
171
 
172
172
  | Option | Type | Default | Description |
173
173
  | :--- | :--- | :--- | :--- |
174
- | `env` | `Record<string, string>` | `{}` | Initial default key-value pairs of environment variables. |
174
+ | `env` | `Record<string, any>` | `{}` | Initial default key-value pairs of environment variables (supports strings, numbers, booleans, objects). |
175
175
  | `enabled` | `boolean` | `true` | Set to `false` to disable lamba (e.g. in production builds). |
176
176
  | `position` | `'bottom-right' \| 'bottom-left' \| 'top-right' \| 'top-left'` | `'bottom-right'` | Screen position for the floating widget launcher button. |
177
177
  | `secretKeysPattern` | `RegExp` | `/(KEY\|SECRET\|TOKEN\|PASSWORD\|AUTH\|PRIVATE)/i` | Regular expression to automatically obscure sensitive keys in the UI. |
178
178
  | `autoFetchEnvFile` | `boolean` | `false` | Whether to attempt fetching root `/.env` file during local development. |
179
179
  | `interceptNetworkRequests` | `boolean` | `true` | Whether to implicitly intercept `fetch` & `XHR` calls matching original base URLs. |
180
180
  | `allowedPrefixes` | `string \| string[] \| RegExp \| null` | `null` | Optional prefix filter (e.g. `['VITE_', 'NEXT_PUBLIC_']`). Omitting allows ALL keys regardless of prefix. |
181
+ | `storageStrategy` | `'local' \| 'session' \| 'memory'` | `'local'` | Where overrides and presets are persisted. See [Storage Strategies](#-storage-strategies) below. |
182
+ | `storage` | `LambaStorageAdapter` | `undefined` | Provide a fully custom storage adapter. Takes precedence over `storageStrategy`. |
181
183
 
182
184
  ---
183
185
 
184
186
  ### Core Methods
185
187
 
186
- #### `lamba.get(key: string, fallback?: string): string`
187
- Returns the active value for the specified environment key (returns active override if present, otherwise default value or fallback).
188
+ #### `lamba.get<T = any>(key: string, fallback?: T): T`
189
+ Returns the active value for the specified environment key (returns active override if present, otherwise default value or fallback). Preserves numbers, booleans, and objects.
188
190
 
189
- #### `lamba.set(key: string, value: string): void`
190
- Programmatically overrides an environment variable live at runtime. The change is persisted in `localStorage` and triggers UI and listener updates.
191
+ #### `lamba.set(key: string, value: any): void`
192
+ Programmatically overrides an environment variable live at runtime with any data type. The change is persisted in the configured storage backend and triggers UI and listener updates.
191
193
 
192
194
  #### `lamba.remove(key: string): void`
193
195
  Removes an override for a specific environment variable key, reverting it to its default value.
@@ -212,6 +214,57 @@ Programmatically controls the visibility of the lamba modal panel.
212
214
 
213
215
  ---
214
216
 
217
+ ## 🔐 Storage Strategies
218
+
219
+ Control where lamba persists overrides and presets via the `storageStrategy` option:
220
+
221
+ | Strategy | Visibility in DevTools | Survives Tab Close? | XSS Storage Scraping Risk |
222
+ | :--- | :--- | :--- | :--- |
223
+ | `'local'` *(default)* | ⚠️ Visible (plain-text) | ✅ Yes (Indefinitely) | ⚠️ Yes |
224
+ | `'session'` | ⚠️ Visible (plain-text) | ❌ No (Cleared on close) | ⚠️ Yes |
225
+ | `'memory'` | ✅ **Not visible (0 bytes stored)** | ❌ No (GC'd on close) | ✅ **No** |
226
+
227
+ ### In-Memory (Most Secure)
228
+
229
+ ```typescript
230
+ lamba.init({
231
+ storageStrategy: 'memory', // Nothing written to DevTools Storage
232
+ env: { VITE_API_URL: import.meta.env.VITE_API_URL },
233
+ });
234
+ ```
235
+
236
+ ### Session (Tab-Ephemeral)
237
+
238
+ ```typescript
239
+ lamba.init({
240
+ storageStrategy: 'session', // Cleared automatically when tab closes
241
+ env: { VITE_API_URL: import.meta.env.VITE_API_URL },
242
+ });
243
+ ```
244
+
245
+ ### Custom Adapter
246
+
247
+ Implement the `LambaStorageAdapter` interface to plug in any storage backend (encrypted storage, Electron keytar, IndexedDB, etc.):
248
+
249
+ ```typescript
250
+ import lamba, { type LambaStorageAdapter } from '@ojolowoblue/lamba';
251
+
252
+ // Example: an encrypted wrapper around sessionStorage
253
+ const encryptedAdapter: LambaStorageAdapter = {
254
+ getItem: (key) => decrypt(sessionStorage.getItem(key)),
255
+ setItem: (key, value) => sessionStorage.setItem(key, encrypt(value)),
256
+ removeItem: (key) => sessionStorage.removeItem(key),
257
+ clear: () => sessionStorage.clear(),
258
+ };
259
+
260
+ lamba.init({
261
+ storage: encryptedAdapter,
262
+ env: { VITE_API_URL: import.meta.env.VITE_API_URL },
263
+ });
264
+ ```
265
+
266
+ ---
267
+
215
268
  ## 🔒 Production Security Best Practice
216
269
 
217
270
  To prevent end-users from overriding environment variables in production, conditionally initialize `lamba` only in non-production environments:
@@ -221,6 +274,7 @@ import lamba from '@ojolowoblue/lamba';
221
274
 
222
275
  lamba.init({
223
276
  enabled: process.env.NODE_ENV !== 'production',
277
+ storageStrategy: 'memory', // Use memory storage so nothing lingers in DevTools
224
278
  env: {
225
279
  VITE_API_URL: import.meta.env.VITE_API_URL,
226
280
  },
@@ -233,12 +287,12 @@ lamba.init({
233
287
 
234
288
  <details>
235
289
  <summary><b>Does lamba modify my local <code>.env</code> files on disk?</b></summary>
236
- <p>No. <code>lamba</code> operates entirely in browser memory and persists overrides in <code>localStorage</code>. It does not write to disk, so your git status remains clean.</p>
290
+ <p>No. <code>lamba</code> operates entirely in browser memory and optionally persists overrides in storage. It does not write to disk, so your git status remains clean.</p>
237
291
  </details>
238
292
 
239
293
  <details>
240
294
  <summary><b>Do overrides persist when I refresh the page?</b></summary>
241
- <p>Yes. Overrides and active preset profiles are saved in <code>localStorage</code> and automatically restored upon page reloads.</p>
295
+ <p>It depends on the <code>storageStrategy</code>. With <code>'local'</code> (default), overrides persist indefinitely. With <code>'session'</code>, they survive reloads but clear when the tab is closed. With <code>'memory'</code>, overrides are lost on any page reload.</p>
242
296
  </details>
243
297
 
244
298
  <details>
package/dist/index.d.mts CHANGED
@@ -1,21 +1,68 @@
1
+ /**
2
+ * Abstract interface for pluggable storage backends used by lamba to persist
3
+ * overrides and presets. All methods are synchronous for simplicity (async
4
+ * adapters can wrap with Promises if needed in custom implementations).
5
+ */
6
+ interface LambaStorageAdapter {
7
+ getItem(key: string): string | null;
8
+ setItem(key: string, value: string): void;
9
+ removeItem(key: string): void;
10
+ clear(): void;
11
+ }
12
+ /**
13
+ * LocalStorage-backed adapter (default).
14
+ * Overrides persist indefinitely across tabs and page reloads.
15
+ * Visible in DevTools → Application → Local Storage.
16
+ */
17
+ declare class LocalStorageAdapter implements LambaStorageAdapter {
18
+ getItem(key: string): string | null;
19
+ setItem(key: string, value: string): void;
20
+ removeItem(key: string): void;
21
+ clear(): void;
22
+ }
23
+ /**
24
+ * SessionStorage-backed adapter.
25
+ * Overrides survive page reloads within the same tab, but are automatically
26
+ * destroyed when the tab is closed. Still visible in DevTools Storage panel.
27
+ */
28
+ declare class SessionStorageAdapter implements LambaStorageAdapter {
29
+ getItem(key: string): string | null;
30
+ setItem(key: string, value: string): void;
31
+ removeItem(key: string): void;
32
+ clear(): void;
33
+ }
34
+ /**
35
+ * In-memory adapter.
36
+ * The most secure option: zero bytes written to any browser storage mechanism.
37
+ * Overrides exist only in JavaScript heap memory and are destroyed when the
38
+ * tab/page is closed or navigated away. Nothing appears in DevTools Storage.
39
+ */
40
+ declare class MemoryStorageAdapter implements LambaStorageAdapter {
41
+ private store;
42
+ getItem(key: string): string | null;
43
+ setItem(key: string, value: string): void;
44
+ removeItem(key: string): void;
45
+ clear(): void;
46
+ }
47
+
1
48
  interface EnvVariable {
2
49
  key: string;
3
- value: string;
4
- defaultValue: string;
50
+ value: any;
51
+ defaultValue: any;
5
52
  isOverridden: boolean;
6
53
  isSecret?: boolean;
7
54
  }
8
55
  interface PresetProfile {
9
56
  id: string;
10
57
  name: string;
11
- overrides: Record<string, string>;
58
+ overrides: Record<string, any>;
12
59
  createdAt: number;
13
60
  }
14
61
  interface LambaOptions {
15
62
  /**
16
- * Initial environment variable key-values to supply to lamba.
63
+ * Initial environment variable key-values to supply to lamba. Accepts strings, numbers, booleans, objects, etc.
17
64
  */
18
- env?: Record<string, string>;
65
+ env?: Record<string, any>;
19
66
  /**
20
67
  * Whether lamba floating UI is enabled. Defaults to true in non-production or when specified.
21
68
  */
@@ -46,8 +93,24 @@ interface LambaOptions {
46
93
  * If omitted, null, or empty, ALL environment variable keys are allowed and supported regardless of prefix.
47
94
  */
48
95
  allowedPrefixes?: string | string[] | RegExp | null;
96
+ /**
97
+ * Storage strategy for persisting overrides and presets across page reloads:
98
+ * - `'local'` — (default) Standard `localStorage`. Persists indefinitely across tabs & reloads.
99
+ * Visible in DevTools → Application → Local Storage.
100
+ * - `'session'` — `sessionStorage`. Survives page reloads within the same tab, but cleared
101
+ * when the tab is closed. Visible in DevTools → Application → Session Storage.
102
+ * - `'memory'` — In-memory only. Most secure option — zero bytes written to any browser storage.
103
+ * Overrides are destroyed when the tab closes or navigates away.
104
+ * Nothing appears in DevTools Storage.
105
+ */
106
+ storageStrategy?: 'local' | 'session' | 'memory';
107
+ /**
108
+ * Provide a fully custom storage adapter that conforms to the `LambaStorageAdapter` interface.
109
+ * When provided, this takes precedence over `storageStrategy`.
110
+ */
111
+ storage?: LambaStorageAdapter;
49
112
  }
50
- type EnvChangeListener = (key: string, value: string, isOverridden: boolean) => void;
113
+ type EnvChangeListener = (key: string, value: any, isOverridden: boolean) => void;
51
114
  type StoreChangeListener = (variables: Record<string, EnvVariable>, presets: PresetProfile[], activePresetId: string | null) => void;
52
115
 
53
116
  /**
@@ -70,7 +133,7 @@ declare class LambaManager {
70
133
  * Implicit ES Proxy object where properties like `lamba.env.VITE_API_BASE_URL`
71
134
  * return the live active overridden value automatically.
72
135
  */
73
- env: Record<string, string>;
136
+ env: Record<string, any>;
74
137
  constructor();
75
138
  /**
76
139
  * Wraps any environment object (such as `import.meta.env` or `process.env`)
@@ -84,11 +147,11 @@ declare class LambaManager {
84
147
  /**
85
148
  * Gets the active value of an environment variable (returns overridden value if active, otherwise default).
86
149
  */
87
- get(key: string, fallback?: string): string;
150
+ get<T = any>(key: string, fallback?: T): T;
88
151
  /**
89
152
  * Overrides an environment variable live at runtime.
90
153
  */
91
- set(key: string, value: string): void;
154
+ set(key: string, value: any): void;
92
155
  /**
93
156
  * Removes an override for a specific environment variable key.
94
157
  */
@@ -116,4 +179,4 @@ declare class LambaManager {
116
179
  }
117
180
  declare const lamba: LambaManager;
118
181
 
119
- export { type EnvChangeListener, type EnvVariable, LambaManager, type LambaOptions, type PresetProfile, type StoreChangeListener, lamba as default, lamba, parseEnvString, stringifyEnv };
182
+ export { type EnvChangeListener, type EnvVariable, LambaManager, type LambaOptions, type LambaStorageAdapter, LocalStorageAdapter, MemoryStorageAdapter, type PresetProfile, SessionStorageAdapter, type StoreChangeListener, lamba as default, lamba, parseEnvString, stringifyEnv };
package/dist/index.d.ts CHANGED
@@ -1,21 +1,68 @@
1
+ /**
2
+ * Abstract interface for pluggable storage backends used by lamba to persist
3
+ * overrides and presets. All methods are synchronous for simplicity (async
4
+ * adapters can wrap with Promises if needed in custom implementations).
5
+ */
6
+ interface LambaStorageAdapter {
7
+ getItem(key: string): string | null;
8
+ setItem(key: string, value: string): void;
9
+ removeItem(key: string): void;
10
+ clear(): void;
11
+ }
12
+ /**
13
+ * LocalStorage-backed adapter (default).
14
+ * Overrides persist indefinitely across tabs and page reloads.
15
+ * Visible in DevTools → Application → Local Storage.
16
+ */
17
+ declare class LocalStorageAdapter implements LambaStorageAdapter {
18
+ getItem(key: string): string | null;
19
+ setItem(key: string, value: string): void;
20
+ removeItem(key: string): void;
21
+ clear(): void;
22
+ }
23
+ /**
24
+ * SessionStorage-backed adapter.
25
+ * Overrides survive page reloads within the same tab, but are automatically
26
+ * destroyed when the tab is closed. Still visible in DevTools Storage panel.
27
+ */
28
+ declare class SessionStorageAdapter implements LambaStorageAdapter {
29
+ getItem(key: string): string | null;
30
+ setItem(key: string, value: string): void;
31
+ removeItem(key: string): void;
32
+ clear(): void;
33
+ }
34
+ /**
35
+ * In-memory adapter.
36
+ * The most secure option: zero bytes written to any browser storage mechanism.
37
+ * Overrides exist only in JavaScript heap memory and are destroyed when the
38
+ * tab/page is closed or navigated away. Nothing appears in DevTools Storage.
39
+ */
40
+ declare class MemoryStorageAdapter implements LambaStorageAdapter {
41
+ private store;
42
+ getItem(key: string): string | null;
43
+ setItem(key: string, value: string): void;
44
+ removeItem(key: string): void;
45
+ clear(): void;
46
+ }
47
+
1
48
  interface EnvVariable {
2
49
  key: string;
3
- value: string;
4
- defaultValue: string;
50
+ value: any;
51
+ defaultValue: any;
5
52
  isOverridden: boolean;
6
53
  isSecret?: boolean;
7
54
  }
8
55
  interface PresetProfile {
9
56
  id: string;
10
57
  name: string;
11
- overrides: Record<string, string>;
58
+ overrides: Record<string, any>;
12
59
  createdAt: number;
13
60
  }
14
61
  interface LambaOptions {
15
62
  /**
16
- * Initial environment variable key-values to supply to lamba.
63
+ * Initial environment variable key-values to supply to lamba. Accepts strings, numbers, booleans, objects, etc.
17
64
  */
18
- env?: Record<string, string>;
65
+ env?: Record<string, any>;
19
66
  /**
20
67
  * Whether lamba floating UI is enabled. Defaults to true in non-production or when specified.
21
68
  */
@@ -46,8 +93,24 @@ interface LambaOptions {
46
93
  * If omitted, null, or empty, ALL environment variable keys are allowed and supported regardless of prefix.
47
94
  */
48
95
  allowedPrefixes?: string | string[] | RegExp | null;
96
+ /**
97
+ * Storage strategy for persisting overrides and presets across page reloads:
98
+ * - `'local'` — (default) Standard `localStorage`. Persists indefinitely across tabs & reloads.
99
+ * Visible in DevTools → Application → Local Storage.
100
+ * - `'session'` — `sessionStorage`. Survives page reloads within the same tab, but cleared
101
+ * when the tab is closed. Visible in DevTools → Application → Session Storage.
102
+ * - `'memory'` — In-memory only. Most secure option — zero bytes written to any browser storage.
103
+ * Overrides are destroyed when the tab closes or navigates away.
104
+ * Nothing appears in DevTools Storage.
105
+ */
106
+ storageStrategy?: 'local' | 'session' | 'memory';
107
+ /**
108
+ * Provide a fully custom storage adapter that conforms to the `LambaStorageAdapter` interface.
109
+ * When provided, this takes precedence over `storageStrategy`.
110
+ */
111
+ storage?: LambaStorageAdapter;
49
112
  }
50
- type EnvChangeListener = (key: string, value: string, isOverridden: boolean) => void;
113
+ type EnvChangeListener = (key: string, value: any, isOverridden: boolean) => void;
51
114
  type StoreChangeListener = (variables: Record<string, EnvVariable>, presets: PresetProfile[], activePresetId: string | null) => void;
52
115
 
53
116
  /**
@@ -70,7 +133,7 @@ declare class LambaManager {
70
133
  * Implicit ES Proxy object where properties like `lamba.env.VITE_API_BASE_URL`
71
134
  * return the live active overridden value automatically.
72
135
  */
73
- env: Record<string, string>;
136
+ env: Record<string, any>;
74
137
  constructor();
75
138
  /**
76
139
  * Wraps any environment object (such as `import.meta.env` or `process.env`)
@@ -84,11 +147,11 @@ declare class LambaManager {
84
147
  /**
85
148
  * Gets the active value of an environment variable (returns overridden value if active, otherwise default).
86
149
  */
87
- get(key: string, fallback?: string): string;
150
+ get<T = any>(key: string, fallback?: T): T;
88
151
  /**
89
152
  * Overrides an environment variable live at runtime.
90
153
  */
91
- set(key: string, value: string): void;
154
+ set(key: string, value: any): void;
92
155
  /**
93
156
  * Removes an override for a specific environment variable key.
94
157
  */
@@ -116,4 +179,4 @@ declare class LambaManager {
116
179
  }
117
180
  declare const lamba: LambaManager;
118
181
 
119
- export { type EnvChangeListener, type EnvVariable, LambaManager, type LambaOptions, type PresetProfile, type StoreChangeListener, lamba as default, lamba, parseEnvString, stringifyEnv };
182
+ export { type EnvChangeListener, type EnvVariable, LambaManager, type LambaOptions, type LambaStorageAdapter, LocalStorageAdapter, MemoryStorageAdapter, type PresetProfile, SessionStorageAdapter, type StoreChangeListener, lamba as default, lamba, parseEnvString, stringifyEnv };