fenneckit 1.0.4 → 1.2.1

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/libs/labs.js CHANGED
@@ -1,38 +1,310 @@
1
1
  /*==================================
2
2
  * Copyright 2026 lasith ruwantha amrwansha
3
- * Written by 2026/09/17
3
+ * Written by 2026/09/20
4
4
  * Author: ruwantha amrwansha
5
5
  * Library: FennecKit 🦊
6
- * Version: 1.1.0-beta (with clearStore feature)
7
6
  *===================================*/
8
- import { access, writeFile } from "fs/promises";
7
+ import { createCipheriv, createDecipheriv, randomBytes, scryptSync, } from "crypto";
8
+ import report from "../utility/report.js";
9
9
  import path from "path";
10
- const d = new Date();
11
- const nowDate = d.toISOString().split('T')[0].replaceAll('-', '/');
12
- const Store = new Map();
13
- const headOfRepotPath = `
14
- # FennecKit 🦊 Report
15
-
16
- **🚀 Version:** 1.1.0-beta
17
- **⏰ Date:** ${nowDate}
18
- **✨ Features:** Zero Config • Sequential Labs • Inter-Lab Data Sharing • Store Management
19
-
20
- ---\n\n
21
- `;
22
- async function writeRepot(data) {
23
- const repotPath = path.join(process.cwd(), "fenneckit.md");
24
- try {
25
- await access(repotPath);
26
- await writeFile(repotPath, data, { flag: 'a' });
10
+ /*===========================
11
+ All calass
12
+ =============================*/
13
+ class SecretVault {
14
+ vault = new Map();
15
+ masterKey;
16
+ cipher = "aes-256-gcm";
17
+ keyLength = 32;
18
+ ivLength = 16;
19
+ constructor(password = "fenneckit-default") {
20
+ this.masterKey = scryptSync(password, "salt", this.keyLength);
21
+ }
22
+ encrypt(data) {
23
+ const iv = randomBytes(this.ivLength);
24
+ const cipher = createCipheriv(this.cipher, this.masterKey, iv);
25
+ let encrypted = cipher.update(data, "utf8");
26
+ encrypted = Buffer.concat([encrypted, cipher.final()]);
27
+ const tag = cipher.getAuthTag();
28
+ return { encrypted, iv, tag };
29
+ }
30
+ decrypt(data, iv, tag) {
31
+ const decipher = createDecipheriv(this.cipher, this.masterKey, iv);
32
+ decipher.setAuthTag(tag);
33
+ let decrypted = decipher.update(data);
34
+ decrypted = Buffer.concat([decrypted, decipher.final()]);
35
+ return decrypted.toString("utf8");
36
+ }
37
+ set(key, value) {
38
+ const { encrypted, iv, tag } = this.encrypt(value);
39
+ const stored = Buffer.concat([iv, tag, encrypted]);
40
+ this.vault.set(key, stored);
41
+ }
42
+ get(key) {
43
+ const stored = this.vault.get(key);
44
+ if (!stored)
45
+ return undefined;
46
+ try {
47
+ const iv = stored.slice(0, this.ivLength);
48
+ const tag = stored.slice(this.ivLength, this.ivLength + 16);
49
+ const encrypted = stored.slice(this.ivLength + 16);
50
+ return this.decrypt(encrypted, iv, tag);
51
+ }
52
+ catch {
53
+ console.error(`Failed to decrypt secret: ${key}`);
54
+ return undefined;
55
+ }
56
+ }
57
+ delete(key) {
58
+ this.vault.delete(key);
59
+ }
60
+ clear() {
61
+ this.vault.clear();
62
+ }
63
+ keys() {
64
+ return Array.from(this.vault.keys());
65
+ }
66
+ }
67
+ class NamespacedStore {
68
+ data = new Map();
69
+ name;
70
+ constructor(name) {
71
+ this.name = name;
72
+ }
73
+ set(key, value) {
74
+ this.data.set(key, value);
75
+ }
76
+ get(key) {
77
+ return this.data.get(key);
78
+ }
79
+ delete(key) {
80
+ this.data.delete(key);
81
+ }
82
+ clear(key) {
83
+ if (key) {
84
+ this.data.delete(key);
85
+ }
86
+ else {
87
+ this.data.clear();
88
+ }
89
+ }
90
+ keys() {
91
+ return Array.from(this.data.keys());
92
+ }
93
+ entries() {
94
+ return Array.from(this.data.entries());
95
+ }
96
+ has(key) {
97
+ return this.data.has(key);
98
+ }
99
+ toJSON() {
100
+ const obj = {};
101
+ for (const [key, value] of this.data) {
102
+ obj[key] = value;
103
+ }
104
+ return obj;
105
+ }
106
+ }
107
+ class AuditLog {
108
+ entries = [];
109
+ record(entry) {
110
+ this.entries.push(entry);
111
+ }
112
+ getLog() {
113
+ return [...this.entries];
114
+ }
115
+ getLast(n) {
116
+ return this.entries.slice(-n);
117
+ }
118
+ filterByKey(key) {
119
+ return this.entries.filter((e) => e.key === key);
120
+ }
121
+ filterByOperation(op) {
122
+ return this.entries.filter((e) => e.operation === op);
123
+ }
124
+ filterByNamespace(ns) {
125
+ return this.entries.filter((e) => e.namespace === ns);
126
+ }
127
+ export(format) {
128
+ if (format === "json") {
129
+ return JSON.stringify(this.entries, null, 2);
130
+ }
131
+ if (format === "csv") {
132
+ const headers = [
133
+ "timestamp",
134
+ "lab",
135
+ "test",
136
+ "operation",
137
+ "namespace",
138
+ "key",
139
+ "dataType",
140
+ "success",
141
+ ].join(",");
142
+ const rows = this.entries.map((e) => [
143
+ e.timestamp,
144
+ e.lab,
145
+ e.test,
146
+ e.operation,
147
+ e.namespace || "",
148
+ e.key,
149
+ e.dataType,
150
+ e.success ? "true" : "false",
151
+ ].join(","));
152
+ return [headers, ...rows].join("\n");
153
+ }
154
+ return "";
155
+ }
156
+ clear() {
157
+ this.entries = [];
158
+ }
159
+ }
160
+ class HttpKit {
161
+ authHeader = null;
162
+ requestHistory = [];
163
+ baseHeaders = {
164
+ "Content-Type": "application/json",
165
+ "User-Agent": "FennecKit/1.2.0",
166
+ };
167
+ setAuth(type, credentials) {
168
+ this.authHeader = { type, value: credentials };
27
169
  }
28
- catch {
29
- await writeFile(repotPath, headOfRepotPath + data);
170
+ clearAuth() {
171
+ this.authHeader = null;
172
+ }
173
+ getAuthHeader() {
174
+ if (!this.authHeader)
175
+ return {};
176
+ if (this.authHeader.type === "bearer") {
177
+ return { Authorization: `Bearer ${this.authHeader.value}` };
178
+ }
179
+ else if (this.authHeader.type === "api-key") {
180
+ return { "X-API-Key": this.authHeader.value };
181
+ }
182
+ else if (this.authHeader.type === "basic") {
183
+ return { Authorization: `Basic ${this.authHeader.value}` };
184
+ }
185
+ return {};
186
+ }
187
+ async makeRequest(method, url, body, options = {}) {
188
+ const startTime = Date.now();
189
+ const requestId = `req_\( {Date.now()}_ \){Math.random().toString(36).substr(2, 9)}`;
190
+ const headers = {
191
+ ...this.baseHeaders,
192
+ ...this.getAuthHeader(),
193
+ ...(options.headers || {}),
194
+ };
195
+ // Use AbortController for timeout (RequestInit does not support `timeout`)
196
+ const controller = new AbortController();
197
+ const timeoutMs = options.timeout ?? 30000;
198
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
199
+ const reqConfig = {
200
+ method,
201
+ headers,
202
+ signal: controller.signal,
203
+ redirect: options.followRedirects !== false ? "follow" : "manual",
204
+ };
205
+ if (body) {
206
+ reqConfig.body = typeof body === "string" ? body : JSON.stringify(body);
207
+ }
208
+ let lastError = null;
209
+ const maxRetries = options.retry?.max || 1;
210
+ const retryDelay = options.retry?.delay || 1000;
211
+ try {
212
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
213
+ try {
214
+ const response = await fetch(url, reqConfig);
215
+ const duration = Date.now() - startTime;
216
+ let data = null;
217
+ const contentType = response.headers.get("content-type");
218
+ if (contentType?.includes("application/json")) {
219
+ data = await response.json();
220
+ }
221
+ else {
222
+ data = await response.text();
223
+ }
224
+ const httpResponse = {
225
+ status: response.status,
226
+ statusText: response.statusText,
227
+ headers: Object.fromEntries(response.headers.entries()),
228
+ data,
229
+ raw: response,
230
+ };
231
+ this.recordRequest({
232
+ id: requestId,
233
+ timestamp: new Date().toISOString(),
234
+ method,
235
+ url,
236
+ status: response.status,
237
+ duration,
238
+ headers,
239
+ requestBody: body,
240
+ responseBody: data,
241
+ });
242
+ return httpResponse;
243
+ }
244
+ catch (error) {
245
+ lastError = error;
246
+ if (attempt < maxRetries - 1) {
247
+ await new Promise((resolve) => setTimeout(resolve, retryDelay));
248
+ }
249
+ }
250
+ }
251
+ }
252
+ finally {
253
+ clearTimeout(timeoutId);
254
+ }
255
+ const duration = Date.now() - startTime;
256
+ this.recordRequest({
257
+ id: requestId,
258
+ timestamp: new Date().toISOString(),
259
+ method,
260
+ url,
261
+ status: 0,
262
+ duration,
263
+ headers,
264
+ requestBody: body,
265
+ error: lastError?.message,
266
+ });
267
+ throw lastError || new Error(`HTTP request failed: ${method} ${url}`);
268
+ }
269
+ recordRequest(req) {
270
+ this.requestHistory.push(req);
271
+ }
272
+ async get(url, options) {
273
+ return this.makeRequest("GET", url, undefined, options);
274
+ }
275
+ async post(url, body, options) {
276
+ return this.makeRequest("POST", url, body, options);
277
+ }
278
+ async put(url, body, options) {
279
+ return this.makeRequest("PUT", url, body, options);
280
+ }
281
+ async patch(url, body, options) {
282
+ return this.makeRequest("PATCH", url, body, options);
283
+ }
284
+ async delete(url, options) {
285
+ return this.makeRequest("DELETE", url, undefined, options);
286
+ }
287
+ getRequestHistory() {
288
+ return [...this.requestHistory];
289
+ }
290
+ clearHistory() {
291
+ this.requestHistory = [];
292
+ }
293
+ getLastRequest() {
294
+ return this.requestHistory[this.requestHistory.length - 1];
30
295
  }
31
296
  }
297
+ // ====================== Lab Context ======================
32
298
  export async function newLabs(name, fn, retCount = 0) {
33
299
  let logs = `## ${name} 🌏\n\n\`\`\`\n`;
34
300
  let currentTest = "";
301
+ const Store = new Map();
302
+ const secretVault = new SecretVault();
303
+ const namespaces = new Map();
35
304
  const temp = new Map();
305
+ const http = new HttpKit();
306
+ const audit = new AuditLog();
307
+ const ttlMap = new Map();
36
308
  const Context = {
37
309
  out: () => {
38
310
  throw new Error("__Lab_Out__");
@@ -66,26 +338,91 @@ export async function newLabs(name, fn, retCount = 0) {
66
338
  logs += `[🟡] ${currentTest}: ${msg}\n`;
67
339
  console.log(` ⚠️ [Warning] ${currentTest} -> ${msg}`);
68
340
  },
341
+ // Store
69
342
  setStore: (key, value) => {
70
343
  logs += `[⚙️] [STORE] set "${key}"\n`;
71
344
  Store.set(key, value);
345
+ audit.record({
346
+ timestamp: new Date().toISOString(),
347
+ lab: name,
348
+ test: currentTest,
349
+ operation: "set",
350
+ key,
351
+ dataType: typeof value,
352
+ success: true,
353
+ });
72
354
  },
73
355
  getStore: (key) => {
74
356
  logs += `[⚙️] [STORE] get "${key}"\n`;
357
+ audit.record({
358
+ timestamp: new Date().toISOString(),
359
+ lab: name,
360
+ test: currentTest,
361
+ operation: "get",
362
+ key,
363
+ dataType: "unknown",
364
+ success: true,
365
+ });
75
366
  return Store.get(key);
76
367
  },
77
368
  clearStore: (key) => {
78
369
  if (key) {
79
370
  logs += `[⚙️] [STORE] cleared key "${key}"\n`;
80
- console.log(` 🧹 [Store] Cleared: "${key}"`);
81
371
  Store.delete(key);
82
372
  }
83
373
  else {
84
374
  logs += `[⚙️] [STORE] cleared all data\n`;
85
- console.log(` 🧹 [Store] Cleared all Store data`);
86
375
  Store.clear();
87
376
  }
88
377
  },
378
+ // Secrets
379
+ setSecret: (key, value) => {
380
+ logs += `[🔐] [SECRET] set "${key}"\n`;
381
+ secretVault.set(key, value);
382
+ audit.record({
383
+ timestamp: new Date().toISOString(),
384
+ lab: name,
385
+ test: currentTest,
386
+ operation: "setSecret",
387
+ key,
388
+ dataType: "secret",
389
+ success: true,
390
+ });
391
+ },
392
+ getSecret: (key) => {
393
+ logs += `[🔐] [SECRET] get "${key}"\n`;
394
+ audit.record({
395
+ timestamp: new Date().toISOString(),
396
+ lab: name,
397
+ test: currentTest,
398
+ operation: "getSecret",
399
+ key,
400
+ dataType: "secret",
401
+ success: true,
402
+ });
403
+ return secretVault.get(key);
404
+ },
405
+ clearSecret: (key) => {
406
+ if (key) {
407
+ logs += `[🔐] [SECRET] cleared key "${key}"\n`;
408
+ secretVault.delete(key);
409
+ }
410
+ else {
411
+ logs += `[🔐] [SECRET] cleared all data\n`;
412
+ secretVault.clear();
413
+ }
414
+ },
415
+ // Namespaces
416
+ namespace: (ns) => {
417
+ if (!namespaces.has(ns)) {
418
+ namespaces.set(ns, new NamespacedStore(ns));
419
+ }
420
+ return namespaces.get(ns);
421
+ },
422
+ getNamespace: (ns) => {
423
+ return namespaces.get(ns);
424
+ },
425
+ // Temp
89
426
  setTemp: (key, value) => {
90
427
  logs += `[⏱️] [TEMP] set "${key}"\n`;
91
428
  temp.set(key, value);
@@ -94,6 +431,34 @@ export async function newLabs(name, fn, retCount = 0) {
94
431
  logs += `[⏱️] [TEMP] get "${key}"\n`;
95
432
  return temp.get(key);
96
433
  },
434
+ http,
435
+ audit,
436
+ // TTL
437
+ setStoreWithTTL: (key, value, ttlMs) => {
438
+ Context.setStore(key, value);
439
+ const existingTimer = ttlMap.get(key);
440
+ if (existingTimer)
441
+ clearTimeout(existingTimer);
442
+ const timer = setTimeout(() => {
443
+ Store.delete(key);
444
+ ttlMap.delete(key);
445
+ logs += `[⏰] [TTL] expired key "${key}"\n`;
446
+ }, ttlMs);
447
+ ttlMap.set(key, timer);
448
+ },
449
+ setSecretWithTTL: (key, value, ttlMs) => {
450
+ Context.setSecret(key, value);
451
+ const existingTimer = ttlMap.get(`secret:${key}`);
452
+ if (existingTimer)
453
+ clearTimeout(existingTimer);
454
+ const timer = setTimeout(() => {
455
+ secretVault.delete(key);
456
+ ttlMap.delete(`secret:${key}`);
457
+ logs += `[⏰] [TTL] expired secret "${key}"\n`;
458
+ }, ttlMs);
459
+ ttlMap.set(`secret:${key}`, timer);
460
+ },
461
+ // Testing
97
462
  test: async (testName, testFn) => {
98
463
  currentTest = testName;
99
464
  try {
@@ -103,7 +468,7 @@ export async function newLabs(name, fn, retCount = 0) {
103
468
  console.log(` 🐛 [Bug Exception] in "${testName}":`, e.message || e);
104
469
  throw e;
105
470
  }
106
- }
471
+ },
107
472
  };
108
473
  console.log(`\n🔬 [Lab Initiated]: ${name}`);
109
474
  try {
@@ -113,36 +478,22 @@ export async function newLabs(name, fn, retCount = 0) {
113
478
  if (err.message === "__Lab_Out__") {
114
479
  logs += "```\n";
115
480
  temp.clear();
116
- return await writeRepot(logs);
481
+ ttlMap.forEach((timer) => clearTimeout(timer));
482
+ // Write report here
483
+ return;
117
484
  }
118
485
  else if (err.message === "__Restart__") {
486
+ // Fixed: was newLabsV12
119
487
  return newLabs(name, fn, retCount + 1);
120
488
  }
121
489
  console.log(`❌ [Lab Failed]: ${name}\n`);
122
- await writeRepot(logs + "```\n");
123
490
  temp.clear();
491
+ ttlMap.forEach((timer) => clearTimeout(timer));
124
492
  return;
125
493
  }
126
494
  logs += "```\n";
495
+ await report(logs);
127
496
  console.log(`✅ [Lab Success]: ${name} completed successfully.\n`);
128
497
  temp.clear();
129
- await writeRepot(logs);
130
- }
131
- // Global Store hadels
132
- export function clearStore(key) {
133
- if (key) {
134
- Store.delete(key);
135
- console.log(`🧹 [Global] Cleared store key: "${key}"`);
136
- }
137
- else {
138
- Store.clear();
139
- console.log(`🧹 [Global] Cleared all Store data`);
140
- }
141
- }
142
- export function getStoreState() {
143
- return new Map(Store);
498
+ ttlMap.forEach((timer) => clearTimeout(timer));
144
499
  }
145
- process.on('exit', () => {
146
- console.log("[⛔] All Labs stopped");
147
- Store.clear();
148
- });
@@ -0,0 +1,9 @@
1
+ interface TestContext {
2
+ succes: (msg: string) => void;
3
+ err: (msg: string) => never;
4
+ log: (msg: string) => void;
5
+ worrn: (msg: string) => void;
6
+ }
7
+ export declare function testing<T>(fn: (t: TestContext) => T | Promise<T>): Promise<T | void>;
8
+ export {};
9
+ //# sourceMappingURL=testing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../../src/libs/testing.ts"],"names":[],"mappings":"AAiCA,UAAU,WAAW;IACnB,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9B,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,KAAK,CAAC;IAC5B,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3B,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B;AAKD,wBAAsB,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,WAAW,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAc1F"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fenneckit",
3
- "version": "1.0.4",
3
+ "version": "1.2.1",
4
4
  "description": "A tiny, fast & adorable testing kit. Lightweight test framework with zero config – easy to hold, easy to run.",
5
5
  "keywords": [
6
6
  "testing",
@@ -29,16 +29,24 @@
29
29
  "author": "lasith ruwantha amrwansha",
30
30
  "type": "module",
31
31
  "main": "index.js",
32
+ "types":"./dist/index.d.ts",
33
+ "exports":{
34
+ ".":{
35
+ "types":"./dist/index.d.ts",
36
+ "import": "./dist/index.js"
37
+ }
38
+ },
32
39
  "scripts": {
33
40
  "eslint": "eslint .",
34
41
  "build": "tsc",
35
42
  "test": "cd test && node ../dist/libs/fenneckit.js"
36
43
  },
37
- "bin":{
38
- "fenneckit": "./bin/fenneckit"
44
+ "bin": {
45
+ "fenneckit": "./bin/fenneckit"
39
46
  },
40
47
  "dependencies": {
41
48
  "chalk": "^6.0.0",
49
+ "crypto": "^1.0.1",
42
50
  "fs-extra": "^11.4.0",
43
51
  "path": "^0.12.7"
44
52
  },
@@ -51,5 +59,8 @@
51
59
  "tsx": "^4.23.13",
52
60
  "typescript": "^6.0.3",
53
61
  "typescript-eslint": "^8.70.0"
62
+ },
63
+ "engines":{
64
+ "node":">=20"
54
65
  }
55
66
  }
package/types.d.ts ADDED
@@ -0,0 +1,39 @@
1
+ export interface HttpResponse<T = any> {
2
+ status: number;
3
+ statusText: string;
4
+ headers: Record<string, string>;
5
+ data: T;
6
+ raw: Response;
7
+ }
8
+ export interface RequestOptions {
9
+ headers?: Record<string, string>;
10
+ timeout?: number;
11
+ retry?: {
12
+ max: number;
13
+ delay: number;
14
+ };
15
+ followRedirects?: boolean;
16
+ }
17
+ export interface TracedRequest {
18
+ id: string;
19
+ timestamp: string;
20
+ method: string;
21
+ url: string;
22
+ status: number;
23
+ duration: number;
24
+ headers: Record<string, string>;
25
+ requestBody?: any;
26
+ responseBody?: any;
27
+ error?: string;
28
+ }
29
+ export interface AuditEntry {
30
+ timestamp: string;
31
+ lab: string;
32
+ test: string;
33
+ operation: "set" | "get" | "delete" | "clear" | "setSecret" | "getSecret";
34
+ namespace?: string;
35
+ key: string;
36
+ dataType: string;
37
+ success: boolean;
38
+ }
39
+ //# sourceMappingURL=types.d.ts.map
package/types.d.ts.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY,CAAC,CAAC,GAAG,GAAG;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,EAAE,CAAC,CAAC;IACR,GAAG,EAAE,QAAQ,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACvC,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,WAAW,CAAC,EAAE,GAAG,CAAC;IAClB,YAAY,CAAC,EAAE,GAAG,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,KAAK,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,GAAG,WAAW,GAAG,WAAW,CAAC;IAC1E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;CAClB"}
package/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ export default function report(data: string): Promise<void>;
2
+ //# sourceMappingURL=report.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../src/utility/report.ts"],"names":[],"mappings":"AAoBA,wBAA8B,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAShE"}
@@ -0,0 +1,26 @@
1
+ import { access, writeFile } from "fs/promises";
2
+ import path from "path";
3
+ const d = new Date();
4
+ const nowDate = d.toISOString().split('T')[0].replaceAll('-', '/');
5
+ const Store = new Map();
6
+ const headOfRepotPath = `
7
+ # FennecKit 🦊 Report
8
+
9
+ **🚀 Version:** 1.2.0
10
+
11
+ **⏰ Date:** ${nowDate}
12
+
13
+ **✨ Features:** Zero Config • Sequential Labs • Inter-Lab Data Sharing • Store Management
14
+
15
+ ---\n\n
16
+ `;
17
+ export default async function report(data) {
18
+ const repotPath = path.join(process.cwd(), "fenneckit.md");
19
+ try {
20
+ await access(repotPath);
21
+ await writeFile(repotPath, data, { flag: 'a' });
22
+ }
23
+ catch {
24
+ await writeFile(repotPath, headOfRepotPath + data);
25
+ }
26
+ }