misoai-web 1.6.0 → 1.6.2
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/dist/es/agent.js +108 -50
- package/dist/es/agent.js.map +1 -1
- package/dist/es/bridge-mode-browser.js +3 -3
- package/dist/es/bridge-mode-browser.js.map +1 -1
- package/dist/es/bridge-mode.js +110 -52
- package/dist/es/bridge-mode.js.map +1 -1
- package/dist/es/chrome-extension.js +109 -51
- package/dist/es/chrome-extension.js.map +1 -1
- package/dist/es/index.js +425 -68
- package/dist/es/index.js.map +1 -1
- package/dist/es/midscene-playground.js +111 -53
- package/dist/es/midscene-playground.js.map +1 -1
- package/dist/es/midscene-server.js +4 -4
- package/dist/es/midscene-server.js.map +1 -1
- package/dist/es/playground.js +108 -50
- package/dist/es/playground.js.map +1 -1
- package/dist/es/playwright-report.js +1 -1
- package/dist/es/playwright-report.js.map +1 -1
- package/dist/es/playwright.js +425 -68
- package/dist/es/playwright.js.map +1 -1
- package/dist/es/puppeteer-agent-launcher.js +424 -67
- package/dist/es/puppeteer-agent-launcher.js.map +1 -1
- package/dist/es/puppeteer.js +424 -67
- package/dist/es/puppeteer.js.map +1 -1
- package/dist/es/utils.js +1 -1
- package/dist/es/utils.js.map +1 -1
- package/dist/es/yaml.js +1 -1
- package/dist/es/yaml.js.map +1 -1
- package/dist/lib/agent.js +108 -50
- package/dist/lib/agent.js.map +1 -1
- package/dist/lib/bridge-mode-browser.js +3 -3
- package/dist/lib/bridge-mode-browser.js.map +1 -1
- package/dist/lib/bridge-mode.js +110 -52
- package/dist/lib/bridge-mode.js.map +1 -1
- package/dist/lib/chrome-extension.js +109 -51
- package/dist/lib/chrome-extension.js.map +1 -1
- package/dist/lib/index.js +425 -68
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/midscene-playground.js +111 -53
- package/dist/lib/midscene-playground.js.map +1 -1
- package/dist/lib/midscene-server.js +4 -4
- package/dist/lib/midscene-server.js.map +1 -1
- package/dist/lib/playground.js +108 -50
- package/dist/lib/playground.js.map +1 -1
- package/dist/lib/playwright-report.js +1 -1
- package/dist/lib/playwright-report.js.map +1 -1
- package/dist/lib/playwright.js +425 -68
- package/dist/lib/playwright.js.map +1 -1
- package/dist/lib/puppeteer-agent-launcher.js +424 -67
- package/dist/lib/puppeteer-agent-launcher.js.map +1 -1
- package/dist/lib/puppeteer.js +424 -67
- package/dist/lib/puppeteer.js.map +1 -1
- package/dist/lib/utils.js +1 -1
- package/dist/lib/utils.js.map +1 -1
- package/dist/lib/yaml.js +1 -1
- package/dist/lib/yaml.js.map +1 -1
- package/dist/types/agent.d.ts +1 -1
- package/dist/types/bridge-mode-browser.d.ts +2 -2
- package/dist/types/bridge-mode.d.ts +2 -2
- package/dist/types/{browser-9b472ffb.d.ts → browser-f205f69d.d.ts} +1 -1
- package/dist/types/chrome-extension.d.ts +2 -2
- package/dist/types/index.d.ts +2 -2
- package/dist/types/midscene-server.d.ts +1 -1
- package/dist/types/{page-ed0ecb44.d.ts → page-c5452809.d.ts} +45 -0
- package/dist/types/playground.d.ts +2 -2
- package/dist/types/playwright.d.ts +2 -2
- package/dist/types/puppeteer-agent-launcher.d.ts +1 -1
- package/dist/types/puppeteer.d.ts +2 -2
- package/dist/types/utils.d.ts +1 -1
- package/dist/types/yaml.d.ts +1 -1
- package/package.json +18 -54
@@ -23,13 +23,13 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
23
23
|
));
|
24
24
|
|
25
25
|
// src/common/utils.ts
|
26
|
+
var import_dayjs = __toESM(require("dayjs"));
|
26
27
|
var import_ai_model = require("misoai-core/ai-model");
|
27
28
|
var import_utils = require("misoai-core/utils");
|
28
29
|
var import_env = require("misoai-shared/env");
|
29
30
|
var import_extractor = require("misoai-shared/extractor");
|
30
31
|
var import_img = require("misoai-shared/img");
|
31
32
|
var import_utils2 = require("misoai-shared/utils");
|
32
|
-
var import_dayjs = __toESM(require("dayjs"));
|
33
33
|
|
34
34
|
// src/web-element.ts
|
35
35
|
var WebElementInfo = class {
|
@@ -448,8 +448,8 @@ var ScriptPlayer = class {
|
|
448
448
|
var import_js_yaml = __toESM(require("js-yaml"));
|
449
449
|
|
450
450
|
// src/yaml/utils.ts
|
451
|
-
var import_utils4 = require("misoai-shared/utils");
|
452
451
|
var import_js_yaml2 = __toESM(require("js-yaml"));
|
452
|
+
var import_utils4 = require("misoai-shared/utils");
|
453
453
|
function interpolateEnvVars(content) {
|
454
454
|
return content.replace(/\$\{([^}]+)\}/g, (_, envVar) => {
|
455
455
|
const value = process.env[envVar.trim()];
|
@@ -625,8 +625,12 @@ var WorkflowMemory = class {
|
|
625
625
|
const workflow = this.workflows.get(workflowId) || this.createEmptyWorkflowData(workflowId);
|
626
626
|
workflow.memory = [...memory];
|
627
627
|
workflow.metadata.totalSteps = workflow.steps.length;
|
628
|
-
workflow.metadata.completedSteps = workflow.steps.filter(
|
629
|
-
|
628
|
+
workflow.metadata.completedSteps = workflow.steps.filter(
|
629
|
+
(s) => s.status === "completed"
|
630
|
+
).length;
|
631
|
+
workflow.metadata.failedSteps = workflow.steps.filter(
|
632
|
+
(s) => s.status === "failed"
|
633
|
+
).length;
|
630
634
|
this.workflows.set(workflowId, workflow);
|
631
635
|
this.enforceRetentionPolicy();
|
632
636
|
}
|
@@ -637,7 +641,9 @@ var WorkflowMemory = class {
|
|
637
641
|
const workflow = this.workflows.get(workflowId) || this.createEmptyWorkflowData(workflowId);
|
638
642
|
workflow.context = { ...workflow.context, ...context };
|
639
643
|
if (context.currentStep) {
|
640
|
-
const existingStep = workflow.steps.find(
|
644
|
+
const existingStep = workflow.steps.find(
|
645
|
+
(s) => s.stepName === context.currentStep
|
646
|
+
);
|
641
647
|
if (!existingStep) {
|
642
648
|
workflow.steps.push({
|
643
649
|
stepId: `step_${workflow.steps.length + 1}`,
|
@@ -682,7 +688,9 @@ var WorkflowMemory = class {
|
|
682
688
|
enforceRetentionPolicy() {
|
683
689
|
const maxWorkflows = 10;
|
684
690
|
if (this.workflows.size > maxWorkflows) {
|
685
|
-
const sortedWorkflows = Array.from(this.workflows.entries()).sort(
|
691
|
+
const sortedWorkflows = Array.from(this.workflows.entries()).sort(
|
692
|
+
([, a], [, b]) => (b.metadata.endTime || b.metadata.startTime) - (a.metadata.endTime || a.metadata.startTime)
|
693
|
+
);
|
686
694
|
const toDelete = sortedWorkflows.slice(maxWorkflows);
|
687
695
|
toDelete.forEach(([workflowId]) => this.workflows.delete(workflowId));
|
688
696
|
}
|
@@ -1249,6 +1257,7 @@ var PageTaskExecutor = class {
|
|
1249
1257
|
actions: [],
|
1250
1258
|
more_actions_needed_by_instruction: false,
|
1251
1259
|
log: "",
|
1260
|
+
summary: "Loaded YAML workflow configuration",
|
1252
1261
|
yamlString
|
1253
1262
|
},
|
1254
1263
|
cache: {
|
@@ -1350,6 +1359,7 @@ var PageTaskExecutor = class {
|
|
1350
1359
|
actions: finalActions,
|
1351
1360
|
more_actions_needed_by_instruction,
|
1352
1361
|
log: log2,
|
1362
|
+
summary: planResult.summary || "Generated action plan from user instruction",
|
1353
1363
|
yamlFlow: planResult.yamlFlow
|
1354
1364
|
},
|
1355
1365
|
cache: {
|
@@ -1405,6 +1415,7 @@ var PageTaskExecutor = class {
|
|
1405
1415
|
actionType: actions[0].type,
|
1406
1416
|
more_actions_needed_by_instruction: true,
|
1407
1417
|
log: "",
|
1418
|
+
summary: action_summary || "Generated VLM action plan",
|
1408
1419
|
yamlFlow: planResult.yamlFlow
|
1409
1420
|
},
|
1410
1421
|
cache: {
|
@@ -1421,7 +1432,9 @@ var PageTaskExecutor = class {
|
|
1421
1432
|
*/
|
1422
1433
|
getPersistentExecutor() {
|
1423
1434
|
if (!this.persistentExecutor || this.persistentExecutor.status === "error") {
|
1424
|
-
const previousMemory = this.workflowMemory.getWorkflowMemory(
|
1435
|
+
const previousMemory = this.workflowMemory.getWorkflowMemory(
|
1436
|
+
this.sessionContext.workflowId
|
1437
|
+
);
|
1425
1438
|
this.persistentExecutor = new import_misoai_core.Executor("Persistent Task Executor", {
|
1426
1439
|
onTaskStart: this.onTaskStartCallback,
|
1427
1440
|
initialMemory: previousMemory
|
@@ -1450,7 +1463,9 @@ var PageTaskExecutor = class {
|
|
1450
1463
|
if (this.persistentExecutor) {
|
1451
1464
|
this.persistentExecutor.clearMemory();
|
1452
1465
|
}
|
1453
|
-
this.workflowMemory.clearWorkflow(
|
1466
|
+
this.workflowMemory.clearWorkflow(
|
1467
|
+
this.sessionContext.workflowId || "default"
|
1468
|
+
);
|
1454
1469
|
}
|
1455
1470
|
/**
|
1456
1471
|
* Mevcut hafızayı döndürür
|
@@ -1462,7 +1477,9 @@ var PageTaskExecutor = class {
|
|
1462
1477
|
* İş akışı hafızasını döndürür
|
1463
1478
|
*/
|
1464
1479
|
getWorkflowMemory() {
|
1465
|
-
return this.workflowMemory.getWorkflowData(
|
1480
|
+
return this.workflowMemory.getWorkflowData(
|
1481
|
+
this.sessionContext.workflowId || "default"
|
1482
|
+
);
|
1466
1483
|
}
|
1467
1484
|
/**
|
1468
1485
|
* Hafıza istatistiklerini döndürür
|
@@ -1470,7 +1487,13 @@ var PageTaskExecutor = class {
|
|
1470
1487
|
getMemoryStats() {
|
1471
1488
|
return this.persistentExecutor?.getMemoryStats() || {
|
1472
1489
|
totalItems: 0,
|
1473
|
-
analytics: {
|
1490
|
+
analytics: {
|
1491
|
+
totalTasks: 0,
|
1492
|
+
memoryHits: 0,
|
1493
|
+
memoryMisses: 0,
|
1494
|
+
averageMemorySize: 0,
|
1495
|
+
memoryEffectiveness: 0
|
1496
|
+
},
|
1474
1497
|
config: this.memoryConfig
|
1475
1498
|
};
|
1476
1499
|
}
|
@@ -1506,11 +1529,14 @@ var PageTaskExecutor = class {
|
|
1506
1529
|
let taskExecutor;
|
1507
1530
|
if (useMemory) {
|
1508
1531
|
taskExecutor = this.getPersistentExecutor();
|
1509
|
-
this.workflowMemory.updateWorkflowContext(
|
1510
|
-
|
1511
|
-
|
1512
|
-
|
1513
|
-
|
1532
|
+
this.workflowMemory.updateWorkflowContext(
|
1533
|
+
{
|
1534
|
+
currentStep: title,
|
1535
|
+
pageInfo: this.sessionContext.pageInfo,
|
1536
|
+
timestamp: Date.now()
|
1537
|
+
},
|
1538
|
+
this.sessionContext.workflowId || "default"
|
1539
|
+
);
|
1514
1540
|
} else {
|
1515
1541
|
taskExecutor = new import_misoai_core.Executor(title, {
|
1516
1542
|
onTaskStart: this.onTaskStartCallback
|
@@ -1876,14 +1902,19 @@ var PageTaskExecutor = class {
|
|
1876
1902
|
*/
|
1877
1903
|
addToMemory(memoryItem) {
|
1878
1904
|
if (!this.persistentExecutor || this.persistentExecutor.status === "error") {
|
1879
|
-
const previousMemory = this.workflowMemory.getWorkflowMemory(
|
1905
|
+
const previousMemory = this.workflowMemory.getWorkflowMemory(
|
1906
|
+
this.sessionContext.workflowId
|
1907
|
+
);
|
1880
1908
|
this.persistentExecutor = new import_misoai_core.Executor("Persistent Task Executor", {
|
1881
1909
|
onTaskStart: this.onTaskStartCallback,
|
1882
1910
|
initialMemory: previousMemory
|
1883
1911
|
});
|
1884
1912
|
}
|
1885
1913
|
this.persistentExecutor.memoryStore?.add(memoryItem);
|
1886
|
-
this.persistentExecutor.memoryAnalytics?.recordMemoryOperation(
|
1914
|
+
this.persistentExecutor.memoryAnalytics?.recordMemoryOperation(
|
1915
|
+
"add",
|
1916
|
+
memoryItem
|
1917
|
+
);
|
1887
1918
|
}
|
1888
1919
|
};
|
1889
1920
|
|
@@ -1972,14 +2003,14 @@ function buildPlans(type, locateParam, param) {
|
|
1972
2003
|
var import_node_assert = __toESM(require("assert"));
|
1973
2004
|
var import_node_fs2 = require("fs");
|
1974
2005
|
var import_node_path2 = require("path");
|
2006
|
+
var import_js_yaml3 = __toESM(require("js-yaml"));
|
1975
2007
|
var import_common2 = require("misoai-shared/common");
|
1976
2008
|
var import_logger3 = require("misoai-shared/logger");
|
1977
2009
|
var import_utils9 = require("misoai-shared/utils");
|
1978
|
-
var import_js_yaml3 = __toESM(require("js-yaml"));
|
1979
2010
|
var import_semver = __toESM(require("semver"));
|
1980
2011
|
|
1981
2012
|
// package.json
|
1982
|
-
var version = "1.6.
|
2013
|
+
var version = "1.6.2";
|
1983
2014
|
|
1984
2015
|
// src/common/task-cache.ts
|
1985
2016
|
var debug3 = (0, import_logger3.getDebug)("cache");
|
@@ -2274,22 +2305,28 @@ var PageAgent = class {
|
|
2274
2305
|
const allThoughts = executor.tasks.filter((task) => task.thought).map((task) => task.thought);
|
2275
2306
|
const allLocates = executor.tasks.filter((task) => task.locate).map((task) => task.locate);
|
2276
2307
|
const allPlans = executor.tasks.filter((task) => task.param?.plans).map((task) => task.param?.plans);
|
2277
|
-
const planningTasks = executor.tasks.filter(
|
2278
|
-
|
2308
|
+
const planningTasks = executor.tasks.filter(
|
2309
|
+
(task) => task.type === "Planning"
|
2310
|
+
);
|
2311
|
+
const insightTasks = executor.tasks.filter(
|
2312
|
+
(task) => task.type === "Insight"
|
2313
|
+
);
|
2279
2314
|
const actionTasks = executor.tasks.filter((task) => task.type === "Action");
|
2280
2315
|
const planning = planningTasks.length > 0 ? {
|
2281
2316
|
type: "Planning",
|
2282
|
-
description:
|
2317
|
+
description: "Planning for task execution",
|
2283
2318
|
steps: planningTasks.map((task) => task.thought || "Planning step")
|
2284
2319
|
} : void 0;
|
2285
2320
|
const insight = insightTasks.length > 0 ? {
|
2286
2321
|
type: "Insight",
|
2287
|
-
description:
|
2288
|
-
elements: insightTasks.map(
|
2322
|
+
description: "Insight for task execution",
|
2323
|
+
elements: insightTasks.map(
|
2324
|
+
(task) => task.thought || "Insight element"
|
2325
|
+
)
|
2289
2326
|
} : void 0;
|
2290
2327
|
const action = actionTasks.length > 0 ? {
|
2291
2328
|
type: "Action",
|
2292
|
-
description:
|
2329
|
+
description: "Action for task execution",
|
2293
2330
|
result: lastTask?.output
|
2294
2331
|
} : void 0;
|
2295
2332
|
const actionDetails = executor.tasks.map((task) => ({
|
@@ -2623,7 +2660,10 @@ ${memoryContext}` : void 0;
|
|
2623
2660
|
}
|
2624
2661
|
const memoryContext = this.getMemoryAsContext();
|
2625
2662
|
const assertionWithContext = currentUrl ? `For the page at URL "${currentUrl}", ${assertion}` : assertion;
|
2626
|
-
const { output, executor } = await this.taskExecutor.assert(
|
2663
|
+
const { output, executor } = await this.taskExecutor.assert(
|
2664
|
+
assertionWithContext,
|
2665
|
+
memoryContext
|
2666
|
+
);
|
2627
2667
|
const metadata = this.afterTaskRunning(executor, true);
|
2628
2668
|
if (output && opt?.keepRawResponse) {
|
2629
2669
|
return {
|
@@ -2662,7 +2702,10 @@ A complex CAPTCHA typically has one or more of these characteristics:
|
|
2662
2702
|
Return only "complex" or "simple" based on your analysis.
|
2663
2703
|
`;
|
2664
2704
|
const complexityMsgs = [
|
2665
|
-
{
|
2705
|
+
{
|
2706
|
+
role: "system",
|
2707
|
+
content: "You are an AI assistant that analyzes screenshots to determine CAPTCHA complexity."
|
2708
|
+
},
|
2666
2709
|
{
|
2667
2710
|
role: "user",
|
2668
2711
|
content: [
|
@@ -2686,7 +2729,12 @@ Return only "complex" or "simple" based on your analysis.
|
|
2686
2729
|
);
|
2687
2730
|
const responseText = typeof complexityResult.content === "string" ? complexityResult.content.toLowerCase() : JSON.stringify(complexityResult.content).toLowerCase();
|
2688
2731
|
shouldUseDeepThink = responseText.includes("complex");
|
2689
|
-
debug4(
|
2732
|
+
debug4(
|
2733
|
+
"CAPTCHA complexity analysis:",
|
2734
|
+
responseText,
|
2735
|
+
"Using deep think:",
|
2736
|
+
shouldUseDeepThink
|
2737
|
+
);
|
2690
2738
|
} catch (error) {
|
2691
2739
|
debug4("Failed to analyze CAPTCHA complexity:", error);
|
2692
2740
|
}
|
@@ -2703,7 +2751,9 @@ Return only "complex" or "simple" based on your analysis.
|
|
2703
2751
|
await this.aiTap(action.target, { deepThink: shouldUseDeepThink });
|
2704
2752
|
} else if (action.type === "input" && action.value) {
|
2705
2753
|
if (action.target) {
|
2706
|
-
await this.aiInput(action.value, action.target, {
|
2754
|
+
await this.aiInput(action.value, action.target, {
|
2755
|
+
deepThink: shouldUseDeepThink
|
2756
|
+
});
|
2707
2757
|
}
|
2708
2758
|
} else if (action.type === "verify" && action.target) {
|
2709
2759
|
await this.aiTap(action.target, { deepThink: shouldUseDeepThink });
|
@@ -2715,7 +2765,9 @@ Return only "complex" or "simple" based on your analysis.
|
|
2715
2765
|
if (action.coordinates) {
|
2716
2766
|
const x = action.coordinates[0];
|
2717
2767
|
const y = action.coordinates[1];
|
2718
|
-
await this.aiTap(`element at coordinates (${x}, ${y})`, {
|
2768
|
+
await this.aiTap(`element at coordinates (${x}, ${y})`, {
|
2769
|
+
deepThink: shouldUseDeepThink
|
2770
|
+
});
|
2719
2771
|
} else if (action.target) {
|
2720
2772
|
await this.aiTap(action.target, { deepThink: shouldUseDeepThink });
|
2721
2773
|
}
|
@@ -2867,25 +2919,27 @@ ${errors}`);
|
|
2867
2919
|
const executionDump = {
|
2868
2920
|
name: screenshotTitle,
|
2869
2921
|
description: content,
|
2870
|
-
tasks: [
|
2871
|
-
|
2872
|
-
|
2873
|
-
|
2874
|
-
|
2875
|
-
|
2876
|
-
|
2877
|
-
|
2878
|
-
|
2879
|
-
|
2880
|
-
|
2881
|
-
|
2882
|
-
|
2883
|
-
|
2884
|
-
|
2885
|
-
|
2886
|
-
|
2922
|
+
tasks: [
|
2923
|
+
{
|
2924
|
+
type: "Screenshot",
|
2925
|
+
subType: "log",
|
2926
|
+
status: "finished",
|
2927
|
+
executor: null,
|
2928
|
+
param: {
|
2929
|
+
title: screenshotTitle,
|
2930
|
+
content
|
2931
|
+
},
|
2932
|
+
output: {
|
2933
|
+
screenshot
|
2934
|
+
},
|
2935
|
+
thought: `Logged screenshot: ${screenshotTitle}`,
|
2936
|
+
timing: {
|
2937
|
+
start: Date.now(),
|
2938
|
+
end: Date.now(),
|
2939
|
+
cost: 0
|
2940
|
+
}
|
2887
2941
|
}
|
2888
|
-
|
2942
|
+
],
|
2889
2943
|
sdkVersion: "1.0.0",
|
2890
2944
|
logTime: Date.now(),
|
2891
2945
|
model_name: "screenshot"
|
@@ -2937,7 +2991,9 @@ ${errors}`);
|
|
2937
2991
|
totalTasks: stats.analytics.totalTasks,
|
2938
2992
|
memoryHits: stats.analytics.memoryHits,
|
2939
2993
|
memoryMisses: stats.analytics.memoryMisses,
|
2940
|
-
memoryEffectiveness: Math.round(
|
2994
|
+
memoryEffectiveness: Math.round(
|
2995
|
+
stats.analytics.memoryEffectiveness * 100
|
2996
|
+
),
|
2941
2997
|
averageMemorySize: Math.round(stats.analytics.averageMemorySize * 100) / 100
|
2942
2998
|
},
|
2943
2999
|
config: stats.config,
|
@@ -3001,7 +3057,9 @@ ${errors}`);
|
|
3001
3057
|
calculateSuccessRate(memory) {
|
3002
3058
|
if (memory.length === 0)
|
3003
3059
|
return 0;
|
3004
|
-
const successCount = memory.filter(
|
3060
|
+
const successCount = memory.filter(
|
3061
|
+
(item) => item.metadata?.success !== false
|
3062
|
+
).length;
|
3005
3063
|
return Math.round(successCount / memory.length * 100);
|
3006
3064
|
}
|
3007
3065
|
calculateAverageExecutionTime(memory) {
|
@@ -3138,13 +3196,13 @@ var StaticPage = class {
|
|
3138
3196
|
var import_node_crypto = require("crypto");
|
3139
3197
|
var import_node_fs3 = require("fs");
|
3140
3198
|
var import_node_path3 = require("path");
|
3199
|
+
var import_cors = __toESM(require("cors"));
|
3200
|
+
var import_dotenv = __toESM(require("dotenv"));
|
3201
|
+
var import_express = __toESM(require("express"));
|
3141
3202
|
var import_utils18 = require("misoai-core/utils");
|
3142
3203
|
var import_constants3 = require("misoai-shared/constants");
|
3143
3204
|
var import_env3 = require("misoai-shared/env");
|
3144
3205
|
var import_utils19 = require("misoai-shared/utils");
|
3145
|
-
var import_cors = __toESM(require("cors"));
|
3146
|
-
var import_dotenv = __toESM(require("dotenv"));
|
3147
|
-
var import_express = __toESM(require("express"));
|
3148
3206
|
var defaultPort = import_constants3.PLAYGROUND_SERVER_PORT;
|
3149
3207
|
var errorHandler = (err, req, res, next) => {
|
3150
3208
|
console.error(err);
|