ff-automationv2 2.1.3-beta.5 → 2.1.3-beta.7

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/RELEASE_GUIDE.md CHANGED
@@ -3,7 +3,7 @@
3
3
  git checkout feature/your-feature-name
4
4
  git add .
5
5
  git commit -m "feat: new changes"
6
- git pull --rebase
6
+ git pull
7
7
  npm version prerelease --preid=beta
8
8
  git push --follow-tags
9
9
 
package/eslint.config.ts CHANGED
@@ -4,6 +4,9 @@ import tseslint from "typescript-eslint";
4
4
  import { defineConfig } from "eslint/config";
5
5
 
6
6
  export default defineConfig([
7
+ {
8
+ ignores: ["src/tests/**", "dist/**", "node_modules/**"]
9
+ },
7
10
  {
8
11
  files: ["**/*.{js,mjs,cjs,ts,mts,cts}"],
9
12
  plugins: { js },
@@ -15,6 +18,7 @@ export default defineConfig([
15
18
 
16
19
  {
17
20
  rules: {
21
+ "no-useless-escape": "off",
18
22
  "no-console": ["error", { allow: ["warn", "error"] }],
19
23
  "@typescript-eslint/no-explicit-any": "off",
20
24
  "@typescript-eslint/no-unused-vars": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ff-automationv2",
3
- "version": "2.1.3-beta.5",
3
+ "version": "2.1.3-beta.7",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "This lib is used to automate the manual testcase",
@@ -14,7 +14,7 @@
14
14
  },
15
15
  "scripts": {
16
16
  "builds": "npm run lint && tsc",
17
- "build": "tsc --pretty --listEmittedFiles && echo Build Successful",
17
+ "build": "npm run lint && tsc --pretty --listEmittedFiles && echo Build Successful",
18
18
  "prepare": "npm run build",
19
19
  "lint": "eslint src --max-warnings=0",
20
20
  "test": "npm run build && node dist/tests/test12.js",
@@ -1,7 +1,5 @@
1
- type verifyActionArgs = {
2
- extractedDomJson: string;
3
- priorAndNextSteps: string[];
4
- }
1
+ import { verifyActionArgs } from "../../../core/types/promptType.js"
2
+
5
3
 
6
4
  export async function verifyActionExtractorPrompt({
7
5
  extractedDomJson,
@@ -41,7 +39,7 @@ export async function verifyActionExtractorPrompt({
41
39
 
42
40
  const elementType = ['link', 'textfield', 'icon', 'button', 'radioButton', 'text', 'textarea', 'image', 'dropdown', 'checkbox', 'tab', 'action overflow button', 'hamburger icon', 'toggle button', 'suggestion', 'time picker', 'date picker', 'toaster message', 'card', 'tooltip', 'option', 'calender', 'sliders', 'visual testing'];
43
41
  const prompt = `You are an intelligent assistant that extracts structured UI action data.
44
- Given the step, the simplified DOM: ${extractedDomJson}, and the list of NLP names: {nlp_list}.
42
+ Given the step, the simplified DOM: ${extractedDomJson}, and the list of NLP names: ${nlpList}.
45
43
 
46
44
  Select the perfect matching NLP name from the list that best fits the step's intent.
47
45
  **The NLP name must match exactly one value from the approved NLP list. Do not generate or suggest any new NLP names under any condition.**
@@ -10,6 +10,7 @@ import { clear } from "./interaction/clear/clear.js";
10
10
  import { clearAndEnter } from "./interaction/clear/clearAndEnter.js";
11
11
  import { ScriptDataAppender } from "../../fireflinkData/fireflinkScript/scriptGenrationData.js";
12
12
  import { ElementGetter } from "../../fireflinkData/fireflinkLocators/getListOfLocators.js";
13
+ import { logger } from "../../utils/logger/logData.js"
13
14
  export class ActionExecutor implements IActionExecutor {
14
15
  constructor(private readonly browser: WebdriverIO.Browser,
15
16
  private scriptDataAppender: ScriptDataAppender,
@@ -27,7 +28,9 @@ export class ActionExecutor implements IActionExecutor {
27
28
  });
28
29
  }
29
30
  catch (error) {
30
- throw new Error(`Click action failed ${error}`);
31
+ logger.error("Error in [ActionExecutor]", error)
32
+
33
+ throw error;
31
34
  }
32
35
  }
33
36
 
@@ -39,7 +42,9 @@ export class ActionExecutor implements IActionExecutor {
39
42
  });
40
43
  }
41
44
  catch (error) {
42
- throw new Error(`Click action failed ${error}`);
45
+ logger.error("Error in [ActionExecutor]", error)
46
+
47
+ throw error;
43
48
  }
44
49
  }
45
50
 
@@ -51,7 +56,9 @@ export class ActionExecutor implements IActionExecutor {
51
56
  });
52
57
  }
53
58
  catch (error) {
54
- throw new Error(`Click action failed ${error}`);
59
+ logger.error("Error in [ActionExecutor]", error)
60
+
61
+ throw error;
55
62
  }
56
63
  }
57
64
 
@@ -65,7 +72,9 @@ export class ActionExecutor implements IActionExecutor {
65
72
  });
66
73
  }
67
74
  catch (error) {
68
- throw new Error(`Click action failed ${error}`);
75
+ logger.error("Error in [ActionExecutor]", error)
76
+
77
+ throw error;
69
78
  }
70
79
  }
71
80
  async click(pageDOM: string, selector: string, fireflinkIndex: string, elementName: string, elementType: string): Promise<void> {
@@ -83,7 +92,9 @@ export class ActionExecutor implements IActionExecutor {
83
92
  });
84
93
  }
85
94
  catch (error) {
86
- throw new Error(`Click action failed ${error}`);
95
+ logger.error("Error in [ActionExecutor]", error)
96
+
97
+ throw error;
87
98
  }
88
99
  }
89
100
  async enterInput(selector: string, value: string, fireflinkIndex: string, pageDOM: string, elementName: string, elementType: string): Promise<void> {
@@ -102,7 +113,9 @@ export class ActionExecutor implements IActionExecutor {
102
113
  });
103
114
  }
104
115
  catch (error) {
105
- throw new Error(`Click action failed ${error}`);
116
+ logger.error("Error in [ActionExecutor]", error)
117
+
118
+ throw error;
106
119
  }
107
120
  }
108
121
  async maximize(): Promise<void> {
@@ -113,7 +126,9 @@ export class ActionExecutor implements IActionExecutor {
113
126
  });
114
127
  }
115
128
  catch (error) {
116
- throw new Error(`Click action failed ${error}`);
129
+ logger.error("Error in [ActionExecutor]", error)
130
+
131
+ throw error;
117
132
  }
118
133
  }
119
134
 
@@ -132,7 +147,9 @@ export class ActionExecutor implements IActionExecutor {
132
147
  });
133
148
  }
134
149
  catch (error) {
135
- throw new Error(`Click action failed ${error}`);
150
+ logger.error("Error in [ActionExecutor]", error)
151
+
152
+ throw error;
136
153
  }
137
154
  }
138
155
 
@@ -152,7 +169,9 @@ export class ActionExecutor implements IActionExecutor {
152
169
  });
153
170
  }
154
171
  catch (error) {
155
- throw new Error(`Click action failed ${error}`);
172
+ logger.error("Error in [ActionExecutor]", error)
173
+
174
+ throw error;
156
175
  }
157
176
  }
158
177
 
@@ -22,7 +22,6 @@ export async function clear(args: clearActionInterface): Promise<void> {
22
22
 
23
23
  }
24
24
  catch (error: any) {
25
- console.log(error);
26
25
  throw new Error("clear action failed", { cause: error });
27
26
 
28
27
  }
@@ -1,6 +1,4 @@
1
1
  import { clearAndEnterActionInterface } from "../../interface/clearActionInterface.js";
2
- import { logger } from "../../../../utils/logger/logData.js";
3
-
4
2
  export async function clearAndEnter(args: clearAndEnterActionInterface): Promise<void> {
5
3
  try {
6
4
 
@@ -25,7 +23,6 @@ export async function clearAndEnter(args: clearAndEnterActionInterface): Promise
25
23
  });
26
24
 
27
25
  } catch (error: any) {
28
- console.log(error);
29
26
  throw new Error("clear and enter action failed", { cause: error });
30
27
  }
31
28
  }
@@ -20,6 +20,6 @@ export async function click(args: ClickInterface): Promise<void> {
20
20
  }]
21
21
  });
22
22
  } catch (error: any) {
23
- throw new Error(`Click action failed ${error}`);
23
+ throw new Error(`Click action failed :`, { cause: error });
24
24
  }
25
25
  }
@@ -29,7 +29,7 @@ export async function enterInput(args: EnterInputInterface): Promise<void> {
29
29
 
30
30
  }
31
31
  catch (error: any) {
32
- throw new Error(`enter action failed ${error}`);
32
+ throw new Error(`enter action failed:`, { cause: error });
33
33
  }
34
34
 
35
35
  }
@@ -0,0 +1,14 @@
1
+ export const allKeywordAction =
2
+ ["enter",
3
+ "wait",
4
+ "verify",
5
+ "scroll",
6
+ "navigate",
7
+ "click",
8
+ "maximize",
9
+ "get",
10
+ "upload",
11
+ "close", "open",
12
+ "drag_and_drop",
13
+ "switch",
14
+ "cleartext"];
@@ -1,3 +1,4 @@
1
+ import { AutomationRequest } from "../../core/interfaces/executionDetails.js";
1
2
  export interface IAutomationRunner {
2
- run(): Promise<void>;
3
+ run(args:AutomationRequest): Promise<void>;
3
4
  }
@@ -1,6 +1,6 @@
1
1
  import { ExecutionContext } from "../main/executionContext.js";
2
2
  import { ActionExecutor } from "../../automation/actions/executor.js";
3
-
3
+ import { logger } from "../../utils/logger/logData.js"
4
4
  type ActionHandler = (result?: any) => Promise<void>;
5
5
 
6
6
  export function createActionHandlers(
@@ -24,12 +24,12 @@ export function createActionHandlers(
24
24
  await fn(executor, result);
25
25
  }
26
26
  catch (error) {
27
- throw new Error(`Error occuried in createActionHandlers , error : ${error}`)
27
+ logger.error("Error in createActionHandlers", error)
28
+ throw error
28
29
  }
29
30
  };
30
31
 
31
32
  return {
32
-
33
33
  open: async () => {
34
34
  try {
35
35
  await context.session.open({
@@ -52,7 +52,10 @@ export function createActionHandlers(
52
52
  });
53
53
  }
54
54
  catch (error) {
55
- throw new Error(`Error occuried in createActionHandlers , error : ${error}`)
55
+
56
+ logger.error("Error in createActionHandlers", error)
57
+
58
+ throw error;
56
59
  }
57
60
  },
58
61
 
@@ -61,7 +64,9 @@ export function createActionHandlers(
61
64
  await context.session.close();
62
65
  }
63
66
  catch (error) {
64
- throw new Error(`Error occuried in createActionHandlers , error : ${error}`)
67
+ logger.error("Error in createActionHandlers", error)
68
+
69
+ throw error;
65
70
  }
66
71
  },
67
72
 
@@ -13,15 +13,14 @@ import { INPUTLESS_ACTIONS, ELEMENTLESS_ACTION } from "../constants/supportedAct
13
13
  import { DomProcessingEngine } from "../../domAnalysis/getRelaventElements.js"
14
14
  import { getAnnotatedDOM } from "../../utils/DomExtraction/jsForAttributeInjection.js"
15
15
  import { logger } from "../../utils/logger/logData.js"
16
+ import { allKeywordAction } from "../constants/allAction.js";
16
17
  export class AutomationRunner implements IAutomationRunner {
17
18
  static sessionTerminationDetails: Record<string, boolean> = {};
18
19
  constructor(
19
- private readonly request: AutomationRequest,
20
20
  private pageLoad: number = 20000,
21
21
  private implicit: number = 15000,
22
- private tokensConsumed: number = 0
23
22
 
24
- ) { AutomationRunner.sessionTerminationDetails[request.testCaseId] = false }
23
+ ) { }
25
24
 
26
25
  static getSessionTerminationInfo(testCaseId: string): boolean {
27
26
  return AutomationRunner.sessionTerminationDetails[testCaseId]
@@ -35,18 +34,17 @@ export class AutomationRunner implements IAutomationRunner {
35
34
  domInfo: any,
36
35
  extractedRelevantDom: any,
37
36
  stepProcessor: StepProcessor,
38
- scriptRunner: ScriptRunner
37
+ scriptRunner: ScriptRunner,
38
+ request: AutomationRequest
39
39
  ) {
40
40
  try {
41
41
  logger.info("Starting cleanup process...");
42
42
  if (context?.session) {
43
43
  try {
44
44
  const browser = await context.session.getCurrentBrowser();
45
- // if (browser) {
46
- // await browser.deleteSession?.();
47
- // }
48
- } catch (e) {
49
- logger.error("Browser cleanup failed:", e);
45
+ logger.info("Still browser session is active, session id :", browser.sessionId)
46
+ } catch (error) {
47
+ logger.error("Browser cleanup failed:", error);
50
48
  }
51
49
  }
52
50
 
@@ -59,7 +57,7 @@ export class AutomationRunner implements IAutomationRunner {
59
57
 
60
58
  scriptRunner = null as any;
61
59
 
62
- delete AutomationRunner.sessionTerminationDetails[this.request.testCaseId];
60
+ delete AutomationRunner.sessionTerminationDetails[request.testCaseId];
63
61
 
64
62
  if (global.gc) {
65
63
  global.gc();
@@ -73,18 +71,19 @@ export class AutomationRunner implements IAutomationRunner {
73
71
  }
74
72
 
75
73
 
76
- async run(): Promise<void> {
74
+ async run(request: AutomationRequest): Promise<void> {
75
+ AutomationRunner.sessionTerminationDetails[request.testCaseId] = false;
77
76
  const apiService = new FireFlinkApiService();
78
77
  const scriptRunner = new ScriptRunner(apiService);
79
- const context = new ExecutionContext(this.request);
78
+ const context = new ExecutionContext(request);
80
79
  const configProvider = new ServiceProviderBaseUrlProvider();
81
- const baseUrl = configProvider.getBaseUrl(this.request.serviceProvider);
80
+ const baseUrl = configProvider.getBaseUrl(request.serviceProvider);
82
81
  let domInfo: any = null;
83
82
  let extractedRelevantDom: any = null;
84
- const llm = new llmAction(this.request.apiKey, baseUrl, this.request.model, this.request.visionApikey);
83
+ const llm = new llmAction(request.apiKey, baseUrl, request.model, request.visionApikey);
85
84
  const stepProcessor = new StepProcessor(llm);
86
85
 
87
- const stepResult = await stepProcessor.getLLMResponse({ type: PromptType.USER_STORY_TO_LIST, args: {}, input: { userStory: this.request.userStory } });
86
+ const stepResult = await stepProcessor.getLLMResponse({ type: PromptType.USER_STORY_TO_LIST, args: {}, input: { userStory: request.userStory } });
88
87
 
89
88
  const actionHandlers = createActionHandlers(
90
89
  context,
@@ -97,40 +96,25 @@ export class AutomationRunner implements IAutomationRunner {
97
96
  if (listOfSteps.length == 0) {
98
97
  throw new Error("No executable manual steps were returned by the LLM.");
99
98
  }
100
-
101
- logger.info(listOfSteps)
102
- const allKeywordAction = ["enter", "wait", "verify", "scroll", "navigate", "click", "maximize", "get", "upload", "close", "open", "drag_and_drop", "switch", "cleartext"];
103
-
99
+ logger.info("Test steps for execution ", listOfSteps)
104
100
  for (const step of listOfSteps) {
105
101
  try {
106
- if (AutomationRunner.getSessionTerminationInfo(this.request.testCaseId)) { break; }
107
-
108
- logger.info
109
- (
110
- `Processing step ${stepCount}: "${step}"`
111
- );
112
-
102
+ if (AutomationRunner.getSessionTerminationInfo(request.testCaseId)) { break; }
103
+ logger.info(`Processing step ${stepCount}: ${step}`);
113
104
  const start = Math.max(0, stepCount - 3);
114
105
  const end = Math.min(listOfSteps.length, stepCount + 3);
115
106
  const priorAndNextSteps = listOfSteps.slice(start, end);
116
-
117
107
  const result = await stepProcessor.getLLMResponse({
118
108
  type: PromptType.KEYWORD_EXTRACTOR,
119
109
  args: { priorAndNextSteps },
120
110
  input: { currentStep: step }
121
111
  });
122
-
123
112
  logger.info(JSON.stringify(result, null, 2))
124
-
125
113
  const action = result.response.action?.toLowerCase();
126
-
127
114
  if (!allKeywordAction.includes(action)) {
128
115
  throw new Error(`Unsupported action at action or keyword exracter: ${action}`);
129
116
  }
130
-
131
117
  let handler = actionHandlers[action];
132
-
133
-
134
118
  if (INPUTLESS_ACTIONS.includes(action)) {
135
119
  await handler(result);
136
120
  stepCount++;
@@ -156,18 +140,16 @@ export class AutomationRunner implements IAutomationRunner {
156
140
  }
157
141
  const driver = await context.session.getCurrentBrowser();
158
142
  domInfo = await getAnnotatedDOM(driver);
159
- await logger.saveDOM(domInfo.dom, `annotated-dom-${stepCount}`);
160
-
143
+ logger.saveDOM(domInfo.dom, `annotated-dom-${stepCount}`);
161
144
  extractedRelevantDom = domProcessor.process({
162
145
  keywords: result.response.keywords,
163
146
  rawDom: domInfo.dom,
164
147
  stepCount: stepCount
165
148
  });
166
-
167
- await logger.saveJSON(extractedRelevantDom, `relevant-dom-${stepCount}`);
149
+ logger.saveJSON(extractedRelevantDom, `relevant-dom-${stepCount}`);
168
150
  let stepResult: any;
169
151
  if (action == "verify") {
170
- const stepResult = await stepProcessor.getLLMResponse({
152
+ stepResult = await stepProcessor.getLLMResponse({
171
153
  type: PromptType.VERIFY_PROMPT,
172
154
  args: {
173
155
  extractedDomJson: JSON.stringify(extractedRelevantDom, null, 2),
@@ -224,35 +206,35 @@ export class AutomationRunner implements IAutomationRunner {
224
206
  elementsData: [],
225
207
  stepInputs: []
226
208
  });
227
-
228
209
  logger.error(`Error executing step "${step}":`, error);
229
210
  break;
230
211
  }
231
212
  }
232
213
  const payload: IPayload = {
233
- scriptName: this.request.scriptName,
234
- scriptType: this.request.scriptType,
235
- projectId: this.request.projectId,
236
- testCaseId: this.request.testCaseId,
237
- promptId: this.request.promptId,
238
- pageDetails: this.request.pageDetails,
239
- generatedBy: this.request.generatedBy,
240
- webSocketId: this.request.webSocketId,
241
- licenseType: this.request.licenseType,
242
- licenseId: this.request.licenseId,
243
- userId: this.request.userId,
244
- topic: this.request.topic,
245
- projectType: this.request.projectType,
214
+ scriptName: request.scriptName,
215
+ scriptType: request.scriptType,
216
+ projectId: request.projectId,
217
+ testCaseId: request.testCaseId,
218
+ promptId: request.promptId,
219
+ pageDetails: request.pageDetails,
220
+ generatedBy: request.generatedBy,
221
+ webSocketId: request.webSocketId,
222
+ licenseType: request.licenseType,
223
+ licenseId: request.licenseId,
224
+ userId: request.userId,
225
+ topic: request.topic,
226
+ projectType: request.projectType,
246
227
  tokensConsumed: (await stepProcessor.getResultTokenUsage()).totalTokens,
247
228
  }
248
229
  try {
249
- // await scriptRunner.runScriptFromPayload(
250
- // context.scriptAppender.getData(),
251
- // payload,
252
- // this.request.token,
253
- // this.request.serverHost
254
- // );
230
+ await scriptRunner.runScriptFromPayload(
231
+ context.scriptAppender.getData(),
232
+ payload,
233
+ request.token,
234
+ request.serverHost
235
+ );
255
236
  } catch (error: any) {
237
+
256
238
  throw new Error(
257
239
  "Failed to send payload to FireFlink API:", { cause: error }
258
240
  );
@@ -263,7 +245,8 @@ export class AutomationRunner implements IAutomationRunner {
263
245
  domInfo,
264
246
  extractedRelevantDom,
265
247
  stepProcessor,
266
- scriptRunner
248
+ scriptRunner,
249
+ request
267
250
  );
268
251
  }
269
252
  }
@@ -6,3 +6,9 @@ export enum PromptType {
6
6
  VISION_PROMPT = "visionPrompt",
7
7
  VERIFY_PROMPT = "verifyActionExtractorPrompt"
8
8
  }
9
+
10
+
11
+ export type verifyActionArgs = {
12
+ extractedDomJson: string;
13
+ priorAndNextSteps: string[];
14
+ }
@@ -1,3 +1,4 @@
1
+
1
2
  import * as fuzz from "fuzzball";
2
3
 
3
4
  import { FlatNode } from "./simplifyAndFlatten.js";
@@ -1,12 +1,11 @@
1
- import type { Browser } from "webdriverio";
2
-
1
+ import { logger } from "../../utils/logger/logData.js"
3
2
  export interface AnnotatedDOMResult {
4
3
  dom: string;
5
4
  selectors: Record<string, string>;
6
5
  }
7
6
 
8
7
  export async function getAnnotatedDOM(
9
- browser: Browser
8
+ browser: WebdriverIO.Browser
10
9
  ): Promise<AnnotatedDOMResult> {
11
10
 
12
11
  return await browser.execute<AnnotatedDOMResult, []>(() => {
@@ -32,9 +31,9 @@ export async function getAnnotatedDOM(
32
31
  [rect.left + rect.width / 2, rect.top + rect.height / 2]
33
32
  ];
34
33
 
35
- for (let [x, y] of testPoints) {
34
+ for (const [x, y] of testPoints) {
36
35
 
37
- let topEl = document.elementFromPoint(x, y);
36
+ const topEl = document.elementFromPoint(x, y);
38
37
  if (!topEl) continue;
39
38
 
40
39
  if (topEl === el || el.contains(topEl)) continue;
@@ -115,7 +114,7 @@ export async function getAnnotatedDOM(
115
114
 
116
115
  if (!node || node.nodeType !== 1) return "";
117
116
 
118
- let segments: string[] = [];
117
+ const segments: string[] = [];
119
118
  let current: Element | null = node;
120
119
 
121
120
  while (current && current.nodeType === 1) {
@@ -300,7 +299,10 @@ export async function getAnnotatedDOM(
300
299
  doc.documentElement
301
300
  );
302
301
  }
303
- } catch { }
302
+ } catch (error) {
303
+
304
+ logger.error("Attribute injection failed", error)
305
+ }
304
306
  }
305
307
 
306
308
  el.childNodes.forEach(child => {
@@ -32,7 +32,7 @@ export const enterActionHelper = (
32
32
  return el?.getAttribute("ff-xpath") || "";
33
33
  };
34
34
 
35
- let element = doc.querySelector(
35
+ const element = doc.querySelector(
36
36
  `[ff-inspect="Fire-Flink-${numericFF}"]`
37
37
  );
38
38
 
@@ -40,15 +40,38 @@ export const logger = {
40
40
 
41
41
  fs.appendFileSync(logFilePath, message, "utf-8");
42
42
  },
43
-
44
43
  error: (...args: any[]) => {
45
- const formattedArgs = args.map(arg =>
46
- typeof arg === "object"
47
- ? JSON.stringify(arg, null, 2)
48
- : arg
49
- );
44
+ const formatted = args.map(arg => {
45
+ if (arg instanceof Error) {
46
+ let output = arg.stack || `${arg.name}: ${arg.message}`;
47
+ output = output.replace(
48
+ /invalid session id:\s*invalid session id:/gi,
49
+ "invalid session id:"
50
+ );
51
+
52
+ if (arg.cause instanceof Error) {
53
+ let causeStack = arg.cause.stack || "";
54
+
55
+ causeStack = causeStack.replace(
56
+ /invalid session id:\s*invalid session id:/gi,
57
+ "invalid session id:"
58
+ );
59
+
60
+ output += `\nCaused by: ${causeStack}`;
61
+ }
62
+
63
+ return output;
64
+ }
65
+
66
+ if (typeof arg === "object") {
67
+ return JSON.stringify(arg, null, 2);
68
+ }
69
+
70
+ return String(arg);
71
+ });
50
72
 
51
- const message = `[ERROR] ${istDate}+05:30 - ${formattedArgs.join(" ")}\n`;
73
+ const message =
74
+ `[ERROR] ${new Date().toISOString()} - ${formatted.join(" ")}\n`;
52
75
 
53
76
  fs.appendFileSync(logFilePath, message, "utf-8");
54
77
  },