fenneckit 1.0.3 → 1.2.0

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
@@ -2,9 +2,16 @@
2
2
 
3
3
  ![logo](./fenneckit.png)
4
4
 
5
- **English**: A Complete Storage System for Practical and Seamless Data Analysis
5
+ ```bash
6
+ npm install fenneckit@latest --save-dev
7
+ npx fenneckit --help
8
+ ```
9
+
10
+ **English**: A Complete Storage + Security + API Testing System for Practical and Seamless Data Analysis
11
+
12
+ **Zero Config** • Sequential Labs • Inter-Lab Data Sharing (within the same file) • Store Management • Encrypted Secrets • Namespaces • Audit Log • HTTP Testing Kit
6
13
 
7
- **Zero Config** • Sequential Labs • Inter-Lab Data Sharing (within the same file) • Store Management
14
+ **🦊Example** : soon
8
15
 
9
16
  ---
10
17
 
@@ -64,8 +71,8 @@ npx fenneckit
64
71
  4. Generates a report (`fenneckit.md`) after execution
65
72
 
66
73
  > **Important limitation**
67
- > Data sharing (`setStore` / `getStore`) only works **inside the same file**.
68
- > Different lab files **cannot** share STORE or TEMP data with each other.
74
+ > Data sharing (`setStore` / `getStore` / secrets / namespaces) only works **inside the same file**.
75
+ > Different lab files **cannot** share STORE, TEMP, Secrets or Namespaces with each other.
69
76
 
70
77
  ---
71
78
 
@@ -74,71 +81,47 @@ npx fenneckit
74
81
  ```
75
82
  📁 FennecKit Execution
76
83
  │
77
- ├─ 📄 file1.labs.js (STORE Instance #1)
84
+ ├─ 📄 file1.labs.js (STORE Instance #1 + SecretVault + Namespaces)
78
85
  │ │
79
86
  │ ├─ 🔬 Lab 1 (User Registration)
80
87
  │ │ ├─ 📝 Test 1: Create User
81
88
  │ │ │ ├─ STORE: {"userId": "123"} ✅ Shared with Lab 2
89
+ │ │ │ ├─ SECRET: encrypted token ✅ Shared with Lab 2
90
+ │ │ │ ├─ NAMESPACE "user": {...} ✅ Shared with Lab 2
82
91
  │ │ │ └─ TEMP: {"token": "abc"} ❌ Only here
83
92
  │ │ │
84
93
  │ │ └─ 📝 Test 2: Send Email
85
- │ │ └─ Can access STORE from Test 1
94
+ │ │ └─ Can access STORE / SECRET / Namespaces from Test 1
86
95
  │ │
87
96
  │ ├─ 🔬 Lab 2 (Authentication)
88
97
  │ │ ├─ 📝 Test 1: Generate Token
89
98
  │ │ │ ├─ STORE: {"userId": "123"} ✅ From Lab 1
99
+ │ │ │ ├─ SECRET / Namespace ✅ From Lab 1
90
100
  │ │ │ └─ TEMP: {"token": "new"} ❌ Only here
91
101
  │ │ │
92
102
  │ │ └─ 📝 Test 2: Verify Token
93
- │ │ └─ Can access STORE from Labs 1 & 2
103
+ │ │ └─ Can access STORE / SECRET / Namespaces from Labs 1 & 2
94
104
  │ │
95
105
  │ └─ 🔬 Lab 3 (Cleanup)
96
- │ └─ File STORE cleared when execution ends
106
+ │ └─ File STORE + Secrets + Namespaces cleared when execution ends
97
107
  │
98
- ├─ 📄 file2.labs.js (STORE Instance #2 - ISOLATED)
99
- │ │
100
- │ ├─ 🔬 Lab 1
101
- │ │ └─ ❌ CANNOT access file1.labs.js STORE
102
- │ │
103
- │ └─ 🔬 Lab 2
104
- │ └─ ❌ CANNOT access file1.labs.js STORE
108
+ ├─ 📄 file2.labs.js (Completely ISOLATED)
109
+ │ └─ ❌ CANNOT access anything from file1.labs.js
105
110
  │
106
- └─ 📄 file3.labs.js (STORE Instance #3 - ISOLATED)
107
- └─ ❌ Isolated from file1.labs.js and file2.labs.js
111
+ └─ 📄 file3.labs.js (Completely ISOLATED)
112
+ └─ ❌ Isolated from all other files
108
113
  ```
109
114
 
110
115
  ### Understanding the Hierarchy
111
116
 
112
- **🔴 Level 1: Different Files = NO Data Sharing**
113
- ```
114
- file1.labs.js ← STORE Instance #1 (isolated)
115
- file2.labs.js ← STORE Instance #2 (isolated)
116
- file3.labs.js ← STORE Instance #3 (isolated)
117
+ **🔴 Level 1: Different Files = NO Data Sharing**
118
+ Each file gets its own isolated STORE, SecretVault and Namespaces.
117
119
 
118
- ❌ file1's STORE ≠ file2's STORE ≠ file3's STORE
119
- ```
120
+ **🟡 Level 2: Same File, Different Labs = STORE + Secrets + Namespaces Sharing**
121
+ Data set in Lab 1 is available in Lab 2, Lab 3, etc. (until cleared).
120
122
 
121
- **🟡 Level 2: Same File, Different Labs = STORE Sharing**
122
- ```
123
- file1.labs.js
124
- ├─ Lab 1: setStore("userId", "123")
125
- ├─ Lab 2: getStore("userId") ✅ Can access
126
- └─ Lab 3: getStore("userId") ✅ Can still access
127
- ```
128
-
129
- **🟢 Level 3: Same Lab, Different Tests = STORE + TEMP Sharing**
130
- ```
131
- Lab 1 (User Registration)
132
- ├─ Test 1:
133
- │ ├─ setStore("userId", "123") ✅ Shared with other tests
134
- │ └─ setTemp("token", "abc") ✅ Shared with other tests in Lab 1
135
- │
136
- ├─ Test 2:
137
- │ ├─ getStore("userId") ✅ Works (from Test 1)
138
- │ └─ getTemp("token") ✅ Works (from Test 1)
139
- │
140
- └─ Lab 1 ends → TEMP cleared, STORE remains
141
- ```
123
+ **🟢 Level 3: Same Lab, Different Tests = STORE + TEMP + Secrets + Namespaces Sharing**
124
+ TEMP is automatically cleared when the Lab ends. Everything else remains.
142
125
 
143
126
  ---
144
127
 
@@ -148,217 +131,218 @@ Lab 1 (User Registration)
148
131
 
149
132
  In Jest and Vitest every test is isolated. You cannot pass data from one test to another.
150
133
 
151
- ### FennecKit Solution – Three Storage Levels
134
+ ### FennecKit Solution – Storage Levels (v1.2.0)
152
135
 
153
136
  ```
154
137
  ┌─────────────────────────────────────────────────────────────┐
155
138
  │ FennecKit Storage System (Per File) │
156
139
  ├─────────────────────────────────────────────────────────────┤
157
140
  │ │
158
- │ LEVEL 1: FILE SCOPE (Entire File) │
141
+ │ LEVEL 1: FILE SCOPE │
159
142
  │ ┌──────────────────────────────────────────────────────┐ │
160
143
  │ │ STORE (Global - Persistent within file) │ │
161
144
  │ │ ├─ Shared across ALL Labs in this file │ │
162
145
  │ │ ├─ Available until file execution ends │ │
163
146
  │ │ ├─ Can be manually cleared with clearStore() │ │
164
- │ │ └─ Example: userId, authToken, orderData │ │
147
+ │ │ └─ Example: userId, orderData, status │ │
148
+ │ └──────────────────────────────────────────────────────┘ │
149
+ │ │
150
+ │ LEVEL 2: ENCRYPTED SECRETS (AES-256-GCM) │
151
+ │ ┌──────────────────────────────────────────────────────┐ │
152
+ │ │ SECRET VAULT │ │
153
+ │ │ ├─ Encrypted at rest inside the process │ │
154
+ │ │ ├─ Shared across Labs in the same file │ │
155
+ │ │ ├─ setSecret / getSecret / clearSecret │ │
156
+ │ │ └─ Example: auth tokens, API keys, passwords │ │
165
157
  │ └──────────────────────────────────────────────────────┘ │
166
158
  │ │
167
- │ LEVEL 2: LAB SCOPE (Single Lab) │
159
+ │ LEVEL 3: NAMESPACES │
168
160
  │ ┌──────────────────────────────────────────────────────┐ │
169
- │ │ STORE (Available to this and following Labs) │ │
170
- │ │ └─ Set in Lab 1, used in Lab 2, Lab 3, etc │ │
161
+ │ │ kit.namespace("user") / kit.namespace("order") │ │
162
+ │ │ ├─ Isolated key-value stores │ │
163
+ │ │ ├─ Shared across Labs in the same file │ │
164
+ │ │ └─ Perfect for grouping related data │ │
171
165
  │ └──────────────────────────────────────────────────────┘ │
172
166
  │ │
173
- │ LEVEL 3: LAB-LOCAL SCOPE (Single Lab Only) │
167
+ │ LEVEL 4: LAB-LOCAL SCOPE │
174
168
  │ ┌──────────────────────────────────────────────────────┐ │
175
169
  │ │ TEMP (Local - Auto-Cleaned) │ │
176
170
  │ │ ├─ Only available inside current Lab │ │
177
171
  │ │ ├─ Automatically cleared when Lab ends │ │
178
- │ │ ├─ Cannot be manually cleared │ │
179
- │ │ └─ Example: timestamps, temp calculations │ │
172
+ │ │ └─ Example: timestamps, temp calculations │ │
180
173
  │ └──────────────────────────────────────────────────────┘ │
181
174
  │ │
182
175
  └─────────────────────────────────────────────────────────────┘
183
176
  ```
184
177
 
185
- ### Storage Demo (same file)
178
+ ---
186
179
 
187
- ```typescript
188
- // ========== LAB 1: User Registration ==========
189
- await newLabs("User Registration", async (kit) => {
190
- await kit.test("Create User", async () => {
191
- const userId = "user_123";
192
- const email = "john@example.com";
180
+ ## 🔐 NEW in v1.2.0: Secret Vault (AES-256-GCM)
193
181
 
194
- // STORE → available to all Labs in this file
195
- kit.setStore("userId", userId);
196
- kit.setStore("userEmail", email);
182
+ Sensitive data should never live in plain STORE.
197
183
 
198
- // TEMP → only for this Lab
199
- kit.setTemp("tempToken", "abc123");
184
+ ```typescript
185
+ await newLabs("Auth Lab", async (kit) => {
186
+ await kit.test("Login", async () => {
187
+ // Encrypted storage
188
+ kit.setSecret("accessToken", "eyJhbGciOiJIUzI1NiIs...");
189
+ kit.setSecret("refreshToken", "rt_abc123");
200
190
 
201
- kit.done("User created");
191
+ kit.done("Tokens stored securely");
202
192
  });
203
- });
204
193
 
205
- // ========== LAB 2: Authentication ==========
206
- await newLabs("Authentication", async (kit) => {
207
- await kit.test("Generate Token", async () => {
208
- const userId = kit.getStore("userId"); // ✅ works (from Lab 1)
209
- const email = kit.getStore("userEmail"); // ✅ works (from Lab 1)
210
- const token = kit.getTemp("tempToken"); // ❌ undefined (cleared after Lab 1)
194
+ await kit.test("Use Token", async () => {
195
+ const token = kit.getSecret("accessToken"); // decrypted on the fly
196
+ kit.http.setAuth("bearer", token!);
197
+ kit.done("Token retrieved");
198
+ });
211
199
 
212
- kit.done(`Token generated for: ${email}`);
200
+ await kit.test("Cleanup", async () => {
201
+ kit.clearSecret("accessToken"); // remove one key
202
+ // kit.clearSecret(); // clear entire vault
203
+ kit.done("Secrets cleared");
213
204
  });
214
205
  });
215
206
  ```
216
207
 
217
- ---
208
+ **TTL Support for Secrets**
209
+ ```typescript
210
+ kit.setSecretWithTTL("tempToken", "abc123", 30_000); // auto-delete after 30s
211
+ ```
218
212
 
219
- ## 🧹 NEW: clearStore() Feature (v1.1.0)
213
+ ---
220
214
 
221
- Manually clear Store data between Labs for better state management and security.
215
+ ## 🗂️ NEW in v1.2.0: Namespaced Store
222
216
 
223
- ### Two Ways to Clear
217
+ Organize data into logical groups.
224
218
 
225
- #### 1. Clear specific key (inside Lab)
226
219
  ```typescript
227
- await newLabs("My Lab", async (kit) => {
228
- await kit.test("Store sensitive data", async () => {
229
- kit.setStore("authToken", "secret123");
230
- kit.done("Token stored");
220
+ await newLabs("E-Commerce Flow", async (kit) => {
221
+ const user = kit.namespace("user");
222
+ const order = kit.namespace("order");
223
+ const cart = kit.namespace("cart");
224
+
225
+ await kit.test("Register", async () => {
226
+ user.set("id", "usr_123");
227
+ user.set("email", "john@example.com");
228
+ kit.done("User namespace populated");
231
229
  });
232
230
 
233
- await kit.test("Cleanup", async () => {
234
- kit.clearStore("authToken"); // Remove only this key
235
- kit.done("Token cleared");
231
+ await kit.test("Create Order", async () => {
232
+ order.set("id", "ord_456");
233
+ order.set("total", 299.99);
234
+ kit.done("Order namespace populated");
235
+ });
236
+
237
+ await kit.test("Read Later", async () => {
238
+ const userId = kit.getNamespace("user")?.get("id"); // "usr_123"
239
+ const total = order.get("total"); // 299.99
240
+ kit.done(`User ${userId} ordered ${total}`);
236
241
  });
237
242
  });
238
243
  ```
239
244
 
240
- #### 2. Clear all data (global)
245
+ ---
246
+
247
+ ## 📡 NEW in v1.2.0: HTTP Kit (API Testing)
248
+
249
+ Built-in HTTP client with auth, retries, history and tracing.
250
+
241
251
  ```typescript
242
- import { newLabs, clearStore } from "fenneckit";
252
+ await newLabs("API Smoke Test", async (kit) => {
253
+ // Set auth once
254
+ kit.http.setAuth("bearer", "your-token");
255
+ // or kit.http.setAuth("basic", "base64creds");
256
+ // or kit.http.setAuth("api-key", "key123");
257
+
258
+ await kit.test("GET Users", async () => {
259
+ const res = await kit.http.get("https://api.example.com/users", {
260
+ timeout: 5000,
261
+ retry: { max: 3, delay: 1000 }
262
+ });
263
+
264
+ if (res.status !== 200) {
265
+ kit.err(`Expected 200, got ${res.status}`);
266
+ }
243
267
 
244
- await newLabs("Lab 1", async (kit) => {
245
- await kit.test("Setup", async () => {
246
- kit.setStore("data1", "value1");
247
- kit.setStore("data2", "value2");
248
- kit.done("Stored");
268
+ kit.setStore("users", res.data);
269
+ kit.done(`Fetched ${res.data.length} users`);
249
270
  });
250
- });
251
271
 
252
- clearStore(); // Clear all STORE data globally
272
+ await kit.test("POST Order", async () => {
273
+ const res = await kit.http.post("https://api.example.com/orders", {
274
+ productId: "prod_1",
275
+ qty: 2
276
+ });
277
+
278
+ kit.done(`Order created: ${res.data.id}`);
279
+ });
253
280
 
254
- await newLabs("Lab 2", async (kit) => {
255
- await kit.test("Fresh Start", async () => {
256
- const data = kit.getStore("data1"); // undefined
257
- kit.done("Fresh state");
281
+ // Inspect request history
282
+ await kit.test("Check History", async () => {
283
+ const last = kit.http.getLastRequest();
284
+ kit.log(`Last request took ${last?.duration}ms`);
258
285
  });
259
286
  });
260
287
  ```
261
288
 
262
- ### When to Use clearStore()
263
-
264
- | Scenario | Method | Why |
265
- |----------|--------|-----|
266
- | Remove sensitive data | `clearStore("token")` | Security |
267
- | Free memory | `clearStore("largeObject")` | Performance |
268
- | Test isolation | `clearStore()` | Prevent data leakage |
269
- | Between phases | `clearStore("tempData")` | Clean state |
289
+ **Available methods**:
290
+ - `kit.http.get / post / put / patch / delete`
291
+ - `kit.http.setAuth(type, credentials)` / `clearAuth()`
292
+ - `kit.http.getRequestHistory()` / `getLastRequest()` / `clearHistory()`
270
293
 
271
294
  ---
272
295
 
273
- ## 📊 Storage Lifecycle (per file)
274
-
275
- ```
276
- FILE EXECUTION START
277
- │
278
- ├─ Lab 1
279
- │ ├─ setStore(...) → kept across all labs
280
- │ ├─ setTemp(...) → kept only for this Lab
281
- │ ├─ clearStore(...) → optionally remove keys
282
- │ └─ Lab ends → TEMP cleared, STORE remains (unless cleared)
283
- │
284
- ├─ Lab 2
285
- │ ├─ getStore(...) → works (if not cleared)
286
- │ ├─ getTemp(...) → undefined (cleared after Lab 1)
287
- │ ├─ clearStore(...) → can clear for next labs
288
- │ └─ Lab ends → TEMP cleared, STORE remains (unless cleared)
289
- │
290
- └─ FILE END → STORE completely cleared
291
- ```
292
-
293
- **Remember**: This lifecycle is **per file**.
294
- Running `npx fenneckit fileA.labs.js` and then `npx fenneckit fileB.labs.js` gives two completely separate STORE instances.
295
-
296
- ---
296
+ ## 📋 NEW in v1.2.0: Audit Log
297
297
 
298
- ## 💡 Real-World Example (Single File)
298
+ Every STORE / SECRET operation is automatically recorded.
299
299
 
300
300
  ```typescript
301
- // order-pipeline.labs.js
302
-
303
- import { newLabs, clearStore } from "fenneckit";
304
-
305
- // LAB 1
306
- await newLabs("Order Validation", async (kit) => {
307
- await kit.test("Check Product Stock", async () => {
308
- kit.setStore("productId", "prod_456");
309
- kit.setStore("stockAvailable", 50);
310
- kit.setTemp("validationTime", Date.now());
311
- kit.done("Product stock verified");
301
+ await newLabs("Audit Demo", async (kit) => {
302
+ await kit.test("Operations", async () => {
303
+ kit.setStore("userId", "123");
304
+ kit.setSecret("token", "secret");
305
+ kit.getStore("userId");
312
306
  });
313
- });
314
307
 
315
- // LAB 2
316
- await newLabs("Payment Processing", async (kit) => {
317
- await kit.test("Charge Customer Card", async () => {
318
- const productId = kit.getStore("productId"); // ✅ From Lab 1
319
- const chargeId = `charge_${Date.now()}`;
308
+ await kit.test("Inspect Audit", async () => {
309
+ const last5 = kit.audit.getLast(5);
310
+ const byKey = kit.audit.filterByKey("token");
311
+ const json = kit.audit.export("json");
312
+ const csv = kit.audit.export("csv");
320
313
 
321
- kit.setStore("chargeId", chargeId);
322
- kit.setStore("orderStatus", "paid");
323
- kit.setTemp("transactionId", chargeId);
324
-
325
- kit.done(`Payment charged: ${chargeId}`);
314
+ kit.log(`Recorded ${last5.length} operations`);
326
315
  });
327
316
  });
317
+ ```
328
318
 
329
- // Clear sensitive payment data before shipping
330
- clearStore("chargeId");
319
+ ---
331
320
 
332
- // LAB 3
333
- await newLabs("Shipping & Notification", async (kit) => {
334
- await kit.test("Create Shipping Label", async () => {
335
- const status = kit.getStore("orderStatus"); // ✅ Available
336
- const chargeId = kit.getStore("chargeId"); // ❌ Cleared
337
- const tempTx = kit.getTemp("transactionId"); // ❌ Undefined
321
+ ## 🧹 clearStore() & clearSecret()
338
322
 
339
- if (status === "paid") {
340
- const tracking = `TRACK_${Date.now()}`;
341
- kit.setStore("trackingNumber", tracking);
342
- kit.done(`Shipping label created: ${tracking}`);
343
- }
344
- });
323
+ ```typescript
324
+ // Clear specific key
325
+ kit.clearStore("authToken");
326
+ kit.clearSecret("accessToken");
345
327
 
346
- await kit.test("Send Notification Email", async () => {
347
- const tracking = kit.getStore("trackingNumber");
348
- kit.done(`Email sent with tracking: ${tracking}`);
349
- });
350
- });
328
+ // Clear everything
329
+ kit.clearStore();
330
+ kit.clearSecret();
351
331
  ```
352
332
 
353
- Run it:
333
+ ---
354
334
 
355
- ```bash
356
- npx fenneckit order-pipeline.labs.js
335
+ ## ⏰ TTL Support (Time-To-Live)
336
+
337
+ ```typescript
338
+ // Auto-expire after 10 seconds
339
+ kit.setStoreWithTTL("sessionId", "sess_abc", 10_000);
340
+ kit.setSecretWithTTL("tempKey", "value", 30_000);
357
341
  ```
358
342
 
359
343
  ---
360
344
 
361
- ## 🛠️ LabContext Methods
345
+ ## 🛠️ LabContext Methods (v1.2.0)
362
346
 
363
347
  ```typescript
364
348
  interface LabContext {
@@ -368,184 +352,136 @@ interface LabContext {
368
352
  err(msg: string): void // stops the Lab
369
353
  flatErr(msg: string): void // continues
370
354
  log(msg: string): void
371
- warning(msg: string): void // warning
355
+ warning(msg: string): void
372
356
 
373
357
  // Flow control
374
358
  out(): void // exit Lab immediately
375
- ret(): void // restart Lab
359
+ ret(): void // restart Lab (max 3 times)
376
360
 
377
- // Persistent (across Labs in same file)
361
+ // Persistent STORE
378
362
  setStore(key: string, value: any): void
379
363
  getStore(key: string): any
380
- clearStore(key?: string): void // NEW: clear specific key or all
364
+ clearStore(key?: string): void
365
+ setStoreWithTTL(key: string, value: any, ttlMs: number): void
366
+
367
+ // Encrypted Secrets (AES-256-GCM)
368
+ setSecret(key: string, value: string): void
369
+ getSecret(key: string): string | undefined
370
+ clearSecret(key?: string): void
371
+ setSecretWithTTL(key: string, value: string, ttlMs: number): void
372
+
373
+ // Namespaces
374
+ namespace(name: string): NamespacedStore
375
+ getNamespace(name: string): NamespacedStore | undefined
381
376
 
382
377
  // Temporary (Lab-local only)
383
378
  setTemp(key: string, value: any): void
384
379
  getTemp(key: string): any
380
+
381
+ // HTTP Kit
382
+ http: HttpKit
383
+
384
+ // Audit Log
385
+ audit: AuditLog
385
386
  }
386
387
  ```
387
388
 
388
389
  ---
389
390
 
390
- ## 🚀 Quick Start
391
-
392
- ### 1. Create a lab file
393
-
394
- ```bash
395
- # example.labs.js
396
- ```
391
+ ## 💡 Real-World Example (v1.2.0)
397
392
 
398
393
  ```typescript
399
394
  import { newLabs } from "fenneckit";
400
395
 
401
- await newLabs("User Registration Workflow", async (kit) => {
402
- kit.log("Starting user registration...");
396
+ await newLabs("E-Commerce API Test", async (kit) => {
397
+ const user = kit.namespace("user");
398
+ const order = kit.namespace("order");
403
399
 
404
- await kit.test("Create User", async () => {
405
- const id = "user_" + Date.now();
406
- kit.setStore("userId", id);
407
- kit.done(`User created: ${id}`);
408
- });
400
+ await kit.test("Register User", async () => {
401
+ const res = await kit.http.post("https://api.shop.com/auth/register", {
402
+ email: "test@example.com",
403
+ password: "secure123"
404
+ });
409
405
 
410
- await kit.test("Send Welcome Email", async () => {
411
- const id = kit.getStore("userId");
412
- kit.done(`Email sent to user: ${id}`);
406
+ user.set("id", res.data.id);
407
+ kit.setSecret("token", res.data.token); // encrypted
408
+ kit.http.setAuth("bearer", res.data.token);
409
+
410
+ kit.done("User registered");
413
411
  });
414
- });
415
- ```
416
412
 
417
- ### 2. Run
413
+ await kit.test("Create Order", async () => {
414
+ const res = await kit.http.post("https://api.shop.com/orders", {
415
+ items: [{ id: "prod_1", qty: 2 }]
416
+ });
418
417
 
419
- ```bash
420
- npx fenneckit example.labs.js
421
- ```
418
+ order.set("id", res.data.orderId);
419
+ order.set("total", res.data.total);
420
+ kit.done(`Order created: ${res.data.orderId}`);
421
+ });
422
422
 
423
- ### 3. Check report
423
+ await kit.test("Security Cleanup", async () => {
424
+ kit.clearSecret("token"); // remove sensitive data
425
+ kit.done("Secrets cleared");
426
+ });
424
427
 
425
- ```bash
426
- cat fenneckit.md
428
+ await kit.test("Audit Check", async () => {
429
+ const log = kit.audit.getLast(10);
430
+ kit.log(`Audit entries: ${log.length}`);
431
+ });
432
+ });
427
433
  ```
428
434
 
429
435
  ---
430
436
 
431
- ## 📋 setStore vs setTemp vs clearStore
437
+ ## 📊 Storage Lifecycle (per file)
432
438
 
433
- | Scenario | Use | Why |
434
- |----------|-----|-----|
435
- | Pass data between Labs | `setStore` | Survives Lab end |
436
- | Performance timing | `setTemp` | Only needed inside one Lab |
437
- | Auth token / DB connection | `setStore` | Needed by multiple Labs |
438
- | Temporary calculation | `setTemp` | Auto-cleaned |
439
- | Remove sensitive data | `clearStore` | Security |
440
- | Reset before next phase | `clearStore` | Fresh state |
441
- | Cross-file sharing | ❌ Impossible | STORE is scoped to one file only |
439
+ ```
440
+ FILE EXECUTION START
441
+ │
442
+ ├─ Lab 1
443
+ │ ├─ setStore / setSecret / namespace.set → kept across Labs
444
+ │ ├─ setTemp → kept only for this Lab
445
+ │ ├─ clearStore / clearSecret → optional cleanup
446
+ │ └─ Lab ends → TEMP cleared, everything else remains
447
+ │
448
+ ├─ Lab 2
449
+ │ ├─ getStore / getSecret / namespace.get → works
450
+ │ └─ Lab ends → TEMP cleared
451
+ │
452
+ └─ FILE END → STORE + Secrets + Namespaces completely cleared
453
+ ```
442
454
 
443
455
  ---
444
456
 
445
- ## 🎯 Best Practices
457
+ ## 🎯 Best Practices (v1.2.0)
446
458
 
447
- 1. **Clear names**
459
+ 1. **Secrets always go into the Vault**
448
460
  ```typescript
449
- kit.setStore("userId", id);
450
- kit.setStore("authToken", token);
461
+ kit.setSecret("token", token); // ✅
462
+ kit.setStore("token", token); // ❌ avoid
451
463
  ```
452
464
 
453
- 2. **Always check before use**
465
+ 2. **Use namespaces for related data**
454
466
  ```typescript
455
- const userId = kit.getStore("userId");
456
- if (!userId) {
457
- kit.err("userId missing from previous Lab!");
458
- }
467
+ const user = kit.namespace("user");
468
+ user.set("id", id);
469
+ user.set("email", email);
459
470
  ```
460
471
 
461
- 3. **Clear sensitive data**
472
+ 3. **Clear sensitive data when no longer needed**
462
473
  ```typescript
463
- kit.clearStore("password");
474
+ kit.clearSecret("accessToken");
464
475
  kit.clearStore("creditCard");
465
476
  ```
466
477
 
467
- 4. **One concern per Lab**
468
- Keep each Lab focused. Use STORE to pass only the necessary data.
469
-
470
- 5. **Do not rely on cross-file data**
471
- If you need data from another file, write it to disk or a database yourself.
472
-
473
- ---
474
-
475
- ## 🔄 Complete Multi-Lab Example (Payment → Invoice)
476
-
477
- ```typescript
478
- import { newLabs, clearStore } from "fenneckit";
479
-
480
- await newLabs("Payment Validation", async (kit) => {
481
- await kit.test("Validate Payment Details", async () => {
482
- kit.setStore("customerId", "cust_123");
483
- kit.setStore("amount", 299.99);
484
- kit.setStore("currency", "USD");
485
- kit.setTemp("validatedAt", Date.now());
486
- kit.done("Payment validated: 299.99 USD");
487
- });
488
- });
489
-
490
- await newLabs("Process Charge", async (kit) => {
491
- await kit.test("Charge Card", async () => {
492
- const amount = kit.getStore("amount");
493
- const chargeId = `charge_${Date.now()}`;
494
- kit.setStore("chargeId", chargeId);
495
- kit.setStore("chargedAt", new Date().toISOString());
496
- kit.done(`Charged: ${chargeId} for ${amount}`);
497
- });
498
- });
499
-
500
- // Clear payment details (security)
501
- clearStore("chargeId");
502
-
503
- await newLabs("Generate Invoice", async (kit) => {
504
- await kit.test("Create Invoice PDF", async () => {
505
- const invoiceId = `inv_${Date.now()}`;
506
- kit.setStore("invoiceId", invoiceId);
507
- kit.done(`Invoice created: ${invoiceId}`);
508
- });
509
-
510
- await kit.test("Send Invoice Email", async () => {
511
- const invoiceId = kit.getStore("invoiceId");
512
- const customerId = kit.getStore("customerId");
513
- kit.done(`Invoice ${invoiceId} emailed to ${customerId}`);
514
- });
515
- });
516
- ```
517
-
518
- Run:
519
-
520
- ```bash
521
- npx fenneckit payment-pipeline.labs.js
522
- ```
523
-
524
- ---
525
-
526
- ## 📞 Troubleshooting
527
-
528
- **Q: Lab 2 cannot see Lab 1 data?**
529
- A: You used `setTemp`. Switch to `setStore`.
530
-
531
- **Q: I cleared data but it's still there?**
532
- A: Make sure you're using `clearStore()` correctly. Check key name.
533
-
534
- **Q: Can STORE survive across different files?**
535
- A: No. Each file execution has its own isolated STORE.
536
- `npx fenneckit a.labs.js` and `npx fenneckit b.labs.js` do not share data.
537
-
538
- **Q: How is TEMP cleaned?**
539
- A: Automatically when the Lab finishes. No manual cleanup needed.
478
+ 4. **Check before use**
479
+ ```typescript
480
+ const token = kit.getSecret("token");
481
+ if (!token) kit.err("Token missing!");
482
+ ```
540
483
 
541
- **Q: How do I run multiple files?**
542
- A:
543
- ```bash
544
- npx fenneckit file1.labs.js
545
- npx fenneckit file2.labs.js
546
- # or let the runner discover all *.labs.* files
547
- npx fenneckit
548
- ```
484
+ 5. **Never rely on cross-file sharing** – write to disk/DB if needed.
549
485
 
550
486
  ---
551
487
 
@@ -557,32 +493,40 @@ npx fenneckit
557
493
  - `⚠️` / `🟡` Warning
558
494
  - `📝` / `⚪` Info
559
495
  - `⚙️` Store operation
496
+ - `🔐` Secret operation
560
497
  - `⏱️` Temp operation
561
498
  - `🧹` Clear operation
499
+ - `⏰` TTL expiration
562
500
 
563
501
  ---
564
502
 
565
503
  ## 💪 Perfect For
566
504
 
567
- - Backend API testing (Express, Fastify, etc.)
505
+ - Backend API testing (Express, Fastify, NestJS, etc.)
506
+ - Security-conscious test flows (tokens, keys)
568
507
  - Database migration validation
569
- - CLI tool workflows
570
508
  - Microservice chaining
571
509
  - Pre-deployment smoke checks
572
- - Development-time sanity tests
573
- - State management testing
510
+ - State management + audit trails
574
511
  - Data pipeline validation
575
512
 
576
513
  ---
577
514
 
578
515
  ## 📝 Version History
579
516
 
580
- ### v1.0.0-beta (Current)
517
+ ### v1.2.0 (Current)
518
+ - 🔐 **Secret Vault** – AES-256-GCM encryption
519
+ - 🗂️ **Namespaced Store**
520
+ - 📋 **Audit Log** (JSON / CSV export)
521
+ - 📡 **HTTP Kit** with auth, retry, history
522
+ - ⏰ **TTL support** for STORE & Secrets
523
+ - Improved LabContext API
524
+
525
+ ### v1.1.0
581
526
  - ✨ Added `clearStore()` for store management
582
527
  - 🌳 Improved data sharing hierarchy documentation
583
- - 🧹 Better state cleanup capabilities
584
528
 
585
- ### v1.0.0 (Initial Release)
529
+ ### v1.0.0
586
530
  - Core Lab functionality
587
531
  - STORE & TEMP storage
588
532
  - Zero config runner
@@ -594,7 +538,7 @@ npx fenneckit
594
538
 
595
539
  **Copyright © 2026 Lasith Ruwantha Amrwansha**
596
540
  Written: 2026/09/17
597
- Updated: 2026/09/20
541
+ Updated: 2026/09/21
598
542
  Author: Ruwantha Amrwansha
599
543
  Library: FennecKit 🦊
600
544