snow-flow 3.0.9 → 3.0.13
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/claude-flow.bat +0 -0
- package/claude-flow.ps1 +0 -0
- package/dist/mcp/intelligent-reporting-mcp.d.ts +7 -0
- package/dist/mcp/intelligent-reporting-mcp.js +379 -0
- package/dist/mcp/servicenow-automation-mcp.js +0 -0
- package/dist/mcp/servicenow-deployment-mcp.js +0 -0
- package/dist/mcp/servicenow-integration-mcp.js +0 -0
- package/dist/mcp/servicenow-mcp-server.js +0 -0
- package/dist/mcp/servicenow-operations-mcp.js +0 -0
- package/dist/mcp/servicenow-platform-development-mcp.js +0 -0
- package/dist/mcp/servicenow-progressive-indexer.js +0 -0
- package/dist/mcp/servicenow-reporting-analytics-mcp.js +280 -29
- package/dist/mcp/servicenow-security-compliance-mcp.js +0 -0
- package/dist/mcp/servicenow-update-set-mcp.js +0 -0
- package/dist/mcp/start-all-mcp-servers.js +0 -0
- package/dist/mcp/start-servicenow-mcp.js +0 -0
- package/dist/services/widget-deployment-service.d.ts +2 -1
- package/dist/services/widget-deployment-service.js +17 -16
- package/dist/utils/anti-mock-data-validator.d.ts +66 -0
- package/dist/utils/anti-mock-data-validator.js +316 -0
- package/dist/utils/servicenow-eventual-consistency.d.ts +120 -0
- package/dist/utils/servicenow-eventual-consistency.js +220 -0
- package/memory/agents/README.md +1 -1
- package/memory/claude-flow-data.json +1 -1
- package/memory/sessions/README.md +1 -1
- package/package.json +4 -3
- package/.mcp.json +0 -22
- package/claude-flow.config.json +0 -20
- package/dist/agents/app-creator.agent.d.ts +0 -55
- package/dist/agents/app-creator.agent.js +0 -1292
- package/dist/agents/base/base-snow-agent.d.ts +0 -75
- package/dist/agents/base/base-snow-agent.js +0 -169
- package/dist/agents/base-snow-agent.d.ts +0 -63
- package/dist/agents/base-snow-agent.js +0 -296
- package/dist/agents/coordinator.d.ts +0 -200
- package/dist/agents/coordinator.js +0 -777
- package/dist/agents/flow-builder-agent.d.ts +0 -18
- package/dist/agents/flow-builder-agent.js +0 -197
- package/dist/agents/queen-403-handler.d.ts +0 -47
- package/dist/agents/queen-403-handler.js +0 -175
- package/dist/agents/queen-agent-example.d.ts +0 -23
- package/dist/agents/queen-agent-example.js +0 -240
- package/dist/agents/queen-agent.test.d.ts +0 -6
- package/dist/agents/script-generator.agent.d.ts +0 -32
- package/dist/agents/script-generator.agent.js +0 -772
- package/dist/agents/script-writer-agent.d.ts +0 -22
- package/dist/agents/script-writer-agent.js +0 -695
- package/dist/agents/security-agent.d.ts +0 -23
- package/dist/agents/security-agent.js +0 -619
- package/dist/agents/specialists/automation-specialist.agent.d.ts +0 -44
- package/dist/agents/specialists/automation-specialist.agent.js +0 -204
- package/dist/agents/specialists/data-specialist.agent.d.ts +0 -165
- package/dist/agents/specialists/data-specialist.agent.js +0 -484
- package/dist/agents/specialists/integration-specialist.agent.d.ts +0 -227
- package/dist/agents/specialists/integration-specialist.agent.js +0 -725
- package/dist/agents/specialists/reporting-specialist.agent.d.ts +0 -54
- package/dist/agents/specialists/reporting-specialist.agent.js +0 -193
- package/dist/agents/specialists/security-specialist.agent.d.ts +0 -85
- package/dist/agents/specialists/security-specialist.agent.js +0 -309
- package/dist/agents/teams/adaptive/adaptive-coordinator.agent.d.ts +0 -111
- package/dist/agents/teams/adaptive/adaptive-coordinator.agent.js +0 -383
- package/dist/agents/teams/base-team.d.ts +0 -72
- package/dist/agents/teams/base-team.js +0 -253
- package/dist/agents/teams/team-types.d.ts +0 -265
- package/dist/agents/teams/team-types.js +0 -3
- package/dist/agents/teams/widget/widget-architect.agent.d.ts +0 -61
- package/dist/agents/teams/widget/widget-architect.agent.js +0 -436
- package/dist/agents/teams/widget/widget-backend.agent.d.ts +0 -74
- package/dist/agents/teams/widget/widget-backend.agent.js +0 -1531
- package/dist/agents/teams/widget/widget-frontend.agent.d.ts +0 -67
- package/dist/agents/teams/widget/widget-frontend.agent.js +0 -1014
- package/dist/agents/teams/widget/widget-platform.agent.d.ts +0 -90
- package/dist/agents/teams/widget/widget-platform.agent.js +0 -1190
- package/dist/agents/teams/widget/widget-uiux.agent.d.ts +0 -107
- package/dist/agents/teams/widget/widget-uiux.agent.js +0 -1033
- package/dist/agents/test-agent.d.ts +0 -26
- package/dist/agents/test-agent.js +0 -734
- package/dist/agents/test-agents.d.ts +0 -7
- package/dist/agents/test-agents.js +0 -64
- package/dist/agents/ui-builder.agent.d.ts +0 -50
- package/dist/agents/ui-builder.agent.js +0 -1539
- package/dist/agents/widget-builder.agent.d.ts +0 -32
- package/dist/agents/widget-builder.agent.js +0 -439
- package/dist/agents/widget-creator-agent.d.ts +0 -18
- package/dist/agents/widget-creator-agent.js +0 -498
- package/dist/agents/workflow-designer.agent.d.ts +0 -31
- package/dist/agents/workflow-designer.agent.js +0 -583
- package/dist/api/error-handling.d.ts +0 -325
- package/dist/api/error-handling.js +0 -1488
- package/dist/api/flow-designer-api.d.ts +0 -167
- package/dist/api/flow-designer-api.js +0 -554
- package/dist/api/natural-language-mapper.d.ts +0 -124
- package/dist/api/natural-language-mapper.js +0 -501
- package/dist/api/performance-optimizer.d.ts +0 -240
- package/dist/api/performance-optimizer.js +0 -706
- package/dist/api/transaction-manager.d.ts +0 -189
- package/dist/api/transaction-manager.js +0 -576
- package/dist/assembly/team-assembler.d.ts +0 -140
- package/dist/assembly/team-assembler.js +0 -502
- package/dist/benchmark-performance.d.ts +0 -41
- package/dist/benchmark-performance.js +0 -230
- package/dist/cli/snow-flow-cli-integration.d.ts +0 -30
- package/dist/cli/snow-flow-cli-integration.js +0 -396
- package/dist/coordination/coordination-engine.d.ts +0 -41
- package/dist/coordination/coordination-engine.js +0 -324
- package/dist/coordination/coordination.test.d.ts +0 -6
- package/dist/coordination/example.d.ts +0 -31
- package/dist/coordination/example.js +0 -394
- package/dist/coordination/execution-patterns.d.ts +0 -43
- package/dist/coordination/execution-patterns.js +0 -507
- package/dist/coordination/factory.d.ts +0 -94
- package/dist/coordination/factory.js +0 -433
- package/dist/coordination/index.d.ts +0 -71
- package/dist/coordination/index.js +0 -135
- package/dist/coordination/progress-monitor.d.ts +0 -71
- package/dist/coordination/progress-monitor.js +0 -505
- package/dist/coordination/quality-gates.d.ts +0 -124
- package/dist/coordination/quality-gates.js +0 -577
- package/dist/coordination/shared-memory.d.ts +0 -39
- package/dist/coordination/shared-memory.js +0 -289
- package/dist/coordination/task-dependencies.d.ts +0 -50
- package/dist/coordination/task-dependencies.js +0 -407
- package/dist/coordination/team-coordinator.d.ts +0 -59
- package/dist/coordination/team-coordinator.js +0 -550
- package/dist/coordination/types.d.ts +0 -152
- package/dist/coordination/types.js +0 -3
- package/dist/mcp/mcp-wrapper.d.ts +0 -8
- package/dist/mcp/mcp-wrapper.js +0 -77
- package/dist/mcp/servicenow-flow-composer-enhanced.js +0 -396
- package/dist/mcp/servicenow-flow-composer-mcp.d.ts +0 -7
- package/dist/mcp/servicenow-flow-composer-mcp.js +0 -3103
- package/dist/mcp/servicenow-graph-memory-mcp.d.ts +0 -7
- package/dist/mcp/servicenow-intelligent-mcp.d.ts +0 -143
- package/dist/mcp/servicenow-intelligent-mcp.js +0 -4156
- package/dist/mcp/servicenow-xml-flow-mcp.d.ts +0 -53
- package/dist/mcp/servicenow-xml-flow-mcp.js +0 -1704
- package/dist/mcp/singleton-check.js +0 -31
- package/dist/mcp/test-simple-mcp.d.ts +0 -6
- package/dist/mcp/test-simple-mcp.js +0 -63
- package/dist/memory/hierarchical-memory-system.d.ts +0 -90
- package/dist/memory/hierarchical-memory-system.js +0 -400
- package/dist/memory/index.d.ts +0 -9
- package/dist/memory/index.js +0 -20
- package/dist/memory/mcp-integration-example.d.ts +0 -6
- package/dist/memory/mcp-integration-example.js +0 -281
- package/dist/memory/memory-client.d.ts +0 -199
- package/dist/memory/memory-client.js +0 -364
- package/dist/memory/memory-manager.d.ts +0 -29
- package/dist/memory/memory-manager.js +0 -280
- package/dist/memory/memory-operations.d.ts +0 -179
- package/dist/memory/memory-operations.js +0 -691
- package/dist/memory/memory-system.d.ts +0 -153
- package/dist/memory/memory-system.js +0 -651
- package/dist/memory/memory-test.d.ts +0 -6
- package/dist/memory/memory-test.js +0 -161
- package/dist/memory/snow-flow-memory-patterns.d.ts +0 -213
- package/dist/memory/snow-flow-memory-patterns.js +0 -200
- package/dist/memory/snow-memory.d.ts +0 -54
- package/dist/memory/snow-memory.js +0 -301
- package/dist/memory/swarm-memory.d.ts +0 -135
- package/dist/memory/swarm-memory.js +0 -378
- package/dist/optimization/flow-performance-optimizer.js +0 -723
- package/dist/orchestration/discovery/service-discovery.d.ts +0 -81
- package/dist/orchestration/discovery/service-discovery.js +0 -808
- package/dist/orchestration/distributed-orchestrator.d.ts +0 -131
- package/dist/orchestration/distributed-orchestrator.js +0 -712
- package/dist/orchestration/distribution/task-distribution-engine.d.ts +0 -53
- package/dist/orchestration/distribution/task-distribution-engine.js +0 -586
- package/dist/orchestration/flow-update-orchestrator.js +0 -648
- package/dist/orchestration/interfaces/distributed-orchestration.interface.d.ts +0 -606
- package/dist/orchestration/interfaces/distributed-orchestration.interface.js +0 -65
- package/dist/orchestration/protocols/mcpx-protocol.d.ts +0 -71
- package/dist/orchestration/protocols/mcpx-protocol.js +0 -668
- package/dist/orchestration/state/distributed-state-manager.d.ts +0 -89
- package/dist/orchestration/state/distributed-state-manager.js +0 -716
- package/dist/orchestrator/flow-composer.d.ts +0 -105
- package/dist/orchestrator/flow-composer.js +0 -404
- package/dist/orchestrator/flow-pattern-templates.d.ts +0 -260
- package/dist/orchestrator/flow-pattern-templates.js +0 -908
- package/dist/orchestrator/flow-subflow-decision-engine.d.ts +0 -202
- package/dist/orchestrator/flow-subflow-decision-engine.js +0 -769
- package/dist/orchestrator/flow-validation-engine.d.ts +0 -169
- package/dist/orchestrator/flow-validation-engine.js +0 -913
- package/dist/orchestrator/snow-orchestrator.d.ts +0 -49
- package/dist/orchestrator/snow-orchestrator.js +0 -235
- package/dist/orchestrator/subflow-creation-handler.d.ts +0 -230
- package/dist/orchestrator/subflow-creation-handler.js +0 -791
- package/dist/patterns/adaptive-patterns.d.ts +0 -140
- package/dist/patterns/adaptive-patterns.js +0 -549
- package/dist/queen/advanced-integration-test.d.ts +0 -48
- package/dist/queen/advanced-integration-test.js +0 -473
- package/dist/queen/integration-example.d.ts +0 -82
- package/dist/queen/integration-example.js +0 -219
- package/dist/queen/integration-test.d.ts +0 -72
- package/dist/queen/integration-test.js +0 -563
- package/dist/queen/mock-mcp-client.d.ts +0 -71
- package/dist/queen/mock-mcp-client.js +0 -317
- package/dist/queen/run-integration-tests.d.ts +0 -9
- package/dist/queen/run-integration-tests.js +0 -27
- package/dist/sparc/coordinators/adaptive-coordinator.d.ts +0 -54
- package/dist/sparc/coordinators/adaptive-coordinator.js +0 -367
- package/dist/sparc/coordinators/team-coordinator.d.ts +0 -66
- package/dist/sparc/coordinators/team-coordinator.js +0 -402
- package/dist/sparc/modes/team-modes.d.ts +0 -33
- package/dist/sparc/modes/team-modes.js +0 -399
- package/dist/sparc/teams/application-team.d.ts +0 -73
- package/dist/sparc/teams/application-team.js +0 -463
- package/dist/sparc/teams/flow-team.d.ts +0 -67
- package/dist/sparc/teams/flow-team.js +0 -373
- package/dist/sparc/teams/widget-team.d.ts +0 -61
- package/dist/sparc/teams/widget-team.js +0 -280
- package/dist/specialists/app-specialists.d.ts +0 -93
- package/dist/specialists/app-specialists.js +0 -1639
- package/dist/specialists/base-specialist.d.ts +0 -19
- package/dist/specialists/base-specialist.js +0 -54
- package/dist/specialists/flow-specialists.d.ts +0 -113
- package/dist/specialists/flow-specialists.js +0 -1787
- package/dist/specialists/individual-specialists.d.ts +0 -67
- package/dist/specialists/individual-specialists.js +0 -632
- package/dist/specialists/widget-specialists.d.ts +0 -70
- package/dist/specialists/widget-specialists.js +0 -1264
- package/dist/src/utils/agent-detector.js +0 -655
- package/dist/teams/adaptive-team.d.ts +0 -81
- package/dist/teams/adaptive-team.js +0 -1153
- package/dist/teams/application-team.d.ts +0 -30
- package/dist/teams/application-team.js +0 -547
- package/dist/teams/base-team.d.ts +0 -55
- package/dist/teams/base-team.js +0 -243
- package/dist/teams/flow-team.d.ts +0 -28
- package/dist/teams/flow-team.js +0 -525
- package/dist/teams/widget-team.d.ts +0 -26
- package/dist/teams/widget-team.js +0 -459
- package/dist/templates/flow-template-system.js +0 -625
- package/dist/test-fetch-incidents.d.ts +0 -2
- package/dist/test-fetch-incidents.js +0 -84
- package/dist/test-incident-access.d.ts +0 -2
- package/dist/test-incident-access.js +0 -72
- package/dist/test-iphone-flow.js +0 -189
- package/dist/test-limit-problem.d.ts +0 -2
- package/dist/test-limit-problem.js +0 -60
- package/dist/test-ml-batch-fix.d.ts +0 -2
- package/dist/test-ml-batch-fix.js +0 -104
- package/dist/test-ml-batch.d.ts +0 -2
- package/dist/test-ml-batch.js +0 -87
- package/dist/test-ml-query.d.ts +0 -2
- package/dist/test-ml-query.js +0 -100
- package/dist/test-ml-training-fix.d.ts +0 -12
- package/dist/test-ml-training-fix.js +0 -113
- package/dist/test-ml-training.d.ts +0 -2
- package/dist/test-ml-training.js +0 -32
- package/dist/test-operations-query.d.ts +0 -2
- package/dist/test-operations-query.js +0 -84
- package/dist/test-performance-query.d.ts +0 -2
- package/dist/test-performance-query.js +0 -52
- package/dist/test-singleton-protection.d.ts +0 -8
- package/dist/test-singleton-protection.js +0 -110
- package/dist/test-smart-limits.d.ts +0 -13
- package/dist/test-smart-limits.js +0 -100
- package/dist/test-snow-query-incidents.d.ts +0 -2
- package/dist/test-snow-query-incidents.js +0 -66
- package/dist/test-universal-query.d.ts +0 -2
- package/dist/test-universal-query.js +0 -106
- package/dist/testing/flow-testing-automation.js +0 -641
- package/dist/utils/complete-flow-xml-generator.js +0 -1285
- package/dist/utils/file-storage-fallback.d.ts +0 -62
- package/dist/utils/file-storage-fallback.js +0 -289
- package/dist/utils/flow-api-discovery.d.ts +0 -151
- package/dist/utils/flow-api-discovery.js +0 -439
- package/dist/utils/flow-examples.js +0 -720
- package/dist/utils/flow-structure-builder.js +0 -677
- package/dist/utils/flow-xml-generator.d.ts +0 -41
- package/dist/utils/flow-xml-generator.js +0 -258
- package/dist/utils/improved-flow-xml-generator.js +0 -820
- package/dist/utils/mcp-process-manager.backup.d.ts +0 -58
- package/dist/utils/mcp-process-manager.backup.js +0 -220
- package/dist/utils/mcp-singleton-enforcer.d.ts +0 -36
- package/dist/utils/mcp-singleton-enforcer.js +0 -201
- package/dist/utils/mcp-timeout-fix.d.ts +0 -53
- package/dist/utils/mcp-timeout-fix.js +0 -221
- package/dist/utils/migrate-claude-flow.d.ts +0 -22
- package/dist/utils/migrate-claude-flow.js +0 -120
- package/dist/utils/scope-utils.d.ts +0 -72
- package/dist/utils/scope-utils.js +0 -386
- package/dist/utils/snow-oauth-old.d.ts +0 -65
- package/dist/utils/snow-oauth-old.js +0 -345
- package/dist/utils/xml-first-flow-generator.js +0 -513
- package/memory/servicenow_artifacts/000d9224c895221055906c7518aa2d3d.json +0 -30
- package/memory/servicenow_artifacts/0196b66173303010e46b4a2214f6a7a2.json +0 -36
- package/memory/servicenow_artifacts/125e5d1d837e2a102a7ea130ceaad397.json +0 -30
- package/memory/servicenow_artifacts/7637c1f2b7112210a5e5911cde11a972.json +0 -30
- package/memory/servicenow_artifacts/default_documentation_tables_1754056582292.json +0 -55
- package/memory/servicenow_artifacts/default_documentation_tables_1754057477189.json +0 -55
- package/memory/update-set-sessions/01f82af583faea102a7ea130ceaad3d4.json +0 -9
- package/memory/update-set-sessions/27718fb983faea102a7ea130ceaad34b.json +0 -9
- package/memory/update-set-sessions/412e9bf6833e22502a7ea130ceaad30a.json +0 -8
- package/memory/update-set-sessions/66fc5a79837aea102a7ea130ceaad3ab.json +0 -9
- package/memory/update-set-sessions/71a30ff5837eea102a7ea130ceaad37f.json +0 -9
- package/memory/update-set-sessions/74fba27983faea102a7ea130ceaad3bd.json +0 -9
- package/memory/update-set-sessions/a0b147b5837eea102a7ea130ceaad344.json +0 -58
- package/memory/update-set-sessions/b13f5eb983baea102a7ea130ceaad33e.json +0 -9
- package/reports/swarm-auto-centralized-1752649029776.json +0 -13
- package/src/memory/README.md +0 -240
|
@@ -1,1531 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.WidgetBackendAgent = void 0;
|
|
4
|
-
/**
|
|
5
|
-
* Widget Backend Agent - Backend Development Specialist
|
|
6
|
-
* Handles server-side scripts, data processing, API integrations, and performance optimization
|
|
7
|
-
*/
|
|
8
|
-
const base_team_1 = require("../base-team");
|
|
9
|
-
class WidgetBackendAgent extends base_team_1.BaseSnowAgent {
|
|
10
|
-
constructor(config) {
|
|
11
|
-
const capabilities = [
|
|
12
|
-
{
|
|
13
|
-
name: 'server_script_development',
|
|
14
|
-
description: 'Create efficient server-side scripts for widgets',
|
|
15
|
-
proficiency: 0.95,
|
|
16
|
-
tools: ['javascript', 'servicenow_server_api', 'gliderecord']
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
name: 'data_processing',
|
|
20
|
-
description: 'Process and transform data for widget consumption',
|
|
21
|
-
proficiency: 0.9,
|
|
22
|
-
tools: ['data_transformation', 'aggregation', 'filtering']
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
name: 'api_integration',
|
|
26
|
-
description: 'Integrate with external APIs and ServiceNow APIs',
|
|
27
|
-
proficiency: 0.88,
|
|
28
|
-
tools: ['rest_api', 'soap_api', 'servicenow_api']
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
name: 'performance_optimization',
|
|
32
|
-
description: 'Optimize scripts for performance and scalability',
|
|
33
|
-
proficiency: 0.85,
|
|
34
|
-
tools: ['caching', 'query_optimization', 'lazy_loading']
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
name: 'security_implementation',
|
|
38
|
-
description: 'Implement security best practices and validation',
|
|
39
|
-
proficiency: 0.83,
|
|
40
|
-
tools: ['input_validation', 'access_control', 'sanitization']
|
|
41
|
-
}
|
|
42
|
-
];
|
|
43
|
-
const specialization = {
|
|
44
|
-
primary: ['server_scripting', 'data_processing', 'api_integration'],
|
|
45
|
-
secondary: ['performance_optimization', 'security', 'error_handling'],
|
|
46
|
-
tools: ['GlideRecord', 'GlideAjax', 'RESTMessage', 'ServiceNow APIs'],
|
|
47
|
-
experience: 0.88
|
|
48
|
-
};
|
|
49
|
-
super('widget-backend-001', 'Widget Backend Specialist', 'backend_developer', capabilities, specialization, config);
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Analyze backend requirements and prepare implementation plan
|
|
53
|
-
*/
|
|
54
|
-
async analyzeRequirements(requirements) {
|
|
55
|
-
try {
|
|
56
|
-
this.setStatus('busy');
|
|
57
|
-
console.log('Backend Agent: Analyzing backend requirements...');
|
|
58
|
-
const analysis = {
|
|
59
|
-
dataProcessingNeeds: this.analyzeDataProcessing(requirements),
|
|
60
|
-
apiIntegrationNeeds: this.analyzeApiIntegrations(requirements),
|
|
61
|
-
performanceStrategy: this.analyzePerformanceNeeds(requirements),
|
|
62
|
-
securityRequirements: this.analyzeSecurityNeeds(requirements),
|
|
63
|
-
errorHandlingStrategy: this.analyzeErrorHandling(requirements)
|
|
64
|
-
};
|
|
65
|
-
console.log('Backend Agent: Analysis complete');
|
|
66
|
-
return analysis;
|
|
67
|
-
}
|
|
68
|
-
catch (error) {
|
|
69
|
-
console.error('Backend Agent: Error analyzing requirements:', error);
|
|
70
|
-
throw error;
|
|
71
|
-
}
|
|
72
|
-
finally {
|
|
73
|
-
this.setStatus('available');
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Execute backend development tasks
|
|
78
|
-
*/
|
|
79
|
-
async execute(requirements) {
|
|
80
|
-
try {
|
|
81
|
-
this.setStatus('busy');
|
|
82
|
-
console.log('Backend Agent: Starting backend development...');
|
|
83
|
-
// Create server-side script
|
|
84
|
-
const serverScript = await this.createServerScript(requirements);
|
|
85
|
-
// Create data processing functions
|
|
86
|
-
const dataProcessors = await this.createDataProcessors(requirements);
|
|
87
|
-
// Create API integration handlers
|
|
88
|
-
const apiHandlers = await this.createApiHandlers(requirements);
|
|
89
|
-
// Create performance optimizations
|
|
90
|
-
const performanceOptimizations = await this.createPerformanceOptimizations(requirements);
|
|
91
|
-
// Create security validations
|
|
92
|
-
const securityValidations = await this.createSecurityValidations(requirements);
|
|
93
|
-
// Validate and test the implementation
|
|
94
|
-
const validation = await this.validateImplementation({
|
|
95
|
-
serverScript,
|
|
96
|
-
dataProcessors,
|
|
97
|
-
apiHandlers,
|
|
98
|
-
requirements
|
|
99
|
-
});
|
|
100
|
-
console.log('Backend Agent: Backend development completed');
|
|
101
|
-
return {
|
|
102
|
-
success: true,
|
|
103
|
-
artifact: {
|
|
104
|
-
serverScript,
|
|
105
|
-
dataProcessors,
|
|
106
|
-
apiHandlers,
|
|
107
|
-
performanceOptimizations,
|
|
108
|
-
securityValidations,
|
|
109
|
-
validation
|
|
110
|
-
},
|
|
111
|
-
metadata: {
|
|
112
|
-
duration: 0,
|
|
113
|
-
performance: {
|
|
114
|
-
script_efficiency: this.assessScriptEfficiency(serverScript),
|
|
115
|
-
query_optimization: this.assessQueryOptimization(serverScript),
|
|
116
|
-
api_performance: this.assessApiPerformance(apiHandlers)
|
|
117
|
-
},
|
|
118
|
-
quality: {
|
|
119
|
-
error_handling: validation.errorHandling,
|
|
120
|
-
security_score: validation.security,
|
|
121
|
-
maintainability: validation.maintainability
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
catch (error) {
|
|
127
|
-
console.error('Backend Agent: Error in backend development:', error);
|
|
128
|
-
return this.handleError(error);
|
|
129
|
-
}
|
|
130
|
-
finally {
|
|
131
|
-
this.setStatus('available');
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* Create comprehensive server-side script
|
|
136
|
-
*/
|
|
137
|
-
async createServerScript(requirements) {
|
|
138
|
-
console.log('Backend Agent: Creating server script...');
|
|
139
|
-
const { serverScript: scriptReq, performance, security } = requirements;
|
|
140
|
-
let script = `(function() {
|
|
141
|
-
'use strict';
|
|
142
|
-
|
|
143
|
-
// Widget data object
|
|
144
|
-
data.loading = true;
|
|
145
|
-
data.error = null;
|
|
146
|
-
data.items = [];
|
|
147
|
-
data.total = 0;
|
|
148
|
-
data.metadata = {};
|
|
149
|
-
|
|
150
|
-
try {
|
|
151
|
-
// Initialize widget
|
|
152
|
-
initializeWidget();
|
|
153
|
-
|
|
154
|
-
// Process main data request
|
|
155
|
-
processDataRequest();
|
|
156
|
-
|
|
157
|
-
} catch (error) {
|
|
158
|
-
handleError(error);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Initialize widget with options and security checks
|
|
163
|
-
*/
|
|
164
|
-
function initializeWidget() {
|
|
165
|
-
// Validate user permissions
|
|
166
|
-
if (!validateUserAccess()) {
|
|
167
|
-
throw new Error('Access denied: Insufficient permissions');
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// Initialize default options
|
|
171
|
-
options = options || {};
|
|
172
|
-
options.max_items = options.max_items || 10;
|
|
173
|
-
options.refresh_interval = options.refresh_interval || 30;
|
|
174
|
-
|
|
175
|
-
// Log widget initialization
|
|
176
|
-
gs.info('Widget initialized for user: ' + gs.getUserID());
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Main data processing function
|
|
181
|
-
*/
|
|
182
|
-
function processDataRequest() {
|
|
183
|
-
var action = input && input.action;
|
|
184
|
-
|
|
185
|
-
switch (action) {
|
|
186
|
-
case 'load_data':
|
|
187
|
-
loadMainData();
|
|
188
|
-
break;
|
|
189
|
-
case 'refresh_data':
|
|
190
|
-
refreshData();
|
|
191
|
-
break;
|
|
192
|
-
case 'save_item':
|
|
193
|
-
saveItemData(input.item);
|
|
194
|
-
break;
|
|
195
|
-
case 'delete_item':
|
|
196
|
-
deleteItemData(input.item_id);
|
|
197
|
-
break;
|
|
198
|
-
default:
|
|
199
|
-
loadMainData();
|
|
200
|
-
}
|
|
201
|
-
}`;
|
|
202
|
-
// Add data loading functions
|
|
203
|
-
script += this.createDataLoadingFunctions(scriptReq);
|
|
204
|
-
// Add API integration functions
|
|
205
|
-
script += this.createApiIntegrationFunctions(scriptReq);
|
|
206
|
-
// Add performance optimization functions
|
|
207
|
-
if (performance.caching) {
|
|
208
|
-
script += this.createCachingFunctions();
|
|
209
|
-
}
|
|
210
|
-
// Add security validation functions
|
|
211
|
-
script += this.createSecurityFunctions(security);
|
|
212
|
-
// Add error handling functions
|
|
213
|
-
script += this.createErrorHandlingFunctions();
|
|
214
|
-
// Close main function
|
|
215
|
-
script += `
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* Finalize data processing
|
|
219
|
-
*/
|
|
220
|
-
function finalizeData() {
|
|
221
|
-
data.loading = false;
|
|
222
|
-
data.lastUpdated = new GlideDateTime().getDisplayValue();
|
|
223
|
-
|
|
224
|
-
// Add metadata
|
|
225
|
-
data.metadata = {
|
|
226
|
-
total_records: data.total,
|
|
227
|
-
processing_time: getProcessingTime(),
|
|
228
|
-
cache_hit: data.cache_hit || false,
|
|
229
|
-
user_id: gs.getUserID()
|
|
230
|
-
};
|
|
231
|
-
|
|
232
|
-
gs.info('Widget data processing completed. Items: ' + data.items.length);
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
// Always finalize data
|
|
236
|
-
finalizeData();
|
|
237
|
-
|
|
238
|
-
})();`;
|
|
239
|
-
return script;
|
|
240
|
-
}
|
|
241
|
-
/**
|
|
242
|
-
* Create data processing functions
|
|
243
|
-
*/
|
|
244
|
-
async createDataProcessors(requirements) {
|
|
245
|
-
console.log('Backend Agent: Creating data processors...');
|
|
246
|
-
const processors = {
|
|
247
|
-
dataFiltering: this.createDataFilterProcessor(requirements),
|
|
248
|
-
dataAggregation: this.createDataAggregationProcessor(requirements),
|
|
249
|
-
dataTransformation: this.createDataTransformationProcessor(requirements),
|
|
250
|
-
dataValidation: this.createDataValidationProcessor(requirements)
|
|
251
|
-
};
|
|
252
|
-
return processors;
|
|
253
|
-
}
|
|
254
|
-
/**
|
|
255
|
-
* Create API integration handlers
|
|
256
|
-
*/
|
|
257
|
-
async createApiHandlers(requirements) {
|
|
258
|
-
console.log('Backend Agent: Creating API handlers...');
|
|
259
|
-
const handlers = {
|
|
260
|
-
restApiHandler: this.createRestApiHandler(requirements),
|
|
261
|
-
externalApiHandler: this.createExternalApiHandler(requirements),
|
|
262
|
-
serviceNowApiHandler: this.createServiceNowApiHandler(requirements)
|
|
263
|
-
};
|
|
264
|
-
return handlers;
|
|
265
|
-
}
|
|
266
|
-
/**
|
|
267
|
-
* Create performance optimizations
|
|
268
|
-
*/
|
|
269
|
-
async createPerformanceOptimizations(requirements) {
|
|
270
|
-
console.log('Backend Agent: Creating performance optimizations...');
|
|
271
|
-
const optimizations = {
|
|
272
|
-
queryOptimization: this.createQueryOptimizations(requirements),
|
|
273
|
-
cachingStrategy: this.createCachingStrategy(requirements),
|
|
274
|
-
lazyLoading: this.createLazyLoadingStrategy(requirements)
|
|
275
|
-
};
|
|
276
|
-
return optimizations;
|
|
277
|
-
}
|
|
278
|
-
/**
|
|
279
|
-
* Create security validations
|
|
280
|
-
*/
|
|
281
|
-
async createSecurityValidations(requirements) {
|
|
282
|
-
console.log('Backend Agent: Creating security validations...');
|
|
283
|
-
const validations = {
|
|
284
|
-
inputValidation: this.createInputValidation(requirements),
|
|
285
|
-
accessControl: this.createAccessControl(requirements),
|
|
286
|
-
dataSanitization: this.createDataSanitization(requirements)
|
|
287
|
-
};
|
|
288
|
-
return validations;
|
|
289
|
-
}
|
|
290
|
-
// Server script creation helpers
|
|
291
|
-
createDataLoadingFunctions(scriptReq) {
|
|
292
|
-
return `
|
|
293
|
-
|
|
294
|
-
/**
|
|
295
|
-
* Load main widget data
|
|
296
|
-
*/
|
|
297
|
-
function loadMainData() {
|
|
298
|
-
try {
|
|
299
|
-
var startTime = new GlideDateTime();
|
|
300
|
-
|
|
301
|
-
// Check cache first if enabled
|
|
302
|
-
var cachedData = getCachedData('main_data');
|
|
303
|
-
if (cachedData) {
|
|
304
|
-
data.items = cachedData.items;
|
|
305
|
-
data.total = cachedData.total;
|
|
306
|
-
data.cache_hit = true;
|
|
307
|
-
return;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
// Query main data
|
|
311
|
-
var gr = new GlideRecord('${scriptReq.dataProcessing.includes('incident') ? 'incident' : 'task'}');
|
|
312
|
-
|
|
313
|
-
// Apply filters
|
|
314
|
-
applyDataFilters(gr);
|
|
315
|
-
|
|
316
|
-
// Apply ordering
|
|
317
|
-
gr.orderByDesc('sys_updated_on');
|
|
318
|
-
|
|
319
|
-
// Apply limits
|
|
320
|
-
gr.setLimit(options.max_items || 10);
|
|
321
|
-
|
|
322
|
-
// Execute query
|
|
323
|
-
gr.query();
|
|
324
|
-
|
|
325
|
-
var items = [];
|
|
326
|
-
var count = 0;
|
|
327
|
-
|
|
328
|
-
while (gr.next() && count < (options.max_items || 10)) {
|
|
329
|
-
items.push(processRecord(gr));
|
|
330
|
-
count++;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
// Set data
|
|
334
|
-
data.items = items;
|
|
335
|
-
data.total = getTotal();
|
|
336
|
-
|
|
337
|
-
// Cache results if enabled
|
|
338
|
-
if (shouldCacheResults()) {
|
|
339
|
-
setCachedData('main_data', {
|
|
340
|
-
items: data.items,
|
|
341
|
-
total: data.total,
|
|
342
|
-
timestamp: new GlideDateTime().getNumericValue()
|
|
343
|
-
});
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
// Log performance
|
|
347
|
-
var endTime = new GlideDateTime();
|
|
348
|
-
var processingTime = endTime.getNumericValue() - startTime.getNumericValue();
|
|
349
|
-
gs.info('Data loading completed in ' + processingTime + 'ms');
|
|
350
|
-
|
|
351
|
-
} catch (error) {
|
|
352
|
-
gs.error('Error loading main data: ' + error.message);
|
|
353
|
-
handleError(error);
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
/**
|
|
358
|
-
* Refresh data (bypass cache)
|
|
359
|
-
*/
|
|
360
|
-
function refreshData() {
|
|
361
|
-
clearCache('main_data');
|
|
362
|
-
loadMainData();
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
/**
|
|
366
|
-
* Process individual record
|
|
367
|
-
*/
|
|
368
|
-
function processRecord(gr) {
|
|
369
|
-
var item = {
|
|
370
|
-
sys_id: gr.getUniqueValue(),
|
|
371
|
-
display_value: gr.getDisplayValue(),
|
|
372
|
-
table: gr.getTableName(),
|
|
373
|
-
updated_on: gr.getValue('sys_updated_on'),
|
|
374
|
-
created_on: gr.getValue('sys_created_on')
|
|
375
|
-
};
|
|
376
|
-
|
|
377
|
-
// Add specific fields based on table
|
|
378
|
-
if (gr.getTableName() === 'incident') {
|
|
379
|
-
item.number = gr.getValue('number');
|
|
380
|
-
item.priority = gr.getValue('priority');
|
|
381
|
-
item.state = gr.getValue('state');
|
|
382
|
-
item.short_description = gr.getValue('short_description');
|
|
383
|
-
item.assigned_to = gr.getDisplayValue('assigned_to');
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
// Transform data if needed
|
|
387
|
-
item = transformItemData(item);
|
|
388
|
-
|
|
389
|
-
return item;
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
/**
|
|
393
|
-
* Apply data filters based on options and user context
|
|
394
|
-
*/
|
|
395
|
-
function applyDataFilters(gr) {
|
|
396
|
-
// User-specific filters
|
|
397
|
-
if (options.assigned_to_me) {
|
|
398
|
-
gr.addQuery('assigned_to', gs.getUserID());
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
// Time-based filters
|
|
402
|
-
if (options.time_range) {
|
|
403
|
-
var timeFilter = getTimeFilter(options.time_range);
|
|
404
|
-
gr.addQuery('sys_created_on', '>=', timeFilter);
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
// Status filters
|
|
408
|
-
if (options.active_only) {
|
|
409
|
-
gr.addQuery('active', true);
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
// Custom filters from input
|
|
413
|
-
if (input && input.filters) {
|
|
414
|
-
applyCustomFilters(gr, input.filters);
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
/**
|
|
419
|
-
* Get total count for pagination
|
|
420
|
-
*/
|
|
421
|
-
function getTotal() {
|
|
422
|
-
var countGr = new GlideRecord('${scriptReq.dataProcessing.includes('incident') ? 'incident' : 'task'}');
|
|
423
|
-
applyDataFilters(countGr);
|
|
424
|
-
countGr.query();
|
|
425
|
-
return countGr.getRowCount();
|
|
426
|
-
}`;
|
|
427
|
-
}
|
|
428
|
-
createApiIntegrationFunctions(scriptReq) {
|
|
429
|
-
if (!scriptReq.apiIntegrations || scriptReq.apiIntegrations.length === 0) {
|
|
430
|
-
return '';
|
|
431
|
-
}
|
|
432
|
-
return `
|
|
433
|
-
|
|
434
|
-
/**
|
|
435
|
-
* Handle external API integrations
|
|
436
|
-
*/
|
|
437
|
-
function handleApiIntegrations() {
|
|
438
|
-
try {
|
|
439
|
-
var apiResults = {};
|
|
440
|
-
|
|
441
|
-
// Process each API integration
|
|
442
|
-
${scriptReq.apiIntegrations.map((api) => `
|
|
443
|
-
apiResults.${api} = call${this.capitalizeFirst(api)}Api();`).join('')}
|
|
444
|
-
|
|
445
|
-
// Merge API results with main data
|
|
446
|
-
mergeApiResults(apiResults);
|
|
447
|
-
|
|
448
|
-
} catch (error) {
|
|
449
|
-
gs.error('API integration error: ' + error.message);
|
|
450
|
-
// Continue without API data
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
/**
|
|
455
|
-
* Call external REST API
|
|
456
|
-
*/
|
|
457
|
-
function callExternalApi(endpoint, params) {
|
|
458
|
-
try {
|
|
459
|
-
var request = new sn_ws.RESTMessageV2();
|
|
460
|
-
request.setEndpoint(endpoint);
|
|
461
|
-
request.setHttpMethod('GET');
|
|
462
|
-
|
|
463
|
-
// Add parameters
|
|
464
|
-
if (params) {
|
|
465
|
-
for (var key in params) {
|
|
466
|
-
request.setQueryParameter(key, params[key]);
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
// Add authentication if configured
|
|
471
|
-
addApiAuthentication(request);
|
|
472
|
-
|
|
473
|
-
var response = request.execute();
|
|
474
|
-
var responseBody = response.getBody();
|
|
475
|
-
var httpStatus = response.getStatusCode();
|
|
476
|
-
|
|
477
|
-
if (httpStatus === 200) {
|
|
478
|
-
return JSON.parse(responseBody);
|
|
479
|
-
} else {
|
|
480
|
-
throw new Error('API call failed with status: ' + httpStatus);
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
} catch (error) {
|
|
484
|
-
gs.error('External API call failed: ' + error.message);
|
|
485
|
-
return null;
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
/**
|
|
490
|
-
* Add API authentication
|
|
491
|
-
*/
|
|
492
|
-
function addApiAuthentication(request) {
|
|
493
|
-
// Basic authentication example
|
|
494
|
-
if (options.api_username && options.api_password) {
|
|
495
|
-
request.setBasicAuth(options.api_username, options.api_password);
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
// Bearer token example
|
|
499
|
-
if (options.api_token) {
|
|
500
|
-
request.setRequestHeader('Authorization', 'Bearer ' + options.api_token);
|
|
501
|
-
}
|
|
502
|
-
}`;
|
|
503
|
-
}
|
|
504
|
-
createCachingFunctions() {
|
|
505
|
-
return `
|
|
506
|
-
|
|
507
|
-
/**
|
|
508
|
-
* Cache management functions
|
|
509
|
-
*/
|
|
510
|
-
function getCachedData(key) {
|
|
511
|
-
try {
|
|
512
|
-
var cacheKey = 'widget_cache_' + key + '_' + gs.getUserID();
|
|
513
|
-
var cache = gs.getProperty(cacheKey);
|
|
514
|
-
|
|
515
|
-
if (cache) {
|
|
516
|
-
var cacheData = JSON.parse(cache);
|
|
517
|
-
var now = new GlideDateTime().getNumericValue();
|
|
518
|
-
var cacheAge = now - cacheData.timestamp;
|
|
519
|
-
var maxAge = (options.cache_ttl || 300) * 1000; // Default 5 minutes
|
|
520
|
-
|
|
521
|
-
if (cacheAge < maxAge) {
|
|
522
|
-
gs.info('Cache hit for key: ' + key);
|
|
523
|
-
return cacheData;
|
|
524
|
-
} else {
|
|
525
|
-
clearCache(key);
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
} catch (error) {
|
|
529
|
-
gs.error('Cache retrieval error: ' + error.message);
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
return null;
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
function setCachedData(key, data) {
|
|
536
|
-
try {
|
|
537
|
-
var cacheKey = 'widget_cache_' + key + '_' + gs.getUserID();
|
|
538
|
-
var cacheData = {
|
|
539
|
-
data: data,
|
|
540
|
-
timestamp: new GlideDateTime().getNumericValue()
|
|
541
|
-
};
|
|
542
|
-
|
|
543
|
-
gs.setProperty(cacheKey, JSON.stringify(cacheData));
|
|
544
|
-
gs.info('Data cached for key: ' + key);
|
|
545
|
-
|
|
546
|
-
} catch (error) {
|
|
547
|
-
gs.error('Cache storage error: ' + error.message);
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
function clearCache(key) {
|
|
552
|
-
try {
|
|
553
|
-
var cacheKey = 'widget_cache_' + key + '_' + gs.getUserID();
|
|
554
|
-
gs.setProperty(cacheKey, '');
|
|
555
|
-
gs.info('Cache cleared for key: ' + key);
|
|
556
|
-
|
|
557
|
-
} catch (error) {
|
|
558
|
-
gs.error('Cache clearing error: ' + error.message);
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
function shouldCacheResults() {
|
|
563
|
-
return options.enable_cache !== false &&
|
|
564
|
-
data.items.length > 0 &&
|
|
565
|
-
!input.force_refresh;
|
|
566
|
-
}`;
|
|
567
|
-
}
|
|
568
|
-
createSecurityFunctions(security) {
|
|
569
|
-
return `
|
|
570
|
-
|
|
571
|
-
/**
|
|
572
|
-
* Security validation functions
|
|
573
|
-
*/
|
|
574
|
-
function validateUserAccess() {
|
|
575
|
-
try {
|
|
576
|
-
// Check if user is logged in
|
|
577
|
-
if (!gs.getUserID()) {
|
|
578
|
-
return false;
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
// Check required roles
|
|
582
|
-
var requiredRoles = options.required_roles || [];
|
|
583
|
-
if (requiredRoles.length > 0) {
|
|
584
|
-
var hasRole = false;
|
|
585
|
-
for (var i = 0; i < requiredRoles.length; i++) {
|
|
586
|
-
if (gs.hasRole(requiredRoles[i])) {
|
|
587
|
-
hasRole = true;
|
|
588
|
-
break;
|
|
589
|
-
}
|
|
590
|
-
}
|
|
591
|
-
if (!hasRole) {
|
|
592
|
-
return false;
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
// Check table access
|
|
597
|
-
if (options.table_name) {
|
|
598
|
-
var testGr = new GlideRecord(options.table_name);
|
|
599
|
-
if (!testGr.canRead()) {
|
|
600
|
-
return false;
|
|
601
|
-
}
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
return true;
|
|
605
|
-
|
|
606
|
-
} catch (error) {
|
|
607
|
-
gs.error('Access validation error: ' + error.message);
|
|
608
|
-
return false;
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
function validateInput(inputData) {
|
|
613
|
-
if (!inputData) {
|
|
614
|
-
return true;
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
// Sanitize string inputs
|
|
618
|
-
for (var key in inputData) {
|
|
619
|
-
if (typeof inputData[key] === 'string') {
|
|
620
|
-
inputData[key] = sanitizeString(inputData[key]);
|
|
621
|
-
}
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
// Validate specific fields
|
|
625
|
-
if (inputData.sys_id && !isValidSysId(inputData.sys_id)) {
|
|
626
|
-
throw new Error('Invalid sys_id format');
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
return true;
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
function sanitizeString(str) {
|
|
633
|
-
if (!str) return str;
|
|
634
|
-
|
|
635
|
-
// Remove potential script tags
|
|
636
|
-
str = str.replace(/<script[^>]*>.*?<\\/script>/gi, '');
|
|
637
|
-
|
|
638
|
-
// Remove potential SQL injection patterns
|
|
639
|
-
str = str.replace(/['";\\\\]/g, '');
|
|
640
|
-
|
|
641
|
-
// Limit length
|
|
642
|
-
if (str.length > 255) {
|
|
643
|
-
str = str.substring(0, 255);
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
return str;
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
function isValidSysId(sysId) {
|
|
650
|
-
return /^[a-f0-9]{32}$/.test(sysId);
|
|
651
|
-
}`;
|
|
652
|
-
}
|
|
653
|
-
createErrorHandlingFunctions() {
|
|
654
|
-
return `
|
|
655
|
-
|
|
656
|
-
/**
|
|
657
|
-
* Error handling functions
|
|
658
|
-
*/
|
|
659
|
-
function handleError(error) {
|
|
660
|
-
var errorMessage = error.message || 'Unknown error occurred';
|
|
661
|
-
var errorCode = error.code || 'GENERAL_ERROR';
|
|
662
|
-
|
|
663
|
-
// Log detailed error
|
|
664
|
-
gs.error('Widget error [' + errorCode + ']: ' + errorMessage);
|
|
665
|
-
gs.error('Stack trace: ' + error.stack);
|
|
666
|
-
|
|
667
|
-
// Set user-friendly error message
|
|
668
|
-
data.error = {
|
|
669
|
-
message: getUserFriendlyErrorMessage(errorCode),
|
|
670
|
-
code: errorCode,
|
|
671
|
-
timestamp: new GlideDateTime().getDisplayValue()
|
|
672
|
-
};
|
|
673
|
-
|
|
674
|
-
data.loading = false;
|
|
675
|
-
data.items = [];
|
|
676
|
-
}
|
|
677
|
-
|
|
678
|
-
function getUserFriendlyErrorMessage(errorCode) {
|
|
679
|
-
var messages = {
|
|
680
|
-
'ACCESS_DENIED': 'You do not have permission to view this data.',
|
|
681
|
-
'DATA_NOT_FOUND': 'No data found matching your criteria.',
|
|
682
|
-
'API_ERROR': 'Unable to retrieve external data at this time.',
|
|
683
|
-
'VALIDATION_ERROR': 'Invalid input provided.',
|
|
684
|
-
'GENERAL_ERROR': 'An unexpected error occurred. Please try again.'
|
|
685
|
-
};
|
|
686
|
-
|
|
687
|
-
return messages[errorCode] || messages['GENERAL_ERROR'];
|
|
688
|
-
}
|
|
689
|
-
|
|
690
|
-
function getProcessingTime() {
|
|
691
|
-
// This would be calculated from start time
|
|
692
|
-
return 0;
|
|
693
|
-
}
|
|
694
|
-
|
|
695
|
-
// Utility functions
|
|
696
|
-
function transformItemData(item) {
|
|
697
|
-
// Apply any data transformations
|
|
698
|
-
return item;
|
|
699
|
-
}
|
|
700
|
-
|
|
701
|
-
function applyCustomFilters(gr, filters) {
|
|
702
|
-
// Apply custom filters from input
|
|
703
|
-
for (var i = 0; i < filters.length; i++) {
|
|
704
|
-
var filter = filters[i];
|
|
705
|
-
gr.addQuery(filter.field, filter.operator, filter.value);
|
|
706
|
-
}
|
|
707
|
-
}
|
|
708
|
-
|
|
709
|
-
function getTimeFilter(range) {
|
|
710
|
-
var now = new GlideDateTime();
|
|
711
|
-
switch (range) {
|
|
712
|
-
case 'today':
|
|
713
|
-
var today = new GlideDate();
|
|
714
|
-
return today.getDisplayValue() + ' 00:00:00';
|
|
715
|
-
case 'week':
|
|
716
|
-
now.addWeeksLocalTime(-1);
|
|
717
|
-
return now.getDisplayValue();
|
|
718
|
-
case 'month':
|
|
719
|
-
now.addMonthsLocalTime(-1);
|
|
720
|
-
return now.getDisplayValue();
|
|
721
|
-
default:
|
|
722
|
-
return '';
|
|
723
|
-
}
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
function mergeApiResults(apiResults) {
|
|
727
|
-
// Merge API results with main data
|
|
728
|
-
for (var api in apiResults) {
|
|
729
|
-
if (apiResults[api] && apiResults[api].data) {
|
|
730
|
-
data[api + '_data'] = apiResults[api].data;
|
|
731
|
-
}
|
|
732
|
-
}
|
|
733
|
-
}`;
|
|
734
|
-
}
|
|
735
|
-
// Data processor creation methods
|
|
736
|
-
createDataFilterProcessor(requirements) {
|
|
737
|
-
return `
|
|
738
|
-
// Data filtering processor
|
|
739
|
-
function filterData(items, filters) {
|
|
740
|
-
if (!filters || filters.length === 0) {
|
|
741
|
-
return items;
|
|
742
|
-
}
|
|
743
|
-
|
|
744
|
-
return items.filter(function(item) {
|
|
745
|
-
return filters.every(function(filter) {
|
|
746
|
-
switch (filter.operator) {
|
|
747
|
-
case 'equals':
|
|
748
|
-
return item[filter.field] === filter.value;
|
|
749
|
-
case 'contains':
|
|
750
|
-
return item[filter.field] && item[filter.field].toString().toLowerCase().includes(filter.value.toLowerCase());
|
|
751
|
-
case 'greater_than':
|
|
752
|
-
return parseFloat(item[filter.field]) > parseFloat(filter.value);
|
|
753
|
-
case 'less_than':
|
|
754
|
-
return parseFloat(item[filter.field]) < parseFloat(filter.value);
|
|
755
|
-
default:
|
|
756
|
-
return true;
|
|
757
|
-
}
|
|
758
|
-
});
|
|
759
|
-
});
|
|
760
|
-
}`;
|
|
761
|
-
}
|
|
762
|
-
createDataAggregationProcessor(requirements) {
|
|
763
|
-
return `
|
|
764
|
-
// Data aggregation processor
|
|
765
|
-
function aggregateData(items, aggregations) {
|
|
766
|
-
var result = {};
|
|
767
|
-
|
|
768
|
-
aggregations.forEach(function(agg) {
|
|
769
|
-
switch (agg.type) {
|
|
770
|
-
case 'count':
|
|
771
|
-
result[agg.name] = items.length;
|
|
772
|
-
break;
|
|
773
|
-
case 'sum':
|
|
774
|
-
result[agg.name] = items.reduce(function(sum, item) {
|
|
775
|
-
return sum + (parseFloat(item[agg.field]) || 0);
|
|
776
|
-
}, 0);
|
|
777
|
-
break;
|
|
778
|
-
case 'average':
|
|
779
|
-
var sum = items.reduce(function(sum, item) {
|
|
780
|
-
return sum + (parseFloat(item[agg.field]) || 0);
|
|
781
|
-
}, 0);
|
|
782
|
-
result[agg.name] = items.length > 0 ? sum / items.length : 0;
|
|
783
|
-
break;
|
|
784
|
-
case 'group_by':
|
|
785
|
-
result[agg.name] = groupBy(items, agg.field);
|
|
786
|
-
break;
|
|
787
|
-
}
|
|
788
|
-
});
|
|
789
|
-
|
|
790
|
-
return result;
|
|
791
|
-
}
|
|
792
|
-
|
|
793
|
-
function groupBy(items, field) {
|
|
794
|
-
return items.reduce(function(groups, item) {
|
|
795
|
-
var key = item[field] || 'Unknown';
|
|
796
|
-
if (!groups[key]) {
|
|
797
|
-
groups[key] = [];
|
|
798
|
-
}
|
|
799
|
-
groups[key].push(item);
|
|
800
|
-
return groups;
|
|
801
|
-
}, {});
|
|
802
|
-
}`;
|
|
803
|
-
}
|
|
804
|
-
createDataTransformationProcessor(requirements) {
|
|
805
|
-
return `
|
|
806
|
-
// Data transformation processor
|
|
807
|
-
function transformData(items, transformations) {
|
|
808
|
-
return items.map(function(item) {
|
|
809
|
-
var transformed = Object.assign({}, item);
|
|
810
|
-
|
|
811
|
-
transformations.forEach(function(transform) {
|
|
812
|
-
switch (transform.type) {
|
|
813
|
-
case 'format_date':
|
|
814
|
-
if (transformed[transform.field]) {
|
|
815
|
-
transformed[transform.field] = formatDate(transformed[transform.field], transform.format);
|
|
816
|
-
}
|
|
817
|
-
break;
|
|
818
|
-
case 'format_currency':
|
|
819
|
-
if (transformed[transform.field]) {
|
|
820
|
-
transformed[transform.field] = formatCurrency(transformed[transform.field]);
|
|
821
|
-
}
|
|
822
|
-
break;
|
|
823
|
-
case 'concatenate':
|
|
824
|
-
transformed[transform.target] = transform.fields.map(function(field) {
|
|
825
|
-
return transformed[field] || '';
|
|
826
|
-
}).join(transform.separator || ' ');
|
|
827
|
-
break;
|
|
828
|
-
case 'calculate':
|
|
829
|
-
transformed[transform.target] = calculateValue(transformed, transform.formula);
|
|
830
|
-
break;
|
|
831
|
-
}
|
|
832
|
-
});
|
|
833
|
-
|
|
834
|
-
return transformed;
|
|
835
|
-
});
|
|
836
|
-
}
|
|
837
|
-
|
|
838
|
-
function formatDate(dateValue, format) {
|
|
839
|
-
var date = new GlideDateTime(dateValue);
|
|
840
|
-
return date.getDisplayValue();
|
|
841
|
-
}
|
|
842
|
-
|
|
843
|
-
function formatCurrency(value) {
|
|
844
|
-
return '$' + parseFloat(value).toFixed(2);
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
function calculateValue(item, formula) {
|
|
848
|
-
// Simple calculation engine
|
|
849
|
-
try {
|
|
850
|
-
return eval(formula.replace(/\{(\w+)\}/g, function(match, field) {
|
|
851
|
-
return parseFloat(item[field]) || 0;
|
|
852
|
-
}));
|
|
853
|
-
} catch (e) {
|
|
854
|
-
return 0;
|
|
855
|
-
}
|
|
856
|
-
}`;
|
|
857
|
-
}
|
|
858
|
-
createDataValidationProcessor(requirements) {
|
|
859
|
-
return `
|
|
860
|
-
// Data validation processor
|
|
861
|
-
function validateData(items, validationRules) {
|
|
862
|
-
return items.map(function(item) {
|
|
863
|
-
var validated = Object.assign({}, item);
|
|
864
|
-
validated._validationErrors = [];
|
|
865
|
-
|
|
866
|
-
validationRules.forEach(function(rule) {
|
|
867
|
-
var value = validated[rule.field];
|
|
868
|
-
var isValid = true;
|
|
869
|
-
|
|
870
|
-
switch (rule.type) {
|
|
871
|
-
case 'required':
|
|
872
|
-
isValid = value !== null && value !== undefined && value !== '';
|
|
873
|
-
break;
|
|
874
|
-
case 'email':
|
|
875
|
-
isValid = !value || /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(value);
|
|
876
|
-
break;
|
|
877
|
-
case 'phone':
|
|
878
|
-
isValid = !value || /^[\\d\\s\\-\\(\\)\\+]+$/.test(value);
|
|
879
|
-
break;
|
|
880
|
-
case 'range':
|
|
881
|
-
var numValue = parseFloat(value);
|
|
882
|
-
isValid = !isNaN(numValue) && numValue >= rule.min && numValue <= rule.max;
|
|
883
|
-
break;
|
|
884
|
-
}
|
|
885
|
-
|
|
886
|
-
if (!isValid) {
|
|
887
|
-
validated._validationErrors.push({
|
|
888
|
-
field: rule.field,
|
|
889
|
-
message: rule.message || 'Validation failed for ' + rule.field
|
|
890
|
-
});
|
|
891
|
-
}
|
|
892
|
-
});
|
|
893
|
-
|
|
894
|
-
validated._isValid = validated._validationErrors.length === 0;
|
|
895
|
-
return validated;
|
|
896
|
-
});
|
|
897
|
-
}`;
|
|
898
|
-
}
|
|
899
|
-
// API handler creation methods
|
|
900
|
-
createRestApiHandler(requirements) {
|
|
901
|
-
return `
|
|
902
|
-
// REST API handler
|
|
903
|
-
var RestApiHandler = {
|
|
904
|
-
call: function(endpoint, method, data) {
|
|
905
|
-
try {
|
|
906
|
-
var request = new sn_ws.RESTMessageV2();
|
|
907
|
-
request.setEndpoint(endpoint);
|
|
908
|
-
request.setHttpMethod(method || 'GET');
|
|
909
|
-
|
|
910
|
-
if (data && (method === 'POST' || method === 'PUT')) {
|
|
911
|
-
request.setRequestBody(JSON.stringify(data));
|
|
912
|
-
request.setRequestHeader('Content-Type', 'application/json');
|
|
913
|
-
}
|
|
914
|
-
|
|
915
|
-
var response = request.execute();
|
|
916
|
-
var responseBody = response.getBody();
|
|
917
|
-
var statusCode = response.getStatusCode();
|
|
918
|
-
|
|
919
|
-
return {
|
|
920
|
-
success: statusCode >= 200 && statusCode < 300,
|
|
921
|
-
data: statusCode < 400 ? JSON.parse(responseBody) : null,
|
|
922
|
-
error: statusCode >= 400 ? responseBody : null,
|
|
923
|
-
statusCode: statusCode
|
|
924
|
-
};
|
|
925
|
-
|
|
926
|
-
} catch (error) {
|
|
927
|
-
return {
|
|
928
|
-
success: false,
|
|
929
|
-
data: null,
|
|
930
|
-
error: error.message,
|
|
931
|
-
statusCode: 0
|
|
932
|
-
};
|
|
933
|
-
}
|
|
934
|
-
}
|
|
935
|
-
};`;
|
|
936
|
-
}
|
|
937
|
-
createExternalApiHandler(requirements) {
|
|
938
|
-
return `
|
|
939
|
-
// External API handler
|
|
940
|
-
var ExternalApiHandler = {
|
|
941
|
-
authenticate: function(config) {
|
|
942
|
-
// Handle different authentication methods
|
|
943
|
-
switch (config.auth_type) {
|
|
944
|
-
case 'bearer':
|
|
945
|
-
return 'Bearer ' + config.token;
|
|
946
|
-
case 'api_key':
|
|
947
|
-
return 'ApiKey ' + config.api_key;
|
|
948
|
-
case 'basic':
|
|
949
|
-
return 'Basic ' + GlideStringUtil.base64Encode(config.username + ':' + config.password);
|
|
950
|
-
default:
|
|
951
|
-
return null;
|
|
952
|
-
}
|
|
953
|
-
},
|
|
954
|
-
|
|
955
|
-
call: function(config, endpoint, params) {
|
|
956
|
-
try {
|
|
957
|
-
var request = new sn_ws.RESTMessageV2();
|
|
958
|
-
request.setEndpoint(config.base_url + endpoint);
|
|
959
|
-
request.setHttpMethod('GET');
|
|
960
|
-
|
|
961
|
-
// Add authentication
|
|
962
|
-
var authHeader = this.authenticate(config);
|
|
963
|
-
if (authHeader) {
|
|
964
|
-
request.setRequestHeader('Authorization', authHeader);
|
|
965
|
-
}
|
|
966
|
-
|
|
967
|
-
// Add parameters
|
|
968
|
-
if (params) {
|
|
969
|
-
for (var key in params) {
|
|
970
|
-
request.setQueryParameter(key, params[key]);
|
|
971
|
-
}
|
|
972
|
-
}
|
|
973
|
-
|
|
974
|
-
var response = request.execute();
|
|
975
|
-
return {
|
|
976
|
-
success: response.getStatusCode() === 200,
|
|
977
|
-
data: JSON.parse(response.getBody()),
|
|
978
|
-
statusCode: response.getStatusCode()
|
|
979
|
-
};
|
|
980
|
-
|
|
981
|
-
} catch (error) {
|
|
982
|
-
return {
|
|
983
|
-
success: false,
|
|
984
|
-
error: error.message
|
|
985
|
-
};
|
|
986
|
-
}
|
|
987
|
-
}
|
|
988
|
-
};`;
|
|
989
|
-
}
|
|
990
|
-
createServiceNowApiHandler(requirements) {
|
|
991
|
-
return `
|
|
992
|
-
// ServiceNow API handler
|
|
993
|
-
var ServiceNowApiHandler = {
|
|
994
|
-
getTableData: function(table, query, fields) {
|
|
995
|
-
try {
|
|
996
|
-
var gr = new GlideRecord(table);
|
|
997
|
-
|
|
998
|
-
if (query) {
|
|
999
|
-
gr.addEncodedQuery(query);
|
|
1000
|
-
}
|
|
1001
|
-
|
|
1002
|
-
gr.query();
|
|
1003
|
-
|
|
1004
|
-
var results = [];
|
|
1005
|
-
while (gr.next()) {
|
|
1006
|
-
var item = {};
|
|
1007
|
-
|
|
1008
|
-
if (fields && fields.length > 0) {
|
|
1009
|
-
fields.forEach(function(field) {
|
|
1010
|
-
item[field] = gr.getDisplayValue(field);
|
|
1011
|
-
});
|
|
1012
|
-
} else {
|
|
1013
|
-
// Get all fields
|
|
1014
|
-
var elements = gr.getElements();
|
|
1015
|
-
for (var i = 0; i < elements.size(); i++) {
|
|
1016
|
-
var element = elements.get(i);
|
|
1017
|
-
item[element.getName()] = gr.getDisplayValue(element.getName());
|
|
1018
|
-
}
|
|
1019
|
-
}
|
|
1020
|
-
|
|
1021
|
-
item.sys_id = gr.getUniqueValue();
|
|
1022
|
-
results.push(item);
|
|
1023
|
-
}
|
|
1024
|
-
|
|
1025
|
-
return {
|
|
1026
|
-
success: true,
|
|
1027
|
-
data: results,
|
|
1028
|
-
total: results.length
|
|
1029
|
-
};
|
|
1030
|
-
|
|
1031
|
-
} catch (error) {
|
|
1032
|
-
return {
|
|
1033
|
-
success: false,
|
|
1034
|
-
error: error.message
|
|
1035
|
-
};
|
|
1036
|
-
}
|
|
1037
|
-
},
|
|
1038
|
-
|
|
1039
|
-
updateRecord: function(table, sysId, data) {
|
|
1040
|
-
try {
|
|
1041
|
-
var gr = new GlideRecord(table);
|
|
1042
|
-
if (gr.get(sysId)) {
|
|
1043
|
-
for (var field in data) {
|
|
1044
|
-
gr.setValue(field, data[field]);
|
|
1045
|
-
}
|
|
1046
|
-
gr.update();
|
|
1047
|
-
|
|
1048
|
-
return {
|
|
1049
|
-
success: true,
|
|
1050
|
-
sys_id: sysId
|
|
1051
|
-
};
|
|
1052
|
-
} else {
|
|
1053
|
-
return {
|
|
1054
|
-
success: false,
|
|
1055
|
-
error: 'Record not found'
|
|
1056
|
-
};
|
|
1057
|
-
}
|
|
1058
|
-
|
|
1059
|
-
} catch (error) {
|
|
1060
|
-
return {
|
|
1061
|
-
success: false,
|
|
1062
|
-
error: error.message
|
|
1063
|
-
};
|
|
1064
|
-
}
|
|
1065
|
-
}
|
|
1066
|
-
};`;
|
|
1067
|
-
}
|
|
1068
|
-
// Optimization creation methods
|
|
1069
|
-
createQueryOptimizations(requirements) {
|
|
1070
|
-
return `
|
|
1071
|
-
// Query optimization strategies
|
|
1072
|
-
var QueryOptimizer = {
|
|
1073
|
-
optimizeQuery: function(gr, options) {
|
|
1074
|
-
// Use indexed fields for filtering when possible
|
|
1075
|
-
if (options.indexed_fields) {
|
|
1076
|
-
options.indexed_fields.forEach(function(field) {
|
|
1077
|
-
if (options.filters && options.filters[field]) {
|
|
1078
|
-
gr.addQuery(field, options.filters[field]);
|
|
1079
|
-
}
|
|
1080
|
-
});
|
|
1081
|
-
}
|
|
1082
|
-
|
|
1083
|
-
// Limit results
|
|
1084
|
-
if (options.limit) {
|
|
1085
|
-
gr.setLimit(options.limit);
|
|
1086
|
-
}
|
|
1087
|
-
|
|
1088
|
-
// Only select needed fields
|
|
1089
|
-
if (options.fields) {
|
|
1090
|
-
gr.setDisplayValue(true);
|
|
1091
|
-
// Note: GlideRecord doesn't have field selection, but we can optimize by only accessing needed fields
|
|
1092
|
-
}
|
|
1093
|
-
|
|
1094
|
-
return gr;
|
|
1095
|
-
},
|
|
1096
|
-
|
|
1097
|
-
batchProcess: function(table, query, batchSize, processor) {
|
|
1098
|
-
var offset = 0;
|
|
1099
|
-
var totalProcessed = 0;
|
|
1100
|
-
|
|
1101
|
-
do {
|
|
1102
|
-
var gr = new GlideRecord(table);
|
|
1103
|
-
gr.addEncodedQuery(query);
|
|
1104
|
-
gr.setLimit(batchSize);
|
|
1105
|
-
gr.query();
|
|
1106
|
-
|
|
1107
|
-
var batchCount = 0;
|
|
1108
|
-
while (gr.next()) {
|
|
1109
|
-
processor(gr);
|
|
1110
|
-
batchCount++;
|
|
1111
|
-
totalProcessed++;
|
|
1112
|
-
}
|
|
1113
|
-
|
|
1114
|
-
offset += batchSize;
|
|
1115
|
-
} while (batchCount === batchSize);
|
|
1116
|
-
|
|
1117
|
-
return totalProcessed;
|
|
1118
|
-
}
|
|
1119
|
-
};`;
|
|
1120
|
-
}
|
|
1121
|
-
createCachingStrategy(requirements) {
|
|
1122
|
-
return `
|
|
1123
|
-
// Caching strategy
|
|
1124
|
-
var CacheManager = {
|
|
1125
|
-
generateKey: function(prefix, params) {
|
|
1126
|
-
var key = prefix + '_' + gs.getUserID();
|
|
1127
|
-
if (params) {
|
|
1128
|
-
key += '_' + JSON.stringify(params).replace(/[^a-zA-Z0-9]/g, '');
|
|
1129
|
-
}
|
|
1130
|
-
return key;
|
|
1131
|
-
},
|
|
1132
|
-
|
|
1133
|
-
get: function(key, maxAge) {
|
|
1134
|
-
try {
|
|
1135
|
-
var cached = gs.getProperty('cache_' + key);
|
|
1136
|
-
if (cached) {
|
|
1137
|
-
var data = JSON.parse(cached);
|
|
1138
|
-
var age = new GlideDateTime().getNumericValue() - data.timestamp;
|
|
1139
|
-
|
|
1140
|
-
if (age < (maxAge || 300000)) { // Default 5 minutes
|
|
1141
|
-
return data.value;
|
|
1142
|
-
} else {
|
|
1143
|
-
this.clear(key);
|
|
1144
|
-
}
|
|
1145
|
-
}
|
|
1146
|
-
} catch (error) {
|
|
1147
|
-
gs.error('Cache get error: ' + error.message);
|
|
1148
|
-
}
|
|
1149
|
-
return null;
|
|
1150
|
-
},
|
|
1151
|
-
|
|
1152
|
-
set: function(key, value, ttl) {
|
|
1153
|
-
try {
|
|
1154
|
-
var data = {
|
|
1155
|
-
value: value,
|
|
1156
|
-
timestamp: new GlideDateTime().getNumericValue(),
|
|
1157
|
-
ttl: ttl || 300000
|
|
1158
|
-
};
|
|
1159
|
-
|
|
1160
|
-
gs.setProperty('cache_' + key, JSON.stringify(data));
|
|
1161
|
-
} catch (error) {
|
|
1162
|
-
gs.error('Cache set error: ' + error.message);
|
|
1163
|
-
}
|
|
1164
|
-
},
|
|
1165
|
-
|
|
1166
|
-
clear: function(key) {
|
|
1167
|
-
gs.setProperty('cache_' + key, '');
|
|
1168
|
-
}
|
|
1169
|
-
};`;
|
|
1170
|
-
}
|
|
1171
|
-
createLazyLoadingStrategy(requirements) {
|
|
1172
|
-
return `
|
|
1173
|
-
// Lazy loading strategy
|
|
1174
|
-
var LazyLoader = {
|
|
1175
|
-
loadInChunks: function(table, query, chunkSize, callback) {
|
|
1176
|
-
var offset = 0;
|
|
1177
|
-
var hasMore = true;
|
|
1178
|
-
|
|
1179
|
-
return {
|
|
1180
|
-
next: function() {
|
|
1181
|
-
if (!hasMore) return null;
|
|
1182
|
-
|
|
1183
|
-
var gr = new GlideRecord(table);
|
|
1184
|
-
gr.addEncodedQuery(query);
|
|
1185
|
-
gr.setLimit(chunkSize);
|
|
1186
|
-
// Note: ServiceNow doesn't have OFFSET, so we use different approach
|
|
1187
|
-
gr.query();
|
|
1188
|
-
|
|
1189
|
-
var items = [];
|
|
1190
|
-
var count = 0;
|
|
1191
|
-
|
|
1192
|
-
while (gr.next() && count < chunkSize) {
|
|
1193
|
-
items.push(callback ? callback(gr) : gr);
|
|
1194
|
-
count++;
|
|
1195
|
-
}
|
|
1196
|
-
|
|
1197
|
-
hasMore = items.length === chunkSize;
|
|
1198
|
-
offset += chunkSize;
|
|
1199
|
-
|
|
1200
|
-
return {
|
|
1201
|
-
items: items,
|
|
1202
|
-
hasMore: hasMore,
|
|
1203
|
-
offset: offset
|
|
1204
|
-
};
|
|
1205
|
-
}
|
|
1206
|
-
};
|
|
1207
|
-
}
|
|
1208
|
-
};`;
|
|
1209
|
-
}
|
|
1210
|
-
// Security validation creation methods
|
|
1211
|
-
createInputValidation(requirements) {
|
|
1212
|
-
return `
|
|
1213
|
-
// Input validation
|
|
1214
|
-
var InputValidator = {
|
|
1215
|
-
validate: function(input, rules) {
|
|
1216
|
-
var errors = [];
|
|
1217
|
-
|
|
1218
|
-
for (var field in rules) {
|
|
1219
|
-
var rule = rules[field];
|
|
1220
|
-
var value = input[field];
|
|
1221
|
-
|
|
1222
|
-
if (rule.required && (!value || value === '')) {
|
|
1223
|
-
errors.push(field + ' is required');
|
|
1224
|
-
continue;
|
|
1225
|
-
}
|
|
1226
|
-
|
|
1227
|
-
if (value && rule.type) {
|
|
1228
|
-
switch (rule.type) {
|
|
1229
|
-
case 'email':
|
|
1230
|
-
if (!/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(value)) {
|
|
1231
|
-
errors.push(field + ' must be a valid email');
|
|
1232
|
-
}
|
|
1233
|
-
break;
|
|
1234
|
-
case 'sys_id':
|
|
1235
|
-
if (!/^[a-f0-9]{32}$/.test(value)) {
|
|
1236
|
-
errors.push(field + ' must be a valid sys_id');
|
|
1237
|
-
}
|
|
1238
|
-
break;
|
|
1239
|
-
case 'number':
|
|
1240
|
-
if (isNaN(parseFloat(value))) {
|
|
1241
|
-
errors.push(field + ' must be a number');
|
|
1242
|
-
}
|
|
1243
|
-
break;
|
|
1244
|
-
}
|
|
1245
|
-
}
|
|
1246
|
-
|
|
1247
|
-
if (value && rule.maxLength && value.length > rule.maxLength) {
|
|
1248
|
-
errors.push(field + ' must not exceed ' + rule.maxLength + ' characters');
|
|
1249
|
-
}
|
|
1250
|
-
}
|
|
1251
|
-
|
|
1252
|
-
return {
|
|
1253
|
-
isValid: errors.length === 0,
|
|
1254
|
-
errors: errors
|
|
1255
|
-
};
|
|
1256
|
-
},
|
|
1257
|
-
|
|
1258
|
-
sanitize: function(input) {
|
|
1259
|
-
var sanitized = {};
|
|
1260
|
-
|
|
1261
|
-
for (var key in input) {
|
|
1262
|
-
var value = input[key];
|
|
1263
|
-
|
|
1264
|
-
if (typeof value === 'string') {
|
|
1265
|
-
// Remove potential XSS
|
|
1266
|
-
value = value.replace(/<script[^>]*>.*?<\\/script>/gi, '');
|
|
1267
|
-
value = value.replace(/javascript:/gi, '');
|
|
1268
|
-
|
|
1269
|
-
// Remove potential SQL injection
|
|
1270
|
-
value = value.replace(/['";\\\\]/g, '');
|
|
1271
|
-
|
|
1272
|
-
// Trim whitespace
|
|
1273
|
-
value = value.trim();
|
|
1274
|
-
}
|
|
1275
|
-
|
|
1276
|
-
sanitized[key] = value;
|
|
1277
|
-
}
|
|
1278
|
-
|
|
1279
|
-
return sanitized;
|
|
1280
|
-
}
|
|
1281
|
-
};`;
|
|
1282
|
-
}
|
|
1283
|
-
createAccessControl(requirements) {
|
|
1284
|
-
return `
|
|
1285
|
-
// Access control
|
|
1286
|
-
var AccessController = {
|
|
1287
|
-
checkTableAccess: function(table, operation) {
|
|
1288
|
-
try {
|
|
1289
|
-
var gr = new GlideRecord(table);
|
|
1290
|
-
|
|
1291
|
-
switch (operation) {
|
|
1292
|
-
case 'read':
|
|
1293
|
-
return gr.canRead();
|
|
1294
|
-
case 'write':
|
|
1295
|
-
return gr.canWrite();
|
|
1296
|
-
case 'create':
|
|
1297
|
-
return gr.canCreate();
|
|
1298
|
-
case 'delete':
|
|
1299
|
-
return gr.canDelete();
|
|
1300
|
-
default:
|
|
1301
|
-
return false;
|
|
1302
|
-
}
|
|
1303
|
-
} catch (error) {
|
|
1304
|
-
return false;
|
|
1305
|
-
}
|
|
1306
|
-
},
|
|
1307
|
-
|
|
1308
|
-
checkRecordAccess: function(table, sysId, operation) {
|
|
1309
|
-
try {
|
|
1310
|
-
var gr = new GlideRecord(table);
|
|
1311
|
-
if (gr.get(sysId)) {
|
|
1312
|
-
switch (operation) {
|
|
1313
|
-
case 'read':
|
|
1314
|
-
return gr.canRead();
|
|
1315
|
-
case 'write':
|
|
1316
|
-
return gr.canWrite();
|
|
1317
|
-
case 'delete':
|
|
1318
|
-
return gr.canDelete();
|
|
1319
|
-
default:
|
|
1320
|
-
return false;
|
|
1321
|
-
}
|
|
1322
|
-
}
|
|
1323
|
-
return false;
|
|
1324
|
-
} catch (error) {
|
|
1325
|
-
return false;
|
|
1326
|
-
}
|
|
1327
|
-
},
|
|
1328
|
-
|
|
1329
|
-
checkRole: function(role) {
|
|
1330
|
-
return gs.hasRole(role);
|
|
1331
|
-
},
|
|
1332
|
-
|
|
1333
|
-
checkRoleOr: function(roles) {
|
|
1334
|
-
return roles.some(function(role) {
|
|
1335
|
-
return gs.hasRole(role);
|
|
1336
|
-
});
|
|
1337
|
-
}
|
|
1338
|
-
};`;
|
|
1339
|
-
}
|
|
1340
|
-
createDataSanitization(requirements) {
|
|
1341
|
-
return `
|
|
1342
|
-
// Data sanitization
|
|
1343
|
-
var DataSanitizer = {
|
|
1344
|
-
sanitizeHtml: function(html) {
|
|
1345
|
-
if (!html) return html;
|
|
1346
|
-
|
|
1347
|
-
// Remove script tags
|
|
1348
|
-
html = html.replace(/<script[^>]*>.*?<\\/script>/gi, '');
|
|
1349
|
-
|
|
1350
|
-
// Remove event handlers
|
|
1351
|
-
html = html.replace(/on\\w+\\s*=\\s*"[^"]*"/gi, '');
|
|
1352
|
-
html = html.replace(/on\\w+\\s*=\\s*'[^']*'/gi, '');
|
|
1353
|
-
|
|
1354
|
-
// Remove javascript: URLs
|
|
1355
|
-
html = html.replace(/href\\s*=\\s*["']javascript:[^"']*["']/gi, '');
|
|
1356
|
-
|
|
1357
|
-
return html;
|
|
1358
|
-
},
|
|
1359
|
-
|
|
1360
|
-
sanitizeJson: function(json) {
|
|
1361
|
-
try {
|
|
1362
|
-
var obj = typeof json === 'string' ? JSON.parse(json) : json;
|
|
1363
|
-
return this.sanitizeObject(obj);
|
|
1364
|
-
} catch (error) {
|
|
1365
|
-
return {};
|
|
1366
|
-
}
|
|
1367
|
-
},
|
|
1368
|
-
|
|
1369
|
-
sanitizeObject: function(obj) {
|
|
1370
|
-
if (typeof obj !== 'object' || obj === null) {
|
|
1371
|
-
return obj;
|
|
1372
|
-
}
|
|
1373
|
-
|
|
1374
|
-
var sanitized = {};
|
|
1375
|
-
for (var key in obj) {
|
|
1376
|
-
if (obj.hasOwnProperty(key)) {
|
|
1377
|
-
var value = obj[key];
|
|
1378
|
-
|
|
1379
|
-
if (typeof value === 'string') {
|
|
1380
|
-
sanitized[key] = this.sanitizeString(value);
|
|
1381
|
-
} else if (typeof value === 'object') {
|
|
1382
|
-
sanitized[key] = this.sanitizeObject(value);
|
|
1383
|
-
} else {
|
|
1384
|
-
sanitized[key] = value;
|
|
1385
|
-
}
|
|
1386
|
-
}
|
|
1387
|
-
}
|
|
1388
|
-
|
|
1389
|
-
return sanitized;
|
|
1390
|
-
},
|
|
1391
|
-
|
|
1392
|
-
sanitizeString: function(str) {
|
|
1393
|
-
if (!str) return str;
|
|
1394
|
-
|
|
1395
|
-
// Remove control characters
|
|
1396
|
-
str = str.replace(/[\\x00-\\x1F\\x7F]/g, '');
|
|
1397
|
-
|
|
1398
|
-
// Limit length
|
|
1399
|
-
if (str.length > 1000) {
|
|
1400
|
-
str = str.substring(0, 1000);
|
|
1401
|
-
}
|
|
1402
|
-
|
|
1403
|
-
return str;
|
|
1404
|
-
}
|
|
1405
|
-
};`;
|
|
1406
|
-
}
|
|
1407
|
-
// Analysis methods
|
|
1408
|
-
analyzeDataProcessing(requirements) {
|
|
1409
|
-
return {
|
|
1410
|
-
complexity: requirements.serverScript.dataProcessing.length > 3 ? 'high' : 'medium',
|
|
1411
|
-
operations: requirements.serverScript.dataProcessing,
|
|
1412
|
-
optimizationNeeded: requirements.serverScript.dataProcessing.includes('aggregation')
|
|
1413
|
-
};
|
|
1414
|
-
}
|
|
1415
|
-
analyzeApiIntegrations(requirements) {
|
|
1416
|
-
return {
|
|
1417
|
-
count: requirements.serverScript.apiIntegrations.length,
|
|
1418
|
-
complexity: requirements.serverScript.apiIntegrations.length > 2 ? 'high' : 'low',
|
|
1419
|
-
types: requirements.serverScript.apiIntegrations
|
|
1420
|
-
};
|
|
1421
|
-
}
|
|
1422
|
-
analyzePerformanceNeeds(requirements) {
|
|
1423
|
-
return {
|
|
1424
|
-
caching: requirements.performance.caching,
|
|
1425
|
-
optimization: requirements.performance.optimization,
|
|
1426
|
-
priority: requirements.performance.caching ? 'high' : 'medium'
|
|
1427
|
-
};
|
|
1428
|
-
}
|
|
1429
|
-
analyzeSecurityNeeds(requirements) {
|
|
1430
|
-
return {
|
|
1431
|
-
validation: requirements.security.validation,
|
|
1432
|
-
authorization: requirements.security.authorization,
|
|
1433
|
-
priority: 'high'
|
|
1434
|
-
};
|
|
1435
|
-
}
|
|
1436
|
-
analyzeErrorHandling(requirements) {
|
|
1437
|
-
return {
|
|
1438
|
-
strategy: 'comprehensive',
|
|
1439
|
-
logging: true,
|
|
1440
|
-
userFriendly: true
|
|
1441
|
-
};
|
|
1442
|
-
}
|
|
1443
|
-
// Validation methods
|
|
1444
|
-
async validateImplementation(implementation) {
|
|
1445
|
-
return {
|
|
1446
|
-
errorHandling: this.validateErrorHandling(implementation),
|
|
1447
|
-
security: this.validateSecurity(implementation),
|
|
1448
|
-
maintainability: this.validateMaintainability(implementation)
|
|
1449
|
-
};
|
|
1450
|
-
}
|
|
1451
|
-
validateErrorHandling(implementation) {
|
|
1452
|
-
const hasTryCatch = implementation.serverScript.includes('try') && implementation.serverScript.includes('catch');
|
|
1453
|
-
const hasErrorLogging = implementation.serverScript.includes('gs.error');
|
|
1454
|
-
const hasUserFriendlyErrors = implementation.serverScript.includes('getUserFriendlyErrorMessage');
|
|
1455
|
-
let score = 0.3;
|
|
1456
|
-
if (hasTryCatch)
|
|
1457
|
-
score += 0.3;
|
|
1458
|
-
if (hasErrorLogging)
|
|
1459
|
-
score += 0.2;
|
|
1460
|
-
if (hasUserFriendlyErrors)
|
|
1461
|
-
score += 0.2;
|
|
1462
|
-
return Math.min(score, 1.0);
|
|
1463
|
-
}
|
|
1464
|
-
validateSecurity(implementation) {
|
|
1465
|
-
const hasInputValidation = implementation.serverScript.includes('validateInput');
|
|
1466
|
-
const hasAccessControl = implementation.serverScript.includes('validateUserAccess');
|
|
1467
|
-
const hasSanitization = implementation.serverScript.includes('sanitize');
|
|
1468
|
-
let score = 0.2;
|
|
1469
|
-
if (hasInputValidation)
|
|
1470
|
-
score += 0.3;
|
|
1471
|
-
if (hasAccessControl)
|
|
1472
|
-
score += 0.3;
|
|
1473
|
-
if (hasSanitization)
|
|
1474
|
-
score += 0.2;
|
|
1475
|
-
return Math.min(score, 1.0);
|
|
1476
|
-
}
|
|
1477
|
-
validateMaintainability(implementation) {
|
|
1478
|
-
const hasComments = implementation.serverScript.includes('/**');
|
|
1479
|
-
const hasFunctions = (implementation.serverScript.match(/function /g) || []).length > 5;
|
|
1480
|
-
const hasErrorHandling = implementation.serverScript.includes('handleError');
|
|
1481
|
-
let score = 0.4;
|
|
1482
|
-
if (hasComments)
|
|
1483
|
-
score += 0.2;
|
|
1484
|
-
if (hasFunctions)
|
|
1485
|
-
score += 0.2;
|
|
1486
|
-
if (hasErrorHandling)
|
|
1487
|
-
score += 0.2;
|
|
1488
|
-
return Math.min(score, 1.0);
|
|
1489
|
-
}
|
|
1490
|
-
// Assessment methods
|
|
1491
|
-
assessScriptEfficiency(script) {
|
|
1492
|
-
const queries = (script.match(/new GlideRecord/g) || []).length;
|
|
1493
|
-
const loops = (script.match(/while|for/g) || []).length;
|
|
1494
|
-
// Lower is better for efficiency
|
|
1495
|
-
return Math.max(0.3, 1.0 - (queries * 0.1) - (loops * 0.05));
|
|
1496
|
-
}
|
|
1497
|
-
assessQueryOptimization(script) {
|
|
1498
|
-
const hasLimits = script.includes('setLimit');
|
|
1499
|
-
const hasIndexedQueries = script.includes('addQuery');
|
|
1500
|
-
const hasCaching = script.includes('cache');
|
|
1501
|
-
let score = 0.3;
|
|
1502
|
-
if (hasLimits)
|
|
1503
|
-
score += 0.25;
|
|
1504
|
-
if (hasIndexedQueries)
|
|
1505
|
-
score += 0.25;
|
|
1506
|
-
if (hasCaching)
|
|
1507
|
-
score += 0.2;
|
|
1508
|
-
return Math.min(score, 1.0);
|
|
1509
|
-
}
|
|
1510
|
-
assessApiPerformance(handlers) {
|
|
1511
|
-
// Assess based on error handling and caching in API handlers
|
|
1512
|
-
const handlerString = JSON.stringify(handlers);
|
|
1513
|
-
const hasErrorHandling = handlerString.includes('error');
|
|
1514
|
-
const hasCaching = handlerString.includes('cache');
|
|
1515
|
-
const hasTimeout = handlerString.includes('timeout');
|
|
1516
|
-
let score = 0.4;
|
|
1517
|
-
if (hasErrorHandling)
|
|
1518
|
-
score += 0.25;
|
|
1519
|
-
if (hasCaching)
|
|
1520
|
-
score += 0.25;
|
|
1521
|
-
if (hasTimeout)
|
|
1522
|
-
score += 0.1;
|
|
1523
|
-
return Math.min(score, 1.0);
|
|
1524
|
-
}
|
|
1525
|
-
// Utility methods
|
|
1526
|
-
capitalizeFirst(str) {
|
|
1527
|
-
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
1528
|
-
}
|
|
1529
|
-
}
|
|
1530
|
-
exports.WidgetBackendAgent = WidgetBackendAgent;
|
|
1531
|
-
//# sourceMappingURL=widget-backend.agent.js.map
|