@reaudit/mcp-server 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +33 -0
- package/README.md +399 -0
- package/dist/auth/oauth-client.d.ts +43 -0
- package/dist/auth/oauth-client.d.ts.map +1 -0
- package/dist/auth/oauth-client.js +340 -0
- package/dist/auth/oauth-client.js.map +1 -0
- package/dist/auth/token-store.d.ts +41 -0
- package/dist/auth/token-store.d.ts.map +1 -0
- package/dist/auth/token-store.js +176 -0
- package/dist/auth/token-store.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +480 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/api-client.d.ts +970 -0
- package/dist/lib/api-client.d.ts.map +1 -0
- package/dist/lib/api-client.js +441 -0
- package/dist/lib/api-client.js.map +1 -0
- package/dist/lib/confirmation.d.ts +92 -0
- package/dist/lib/confirmation.d.ts.map +1 -0
- package/dist/lib/confirmation.js +224 -0
- package/dist/lib/confirmation.js.map +1 -0
- package/dist/lib/error-handler.d.ts +57 -0
- package/dist/lib/error-handler.d.ts.map +1 -0
- package/dist/lib/error-handler.js +235 -0
- package/dist/lib/error-handler.js.map +1 -0
- package/dist/lib/offline-mode.d.ts +107 -0
- package/dist/lib/offline-mode.d.ts.map +1 -0
- package/dist/lib/offline-mode.js +356 -0
- package/dist/lib/offline-mode.js.map +1 -0
- package/dist/lib/progress-tracker.d.ts +87 -0
- package/dist/lib/progress-tracker.d.ts.map +1 -0
- package/dist/lib/progress-tracker.js +238 -0
- package/dist/lib/progress-tracker.js.map +1 -0
- package/dist/prompts/index.d.ts +24 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +305 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/resources/index.d.ts +44 -0
- package/dist/resources/index.d.ts.map +1 -0
- package/dist/resources/index.js +125 -0
- package/dist/resources/index.js.map +1 -0
- package/dist/tools/account.d.ts +25 -0
- package/dist/tools/account.d.ts.map +1 -0
- package/dist/tools/account.js +69 -0
- package/dist/tools/account.js.map +1 -0
- package/dist/tools/action-grids.d.ts +414 -0
- package/dist/tools/action-grids.d.ts.map +1 -0
- package/dist/tools/action-grids.js +271 -0
- package/dist/tools/action-grids.js.map +1 -0
- package/dist/tools/analytics-query.d.ts +126 -0
- package/dist/tools/analytics-query.d.ts.map +1 -0
- package/dist/tools/analytics-query.js +106 -0
- package/dist/tools/analytics-query.js.map +1 -0
- package/dist/tools/analytics.d.ts +57 -0
- package/dist/tools/analytics.d.ts.map +1 -0
- package/dist/tools/analytics.js +122 -0
- package/dist/tools/analytics.js.map +1 -0
- package/dist/tools/audits.d.ts +123 -0
- package/dist/tools/audits.d.ts.map +1 -0
- package/dist/tools/audits.js +226 -0
- package/dist/tools/audits.js.map +1 -0
- package/dist/tools/calendar.d.ts +57 -0
- package/dist/tools/calendar.d.ts.map +1 -0
- package/dist/tools/calendar.js +109 -0
- package/dist/tools/calendar.js.map +1 -0
- package/dist/tools/content-generation.d.ts +211 -0
- package/dist/tools/content-generation.d.ts.map +1 -0
- package/dist/tools/content-generation.js +363 -0
- package/dist/tools/content-generation.js.map +1 -0
- package/dist/tools/content.d.ts +92 -0
- package/dist/tools/content.d.ts.map +1 -0
- package/dist/tools/content.js +130 -0
- package/dist/tools/content.js.map +1 -0
- package/dist/tools/indexing.d.ts +132 -0
- package/dist/tools/indexing.d.ts.map +1 -0
- package/dist/tools/indexing.js +190 -0
- package/dist/tools/indexing.js.map +1 -0
- package/dist/tools/optimization.d.ts +70 -0
- package/dist/tools/optimization.d.ts.map +1 -0
- package/dist/tools/optimization.js +106 -0
- package/dist/tools/optimization.js.map +1 -0
- package/dist/tools/projects.d.ts +67 -0
- package/dist/tools/projects.d.ts.map +1 -0
- package/dist/tools/projects.js +113 -0
- package/dist/tools/projects.js.map +1 -0
- package/dist/tools/prompts.d.ts +306 -0
- package/dist/tools/prompts.d.ts.map +1 -0
- package/dist/tools/prompts.js +378 -0
- package/dist/tools/prompts.js.map +1 -0
- package/dist/tools/publishing.d.ts +135 -0
- package/dist/tools/publishing.d.ts.map +1 -0
- package/dist/tools/publishing.js +209 -0
- package/dist/tools/publishing.js.map +1 -0
- package/dist/tools/reports.d.ts +252 -0
- package/dist/tools/reports.d.ts.map +1 -0
- package/dist/tools/reports.js +183 -0
- package/dist/tools/reports.js.map +1 -0
- package/dist/tools/social.d.ts +224 -0
- package/dist/tools/social.d.ts.map +1 -0
- package/dist/tools/social.js +291 -0
- package/dist/tools/social.js.map +1 -0
- package/dist/tools/sources.d.ts +221 -0
- package/dist/tools/sources.d.ts.map +1 -0
- package/dist/tools/sources.js +308 -0
- package/dist/tools/sources.js.map +1 -0
- package/dist/tools/strategy.d.ts +345 -0
- package/dist/tools/strategy.d.ts.map +1 -0
- package/dist/tools/strategy.js +392 -0
- package/dist/tools/strategy.js.map +1 -0
- package/dist/tools/usage.d.ts +101 -0
- package/dist/tools/usage.d.ts.map +1 -0
- package/dist/tools/usage.js +184 -0
- package/dist/tools/usage.js.map +1 -0
- package/dist/tools/visibility.d.ts +95 -0
- package/dist/tools/visibility.d.ts.map +1 -0
- package/dist/tools/visibility.js +163 -0
- package/dist/tools/visibility.js.map +1 -0
- package/package.json +54 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Human-in-the-Loop Confirmation System
|
|
4
|
+
*
|
|
5
|
+
* Provides confirmation flows for high-risk or high-cost operations.
|
|
6
|
+
* Uses MCP's built-in confirmation mechanism when available.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.OperationType = exports.RiskLevel = void 0;
|
|
10
|
+
exports.requiresConfirmation = requiresConfirmation;
|
|
11
|
+
exports.getOperationConfig = getOperationConfig;
|
|
12
|
+
exports.createConfirmationRequest = createConfirmationRequest;
|
|
13
|
+
exports.validateConfirmation = validateConfirmation;
|
|
14
|
+
exports.formatConfirmationMessage = formatConfirmationMessage;
|
|
15
|
+
exports.cleanupExpiredConfirmations = cleanupExpiredConfirmations;
|
|
16
|
+
/**
|
|
17
|
+
* Risk levels for operations
|
|
18
|
+
*/
|
|
19
|
+
var RiskLevel;
|
|
20
|
+
(function (RiskLevel) {
|
|
21
|
+
RiskLevel["LOW"] = "low";
|
|
22
|
+
RiskLevel["MEDIUM"] = "medium";
|
|
23
|
+
RiskLevel["HIGH"] = "high";
|
|
24
|
+
RiskLevel["CRITICAL"] = "critical";
|
|
25
|
+
})(RiskLevel || (exports.RiskLevel = RiskLevel = {}));
|
|
26
|
+
/**
|
|
27
|
+
* Operation types that may require confirmation
|
|
28
|
+
*/
|
|
29
|
+
var OperationType;
|
|
30
|
+
(function (OperationType) {
|
|
31
|
+
// Data modification
|
|
32
|
+
OperationType["DELETE_PROJECT"] = "delete_project";
|
|
33
|
+
OperationType["DELETE_AUDIT"] = "delete_audit";
|
|
34
|
+
OperationType["DELETE_CONTENT"] = "delete_content";
|
|
35
|
+
// Publishing/External actions
|
|
36
|
+
OperationType["PUBLISH_CONTENT"] = "publish_content";
|
|
37
|
+
OperationType["SEND_OUTREACH"] = "send_outreach";
|
|
38
|
+
// High-cost operations
|
|
39
|
+
OperationType["RUN_FULL_AUDIT"] = "run_full_audit";
|
|
40
|
+
OperationType["GENERATE_CONTENT"] = "generate_content";
|
|
41
|
+
OperationType["BULK_ANALYSIS"] = "bulk_analysis";
|
|
42
|
+
// Account changes
|
|
43
|
+
OperationType["CHANGE_SUBSCRIPTION"] = "change_subscription";
|
|
44
|
+
OperationType["REVOKE_ACCESS"] = "revoke_access";
|
|
45
|
+
})(OperationType || (exports.OperationType = OperationType = {}));
|
|
46
|
+
/**
|
|
47
|
+
* Operation configurations
|
|
48
|
+
*/
|
|
49
|
+
const OPERATION_CONFIGS = {
|
|
50
|
+
[OperationType.DELETE_PROJECT]: {
|
|
51
|
+
riskLevel: RiskLevel.CRITICAL,
|
|
52
|
+
requiresConfirmation: true,
|
|
53
|
+
warningMessage: 'This will permanently delete the project and all associated data.',
|
|
54
|
+
confirmationPrompt: 'Type the project name to confirm deletion:',
|
|
55
|
+
},
|
|
56
|
+
[OperationType.DELETE_AUDIT]: {
|
|
57
|
+
riskLevel: RiskLevel.HIGH,
|
|
58
|
+
requiresConfirmation: true,
|
|
59
|
+
warningMessage: 'This will permanently delete the audit results.',
|
|
60
|
+
confirmationPrompt: 'Are you sure you want to delete this audit?',
|
|
61
|
+
},
|
|
62
|
+
[OperationType.DELETE_CONTENT]: {
|
|
63
|
+
riskLevel: RiskLevel.MEDIUM,
|
|
64
|
+
requiresConfirmation: true,
|
|
65
|
+
warningMessage: 'This will delete the content suggestion.',
|
|
66
|
+
confirmationPrompt: 'Confirm content deletion?',
|
|
67
|
+
},
|
|
68
|
+
[OperationType.PUBLISH_CONTENT]: {
|
|
69
|
+
riskLevel: RiskLevel.HIGH,
|
|
70
|
+
requiresConfirmation: true,
|
|
71
|
+
warningMessage: 'This will publish content to your connected platforms.',
|
|
72
|
+
confirmationPrompt: 'Confirm publishing this content?',
|
|
73
|
+
},
|
|
74
|
+
[OperationType.SEND_OUTREACH]: {
|
|
75
|
+
riskLevel: RiskLevel.HIGH,
|
|
76
|
+
requiresConfirmation: true,
|
|
77
|
+
warningMessage: 'This will send emails to the specified recipients.',
|
|
78
|
+
confirmationPrompt: 'Confirm sending outreach emails?',
|
|
79
|
+
},
|
|
80
|
+
[OperationType.RUN_FULL_AUDIT]: {
|
|
81
|
+
riskLevel: RiskLevel.MEDIUM,
|
|
82
|
+
requiresConfirmation: true,
|
|
83
|
+
estimatedCost: 1,
|
|
84
|
+
warningMessage: 'Running a full audit will use 1 audit credit.',
|
|
85
|
+
confirmationPrompt: 'Proceed with the audit?',
|
|
86
|
+
},
|
|
87
|
+
[OperationType.GENERATE_CONTENT]: {
|
|
88
|
+
riskLevel: RiskLevel.LOW,
|
|
89
|
+
requiresConfirmation: false,
|
|
90
|
+
estimatedCost: 1,
|
|
91
|
+
warningMessage: 'Content generation uses AI credits.',
|
|
92
|
+
confirmationPrompt: 'Generate content?',
|
|
93
|
+
},
|
|
94
|
+
[OperationType.BULK_ANALYSIS]: {
|
|
95
|
+
riskLevel: RiskLevel.MEDIUM,
|
|
96
|
+
requiresConfirmation: true,
|
|
97
|
+
estimatedCost: 5,
|
|
98
|
+
warningMessage: 'Bulk analysis will use multiple credits.',
|
|
99
|
+
confirmationPrompt: 'Proceed with bulk analysis?',
|
|
100
|
+
},
|
|
101
|
+
[OperationType.CHANGE_SUBSCRIPTION]: {
|
|
102
|
+
riskLevel: RiskLevel.HIGH,
|
|
103
|
+
requiresConfirmation: true,
|
|
104
|
+
warningMessage: 'This will change your subscription plan.',
|
|
105
|
+
confirmationPrompt: 'Confirm subscription change?',
|
|
106
|
+
},
|
|
107
|
+
[OperationType.REVOKE_ACCESS]: {
|
|
108
|
+
riskLevel: RiskLevel.MEDIUM,
|
|
109
|
+
requiresConfirmation: true,
|
|
110
|
+
warningMessage: 'This will revoke access for the connected application.',
|
|
111
|
+
confirmationPrompt: 'Revoke access?',
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
/**
|
|
115
|
+
* Pending confirmation storage (in-memory for now)
|
|
116
|
+
*/
|
|
117
|
+
const pendingConfirmations = new Map();
|
|
118
|
+
/**
|
|
119
|
+
* Generate a confirmation token
|
|
120
|
+
*/
|
|
121
|
+
function generateConfirmationToken() {
|
|
122
|
+
return `confirm_${Date.now()}_${Math.random().toString(36).substring(2, 15)}`;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Check if an operation requires confirmation
|
|
126
|
+
*/
|
|
127
|
+
function requiresConfirmation(operationType) {
|
|
128
|
+
const config = OPERATION_CONFIGS[operationType];
|
|
129
|
+
return config?.requiresConfirmation ?? false;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Get operation configuration
|
|
133
|
+
*/
|
|
134
|
+
function getOperationConfig(operationType) {
|
|
135
|
+
return OPERATION_CONFIGS[operationType];
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Create a confirmation request
|
|
139
|
+
*/
|
|
140
|
+
function createConfirmationRequest(operationType, details) {
|
|
141
|
+
const config = OPERATION_CONFIGS[operationType];
|
|
142
|
+
if (!config) {
|
|
143
|
+
throw new Error(`Unknown operation type: ${operationType}`);
|
|
144
|
+
}
|
|
145
|
+
const token = generateConfirmationToken();
|
|
146
|
+
const request = {
|
|
147
|
+
operationType,
|
|
148
|
+
riskLevel: config.riskLevel,
|
|
149
|
+
warningMessage: config.warningMessage,
|
|
150
|
+
confirmationPrompt: config.confirmationPrompt,
|
|
151
|
+
estimatedCost: config.estimatedCost,
|
|
152
|
+
details,
|
|
153
|
+
};
|
|
154
|
+
// Store pending confirmation (expires in 5 minutes)
|
|
155
|
+
const now = Date.now();
|
|
156
|
+
pendingConfirmations.set(token, {
|
|
157
|
+
request,
|
|
158
|
+
createdAt: now,
|
|
159
|
+
expiresAt: now + 5 * 60 * 1000,
|
|
160
|
+
});
|
|
161
|
+
return { token, request };
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Validate and consume a confirmation token
|
|
165
|
+
*/
|
|
166
|
+
function validateConfirmation(token, expectedOperation) {
|
|
167
|
+
const pending = pendingConfirmations.get(token);
|
|
168
|
+
if (!pending) {
|
|
169
|
+
return { valid: false, error: 'Invalid or expired confirmation token' };
|
|
170
|
+
}
|
|
171
|
+
if (Date.now() > pending.expiresAt) {
|
|
172
|
+
pendingConfirmations.delete(token);
|
|
173
|
+
return { valid: false, error: 'Confirmation token has expired' };
|
|
174
|
+
}
|
|
175
|
+
if (expectedOperation && pending.request.operationType !== expectedOperation) {
|
|
176
|
+
return { valid: false, error: 'Confirmation token does not match operation' };
|
|
177
|
+
}
|
|
178
|
+
// Consume the token (one-time use)
|
|
179
|
+
pendingConfirmations.delete(token);
|
|
180
|
+
return { valid: true, request: pending.request };
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Format confirmation request for display
|
|
184
|
+
*/
|
|
185
|
+
function formatConfirmationMessage(request) {
|
|
186
|
+
const riskEmoji = {
|
|
187
|
+
[RiskLevel.LOW]: '',
|
|
188
|
+
[RiskLevel.MEDIUM]: '⚠️',
|
|
189
|
+
[RiskLevel.HIGH]: '⚠️⚠️',
|
|
190
|
+
[RiskLevel.CRITICAL]: '🚨',
|
|
191
|
+
};
|
|
192
|
+
let message = `${riskEmoji[request.riskLevel]} **Confirmation Required**\n\n`;
|
|
193
|
+
message += `${request.warningMessage}\n\n`;
|
|
194
|
+
if (request.estimatedCost) {
|
|
195
|
+
message += `**Estimated cost:** ${request.estimatedCost} credit(s)\n\n`;
|
|
196
|
+
}
|
|
197
|
+
if (request.details) {
|
|
198
|
+
message += '**Details:**\n';
|
|
199
|
+
for (const [key, value] of Object.entries(request.details)) {
|
|
200
|
+
message += `- ${key}: ${value}\n`;
|
|
201
|
+
}
|
|
202
|
+
message += '\n';
|
|
203
|
+
}
|
|
204
|
+
message += `${request.confirmationPrompt}\n\n`;
|
|
205
|
+
message += '_To proceed, call this tool again with `confirmed: true`_';
|
|
206
|
+
return message;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Clean up expired confirmations
|
|
210
|
+
*/
|
|
211
|
+
function cleanupExpiredConfirmations() {
|
|
212
|
+
const now = Date.now();
|
|
213
|
+
let cleaned = 0;
|
|
214
|
+
for (const [token, pending] of pendingConfirmations.entries()) {
|
|
215
|
+
if (now > pending.expiresAt) {
|
|
216
|
+
pendingConfirmations.delete(token);
|
|
217
|
+
cleaned++;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return cleaned;
|
|
221
|
+
}
|
|
222
|
+
// Run cleanup every minute
|
|
223
|
+
setInterval(cleanupExpiredConfirmations, 60 * 1000);
|
|
224
|
+
//# sourceMappingURL=confirmation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"confirmation.js","sourceRoot":"","sources":["../../src/lib/confirmation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error Handler
|
|
3
|
+
*
|
|
4
|
+
* Centralized error handling with auto-retry, user-friendly messages,
|
|
5
|
+
* and error categorization.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Error categories for user-friendly messaging
|
|
9
|
+
*/
|
|
10
|
+
export declare enum ErrorCategory {
|
|
11
|
+
AUTHENTICATION = "authentication",
|
|
12
|
+
AUTHORIZATION = "authorization",
|
|
13
|
+
RATE_LIMIT = "rate_limit",
|
|
14
|
+
NOT_FOUND = "not_found",
|
|
15
|
+
VALIDATION = "validation",
|
|
16
|
+
SERVER = "server",
|
|
17
|
+
NETWORK = "network",
|
|
18
|
+
UNKNOWN = "unknown"
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Structured error with user-friendly information
|
|
22
|
+
*/
|
|
23
|
+
export interface MCPError {
|
|
24
|
+
category: ErrorCategory;
|
|
25
|
+
message: string;
|
|
26
|
+
userMessage: string;
|
|
27
|
+
suggestion?: string;
|
|
28
|
+
retryable: boolean;
|
|
29
|
+
retryAfter?: number;
|
|
30
|
+
originalError?: Error;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Parse and categorize an error
|
|
34
|
+
*/
|
|
35
|
+
export declare function parseError(error: unknown): MCPError;
|
|
36
|
+
/**
|
|
37
|
+
* Format error for display to user
|
|
38
|
+
*/
|
|
39
|
+
export declare function formatErrorForUser(error: MCPError): string;
|
|
40
|
+
/**
|
|
41
|
+
* Retry configuration
|
|
42
|
+
*/
|
|
43
|
+
export interface RetryConfig {
|
|
44
|
+
maxRetries: number;
|
|
45
|
+
baseDelay: number;
|
|
46
|
+
maxDelay: number;
|
|
47
|
+
retryableCategories: ErrorCategory[];
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Calculate delay for retry with exponential backoff
|
|
51
|
+
*/
|
|
52
|
+
export declare function calculateRetryDelay(attempt: number, config?: RetryConfig): number;
|
|
53
|
+
/**
|
|
54
|
+
* Execute a function with automatic retry
|
|
55
|
+
*/
|
|
56
|
+
export declare function withRetry<T>(fn: () => Promise<T>, config?: Partial<RetryConfig>): Promise<T>;
|
|
57
|
+
//# sourceMappingURL=error-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-handler.d.ts","sourceRoot":"","sources":["../../src/lib/error-handler.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH;;GAEG;AACH,oBAAY,aAAa;IACvB,cAAc,mBAAmB;IACjC,aAAa,kBAAkB;IAC/B,UAAU,eAAe;IACzB,SAAS,cAAc;IACvB,UAAU,eAAe;IACzB,MAAM,WAAW;IACjB,OAAO,YAAY;IACnB,OAAO,YAAY;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,QAAQ,EAAE,aAAa,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,KAAK,CAAC;CACvB;AAqFD;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,QAAQ,CAmEnD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM,CAY1D;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB,EAAE,aAAa,EAAE,CAAC;CACtC;AAaD;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,MAAM,GAAE,WAAkC,GACzC,MAAM,CAQR;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,CAAC,EAC/B,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,MAAM,GAAE,OAAO,CAAC,WAAW,CAAM,GAChC,OAAO,CAAC,CAAC,CAAC,CA+BZ"}
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Error Handler
|
|
4
|
+
*
|
|
5
|
+
* Centralized error handling with auto-retry, user-friendly messages,
|
|
6
|
+
* and error categorization.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.ErrorCategory = void 0;
|
|
10
|
+
exports.parseError = parseError;
|
|
11
|
+
exports.formatErrorForUser = formatErrorForUser;
|
|
12
|
+
exports.calculateRetryDelay = calculateRetryDelay;
|
|
13
|
+
exports.withRetry = withRetry;
|
|
14
|
+
const axios_1 = require("axios");
|
|
15
|
+
/**
|
|
16
|
+
* Error categories for user-friendly messaging
|
|
17
|
+
*/
|
|
18
|
+
var ErrorCategory;
|
|
19
|
+
(function (ErrorCategory) {
|
|
20
|
+
ErrorCategory["AUTHENTICATION"] = "authentication";
|
|
21
|
+
ErrorCategory["AUTHORIZATION"] = "authorization";
|
|
22
|
+
ErrorCategory["RATE_LIMIT"] = "rate_limit";
|
|
23
|
+
ErrorCategory["NOT_FOUND"] = "not_found";
|
|
24
|
+
ErrorCategory["VALIDATION"] = "validation";
|
|
25
|
+
ErrorCategory["SERVER"] = "server";
|
|
26
|
+
ErrorCategory["NETWORK"] = "network";
|
|
27
|
+
ErrorCategory["UNKNOWN"] = "unknown";
|
|
28
|
+
})(ErrorCategory || (exports.ErrorCategory = ErrorCategory = {}));
|
|
29
|
+
/**
|
|
30
|
+
* Map HTTP status codes to error categories
|
|
31
|
+
*/
|
|
32
|
+
function categorizeHttpError(status) {
|
|
33
|
+
switch (status) {
|
|
34
|
+
case 401:
|
|
35
|
+
return ErrorCategory.AUTHENTICATION;
|
|
36
|
+
case 403:
|
|
37
|
+
return ErrorCategory.AUTHORIZATION;
|
|
38
|
+
case 404:
|
|
39
|
+
return ErrorCategory.NOT_FOUND;
|
|
40
|
+
case 422:
|
|
41
|
+
case 400:
|
|
42
|
+
return ErrorCategory.VALIDATION;
|
|
43
|
+
case 429:
|
|
44
|
+
return ErrorCategory.RATE_LIMIT;
|
|
45
|
+
case 500:
|
|
46
|
+
case 502:
|
|
47
|
+
case 503:
|
|
48
|
+
case 504:
|
|
49
|
+
return ErrorCategory.SERVER;
|
|
50
|
+
default:
|
|
51
|
+
return ErrorCategory.UNKNOWN;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Get user-friendly message for error category
|
|
56
|
+
*/
|
|
57
|
+
function getUserMessage(category, details) {
|
|
58
|
+
switch (category) {
|
|
59
|
+
case ErrorCategory.AUTHENTICATION:
|
|
60
|
+
return 'Your session has expired. Please re-authenticate with Reaudit.';
|
|
61
|
+
case ErrorCategory.AUTHORIZATION:
|
|
62
|
+
return details || 'You don\'t have permission to perform this action. Check your subscription tier.';
|
|
63
|
+
case ErrorCategory.RATE_LIMIT:
|
|
64
|
+
return 'You\'ve reached your usage limit. Please wait before trying again or upgrade your plan.';
|
|
65
|
+
case ErrorCategory.NOT_FOUND:
|
|
66
|
+
return details || 'The requested resource was not found. It may have been deleted or you may not have access.';
|
|
67
|
+
case ErrorCategory.VALIDATION:
|
|
68
|
+
return details || 'Invalid request. Please check your input and try again.';
|
|
69
|
+
case ErrorCategory.SERVER:
|
|
70
|
+
return 'Reaudit is experiencing issues. Please try again in a few minutes.';
|
|
71
|
+
case ErrorCategory.NETWORK:
|
|
72
|
+
return 'Unable to connect to Reaudit. Please check your internet connection.';
|
|
73
|
+
default:
|
|
74
|
+
return 'An unexpected error occurred. Please try again.';
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Get suggestion for error recovery
|
|
79
|
+
*/
|
|
80
|
+
function getSuggestion(category) {
|
|
81
|
+
switch (category) {
|
|
82
|
+
case ErrorCategory.AUTHENTICATION:
|
|
83
|
+
return 'Delete ~/.reaudit/credentials.json and restart to re-authenticate.';
|
|
84
|
+
case ErrorCategory.AUTHORIZATION:
|
|
85
|
+
return 'Visit https://reaudit.io/settings to check your subscription.';
|
|
86
|
+
case ErrorCategory.RATE_LIMIT:
|
|
87
|
+
return 'Use get_usage_summary to check your current limits.';
|
|
88
|
+
case ErrorCategory.NOT_FOUND:
|
|
89
|
+
return 'Use list_projects or list_audits to find valid IDs.';
|
|
90
|
+
case ErrorCategory.SERVER:
|
|
91
|
+
return 'Check https://status.reaudit.io for service status.';
|
|
92
|
+
case ErrorCategory.NETWORK:
|
|
93
|
+
return 'Verify you can access https://reaudit.io in your browser.';
|
|
94
|
+
default:
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Check if error is retryable
|
|
100
|
+
*/
|
|
101
|
+
function isRetryable(category) {
|
|
102
|
+
return [
|
|
103
|
+
ErrorCategory.RATE_LIMIT,
|
|
104
|
+
ErrorCategory.SERVER,
|
|
105
|
+
ErrorCategory.NETWORK,
|
|
106
|
+
].includes(category);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Parse and categorize an error
|
|
110
|
+
*/
|
|
111
|
+
function parseError(error) {
|
|
112
|
+
// Handle Axios errors
|
|
113
|
+
if (error instanceof axios_1.AxiosError) {
|
|
114
|
+
const status = error.response?.status;
|
|
115
|
+
const data = error.response?.data;
|
|
116
|
+
// Network error (no response)
|
|
117
|
+
if (!error.response) {
|
|
118
|
+
return {
|
|
119
|
+
category: ErrorCategory.NETWORK,
|
|
120
|
+
message: error.message,
|
|
121
|
+
userMessage: getUserMessage(ErrorCategory.NETWORK),
|
|
122
|
+
suggestion: getSuggestion(ErrorCategory.NETWORK),
|
|
123
|
+
retryable: true,
|
|
124
|
+
retryAfter: 5,
|
|
125
|
+
originalError: error,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
const category = categorizeHttpError(status || 500);
|
|
129
|
+
const apiMessage = data?.error_description || data?.message || data?.error;
|
|
130
|
+
// Extract retry-after header for rate limits
|
|
131
|
+
let retryAfter;
|
|
132
|
+
if (category === ErrorCategory.RATE_LIMIT) {
|
|
133
|
+
const retryHeader = error.response.headers['retry-after'];
|
|
134
|
+
if (retryHeader) {
|
|
135
|
+
// Could be seconds or a date
|
|
136
|
+
const parsed = parseInt(retryHeader);
|
|
137
|
+
if (!isNaN(parsed)) {
|
|
138
|
+
retryAfter = parsed;
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
const date = new Date(retryHeader);
|
|
142
|
+
retryAfter = Math.ceil((date.getTime() - Date.now()) / 1000);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
category,
|
|
148
|
+
message: apiMessage || error.message,
|
|
149
|
+
userMessage: getUserMessage(category, apiMessage),
|
|
150
|
+
suggestion: getSuggestion(category),
|
|
151
|
+
retryable: isRetryable(category),
|
|
152
|
+
retryAfter: retryAfter || (isRetryable(category) ? 30 : undefined),
|
|
153
|
+
originalError: error,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
// Handle standard errors
|
|
157
|
+
if (error instanceof Error) {
|
|
158
|
+
return {
|
|
159
|
+
category: ErrorCategory.UNKNOWN,
|
|
160
|
+
message: error.message,
|
|
161
|
+
userMessage: getUserMessage(ErrorCategory.UNKNOWN),
|
|
162
|
+
retryable: false,
|
|
163
|
+
originalError: error,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
// Handle unknown errors
|
|
167
|
+
return {
|
|
168
|
+
category: ErrorCategory.UNKNOWN,
|
|
169
|
+
message: String(error),
|
|
170
|
+
userMessage: getUserMessage(ErrorCategory.UNKNOWN),
|
|
171
|
+
retryable: false,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Format error for display to user
|
|
176
|
+
*/
|
|
177
|
+
function formatErrorForUser(error) {
|
|
178
|
+
let message = `**Error:** ${error.userMessage}`;
|
|
179
|
+
if (error.suggestion) {
|
|
180
|
+
message += `\n\n**Suggestion:** ${error.suggestion}`;
|
|
181
|
+
}
|
|
182
|
+
if (error.retryable && error.retryAfter) {
|
|
183
|
+
message += `\n\n*This error may be temporary. Try again in ${error.retryAfter} seconds.*`;
|
|
184
|
+
}
|
|
185
|
+
return message;
|
|
186
|
+
}
|
|
187
|
+
const DEFAULT_RETRY_CONFIG = {
|
|
188
|
+
maxRetries: 3,
|
|
189
|
+
baseDelay: 1000,
|
|
190
|
+
maxDelay: 30000,
|
|
191
|
+
retryableCategories: [
|
|
192
|
+
ErrorCategory.RATE_LIMIT,
|
|
193
|
+
ErrorCategory.SERVER,
|
|
194
|
+
ErrorCategory.NETWORK,
|
|
195
|
+
],
|
|
196
|
+
};
|
|
197
|
+
/**
|
|
198
|
+
* Calculate delay for retry with exponential backoff
|
|
199
|
+
*/
|
|
200
|
+
function calculateRetryDelay(attempt, config = DEFAULT_RETRY_CONFIG) {
|
|
201
|
+
const delay = Math.min(config.baseDelay * Math.pow(2, attempt), config.maxDelay);
|
|
202
|
+
// Add jitter (±20%)
|
|
203
|
+
const jitter = delay * 0.2 * (Math.random() - 0.5);
|
|
204
|
+
return Math.round(delay + jitter);
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Execute a function with automatic retry
|
|
208
|
+
*/
|
|
209
|
+
async function withRetry(fn, config = {}) {
|
|
210
|
+
const fullConfig = { ...DEFAULT_RETRY_CONFIG, ...config };
|
|
211
|
+
let lastError;
|
|
212
|
+
for (let attempt = 0; attempt <= fullConfig.maxRetries; attempt++) {
|
|
213
|
+
try {
|
|
214
|
+
return await fn();
|
|
215
|
+
}
|
|
216
|
+
catch (error) {
|
|
217
|
+
lastError = parseError(error);
|
|
218
|
+
// Don't retry if not retryable or max retries reached
|
|
219
|
+
if (!lastError.retryable ||
|
|
220
|
+
!fullConfig.retryableCategories.includes(lastError.category) ||
|
|
221
|
+
attempt === fullConfig.maxRetries) {
|
|
222
|
+
throw error;
|
|
223
|
+
}
|
|
224
|
+
// Wait before retrying
|
|
225
|
+
const delay = lastError.retryAfter
|
|
226
|
+
? lastError.retryAfter * 1000
|
|
227
|
+
: calculateRetryDelay(attempt, fullConfig);
|
|
228
|
+
console.error(`Retry attempt ${attempt + 1}/${fullConfig.maxRetries} after ${delay}ms`);
|
|
229
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
// Should never reach here, but TypeScript needs it
|
|
233
|
+
throw lastError?.originalError || new Error('Retry failed');
|
|
234
|
+
}
|
|
235
|
+
//# sourceMappingURL=error-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-handler.js","sourceRoot":"","sources":["../../src/lib/error-handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Offline Mode Handler
|
|
3
|
+
*
|
|
4
|
+
* Provides graceful degradation when the API is unavailable,
|
|
5
|
+
* with request queuing for retry.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Connection status
|
|
9
|
+
*/
|
|
10
|
+
export declare enum ConnectionStatus {
|
|
11
|
+
ONLINE = "online",
|
|
12
|
+
OFFLINE = "offline",
|
|
13
|
+
DEGRADED = "degraded"
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Queued request
|
|
17
|
+
*/
|
|
18
|
+
interface QueuedRequest {
|
|
19
|
+
id: string;
|
|
20
|
+
method: string;
|
|
21
|
+
path: string;
|
|
22
|
+
data?: unknown;
|
|
23
|
+
params?: Record<string, string>;
|
|
24
|
+
queuedAt: number;
|
|
25
|
+
retryCount: number;
|
|
26
|
+
maxRetries: number;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Offline mode configuration
|
|
30
|
+
*/
|
|
31
|
+
interface OfflineConfig {
|
|
32
|
+
queuePath: string;
|
|
33
|
+
maxQueueSize: number;
|
|
34
|
+
maxRetries: number;
|
|
35
|
+
checkInterval: number;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Initialize offline mode
|
|
39
|
+
*/
|
|
40
|
+
export declare function initOfflineMode(config?: Partial<OfflineConfig>): void;
|
|
41
|
+
/**
|
|
42
|
+
* Stop offline mode
|
|
43
|
+
*/
|
|
44
|
+
export declare function stopOfflineMode(): void;
|
|
45
|
+
/**
|
|
46
|
+
* Get current connection status
|
|
47
|
+
*/
|
|
48
|
+
export declare function getConnectionStatus(): ConnectionStatus;
|
|
49
|
+
/**
|
|
50
|
+
* Check if we're online
|
|
51
|
+
*/
|
|
52
|
+
export declare function isOnline(): boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Register status change callback
|
|
55
|
+
*/
|
|
56
|
+
export declare function onStatusChange(callback: (status: ConnectionStatus) => void): void;
|
|
57
|
+
/**
|
|
58
|
+
* Update connection status
|
|
59
|
+
*/
|
|
60
|
+
export declare function setConnectionStatus(status: ConnectionStatus): void;
|
|
61
|
+
/**
|
|
62
|
+
* Queue a request for later retry
|
|
63
|
+
*/
|
|
64
|
+
export declare function queueRequest(method: string, path: string, data?: unknown, params?: Record<string, string>): string;
|
|
65
|
+
/**
|
|
66
|
+
* Get queued requests
|
|
67
|
+
*/
|
|
68
|
+
export declare function getQueuedRequests(): QueuedRequest[];
|
|
69
|
+
/**
|
|
70
|
+
* Get queue size
|
|
71
|
+
*/
|
|
72
|
+
export declare function getQueueSize(): number;
|
|
73
|
+
/**
|
|
74
|
+
* Clear the request queue
|
|
75
|
+
*/
|
|
76
|
+
export declare function clearQueue(): void;
|
|
77
|
+
/**
|
|
78
|
+
* Remove a request from queue
|
|
79
|
+
*/
|
|
80
|
+
export declare function removeFromQueue(requestId: string): boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Get offline mode status for display
|
|
83
|
+
*/
|
|
84
|
+
export declare function getOfflineModeStatus(): {
|
|
85
|
+
status: ConnectionStatus;
|
|
86
|
+
queueSize: number;
|
|
87
|
+
lastCheck: string;
|
|
88
|
+
message: string;
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* Format offline status for user display
|
|
92
|
+
*/
|
|
93
|
+
export declare function formatOfflineStatus(): string;
|
|
94
|
+
/**
|
|
95
|
+
* Cache data for offline access
|
|
96
|
+
*/
|
|
97
|
+
export declare function cacheForOffline(key: string, data: unknown, ttlMs?: number): void;
|
|
98
|
+
/**
|
|
99
|
+
* Get cached data (for offline use)
|
|
100
|
+
*/
|
|
101
|
+
export declare function getOfflineCache<T>(key: string): T | null;
|
|
102
|
+
/**
|
|
103
|
+
* Clear offline cache
|
|
104
|
+
*/
|
|
105
|
+
export declare function clearOfflineCache(): void;
|
|
106
|
+
export {};
|
|
107
|
+
//# sourceMappingURL=offline-mode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"offline-mode.d.ts","sourceRoot":"","sources":["../../src/lib/offline-mode.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH;;GAEG;AACH,oBAAY,gBAAgB;IAC1B,MAAM,WAAW;IACjB,OAAO,YAAY;IACnB,QAAQ,aAAa;CACtB;AAED;;GAEG;AACH,UAAU,aAAa;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,UAAU,aAAa;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;CACvB;AAsBD;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,GAAE,OAAO,CAAC,aAAa,CAAM,GAAG,IAAI,CAczE;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,IAAI,CAKtC;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,gBAAgB,CAEtD;AAED;;GAEG;AACH,wBAAgB,QAAQ,IAAI,OAAO,CAElC;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,GAAG,IAAI,CAEjF;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAmBlE;AAWD;;GAEG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,OAAO,EACd,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC9B,MAAM,CAwBR;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,aAAa,EAAE,CAEnD;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,IAAI,CAGjC;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAQ1D;AAqED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI;IACtC,MAAM,EAAE,gBAAgB,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB,CAwBA;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAqB5C;AAcD;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,GAAE,MAAgB,GAAG,IAAI,CAQzF;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,CAcxD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAExC"}
|