sfdx-hardis 6.4.4 → 6.5.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/CHANGELOG.md +8 -3
- package/lib/commands/hardis/org/files/export.js +56 -4
- package/lib/commands/hardis/org/files/export.js.map +1 -1
- package/lib/common/utils/filesUtils.d.ts +34 -14
- package/lib/common/utils/filesUtils.js +260 -70
- package/lib/common/utils/filesUtils.js.map +1 -1
- package/lib/common/utils/index.js +8 -2
- package/lib/common/utils/index.js.map +1 -1
- package/lib/common/utils/limitUtils.d.ts +42 -0
- package/lib/common/utils/limitUtils.js +163 -0
- package/lib/common/utils/limitUtils.js.map +1 -0
- package/oclif.manifest.json +501 -494
- package/package.json +1 -1
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
// External Libraries and Node.js Modules
|
|
2
|
+
import c from 'chalk';
|
|
3
|
+
// Salesforce Specific Libraries
|
|
4
|
+
import { SfError } from '@salesforce/core';
|
|
5
|
+
// Project Specific Utilities
|
|
6
|
+
import { uxLog } from './index.js';
|
|
7
|
+
// Optimized API Limits Management System
|
|
8
|
+
export class ApiLimitsManager {
|
|
9
|
+
conn;
|
|
10
|
+
commandThis;
|
|
11
|
+
// Caching system
|
|
12
|
+
cachedLimits = null;
|
|
13
|
+
lastRefreshTime = 0;
|
|
14
|
+
cacheDuration = 5 * 60 * 1000; // 5 minutes
|
|
15
|
+
// Local tracking counters
|
|
16
|
+
localRestApiCalls = 0;
|
|
17
|
+
localBulkApiCalls = 0;
|
|
18
|
+
// Base limits from Salesforce
|
|
19
|
+
baseRestApiUsed = 0;
|
|
20
|
+
baseRestApiLimit = 0;
|
|
21
|
+
baseBulkApiUsed = 0;
|
|
22
|
+
baseBulkApiLimit = 0;
|
|
23
|
+
// Thresholds for API management
|
|
24
|
+
WARNING_THRESHOLD = 70; // Force refresh at 70%
|
|
25
|
+
DANGER_THRESHOLD = 80; // Stop operations at 80%
|
|
26
|
+
constructor(conn, commandThis) {
|
|
27
|
+
this.conn = conn;
|
|
28
|
+
this.commandThis = commandThis;
|
|
29
|
+
}
|
|
30
|
+
// Initialize the limits manager with initial API limits data
|
|
31
|
+
async initialize() {
|
|
32
|
+
await this.refreshLimits(); // Initial refresh
|
|
33
|
+
}
|
|
34
|
+
// Refresh limits from Salesforce
|
|
35
|
+
async refreshLimits() {
|
|
36
|
+
const now = Date.now();
|
|
37
|
+
try {
|
|
38
|
+
uxLog("log", this.commandThis, c.grey(`Refreshing API limits from Salesforce...`));
|
|
39
|
+
// Fetch fresh limits from Salesforce
|
|
40
|
+
this.cachedLimits = await this.conn.limits();
|
|
41
|
+
if (!this.cachedLimits) {
|
|
42
|
+
throw new SfError("Unable to retrieve API limit information from Salesforce org.");
|
|
43
|
+
}
|
|
44
|
+
// Extract REST API limits
|
|
45
|
+
if (!this.cachedLimits.DailyApiRequests) {
|
|
46
|
+
throw new SfError("DailyApiRequests limit not available from Salesforce org.");
|
|
47
|
+
}
|
|
48
|
+
this.baseRestApiUsed = this.cachedLimits.DailyApiRequests.Max - this.cachedLimits.DailyApiRequests.Remaining;
|
|
49
|
+
this.baseRestApiLimit = this.cachedLimits.DailyApiRequests.Max;
|
|
50
|
+
// Extract Bulk API v2 limits
|
|
51
|
+
if (!this.cachedLimits.DailyBulkV2QueryJobs) {
|
|
52
|
+
throw new SfError("DailyBulkV2QueryJobs limit not available from Salesforce org.");
|
|
53
|
+
}
|
|
54
|
+
this.baseBulkApiUsed = this.cachedLimits.DailyBulkV2QueryJobs.Max - this.cachedLimits.DailyBulkV2QueryJobs.Remaining;
|
|
55
|
+
this.baseBulkApiLimit = this.cachedLimits.DailyBulkV2QueryJobs.Max;
|
|
56
|
+
// Reset local counters on fresh data
|
|
57
|
+
this.localRestApiCalls = 0;
|
|
58
|
+
this.localBulkApiCalls = 0;
|
|
59
|
+
this.lastRefreshTime = now;
|
|
60
|
+
uxLog("success", this.commandThis, `API Limits refreshed - REST: ${this.baseRestApiUsed}/${this.baseRestApiLimit}, Bulk: ${this.baseBulkApiUsed}/${this.baseBulkApiLimit}`);
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
if (error instanceof SfError)
|
|
64
|
+
throw error;
|
|
65
|
+
throw new SfError(`Failed to refresh API limits: ${error?.message || 'Unknown error'}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// Track API call and check if we need to wait or refresh
|
|
69
|
+
async trackApiCall(apiType) {
|
|
70
|
+
// Increment local counter
|
|
71
|
+
if (apiType === 'REST') {
|
|
72
|
+
this.localRestApiCalls++;
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
this.localBulkApiCalls++;
|
|
76
|
+
}
|
|
77
|
+
// Check if cache has expired (5 minutes)
|
|
78
|
+
const now = Date.now();
|
|
79
|
+
const cacheAge = now - this.lastRefreshTime;
|
|
80
|
+
const cacheExpired = cacheAge >= this.cacheDuration;
|
|
81
|
+
if (cacheExpired) {
|
|
82
|
+
await this.refreshLimits(); // Use smart caching (no force)
|
|
83
|
+
}
|
|
84
|
+
// Calculate current usage after potential refresh
|
|
85
|
+
const currentRestUsage = this.baseRestApiUsed + this.localRestApiCalls;
|
|
86
|
+
const currentBulkUsage = this.baseBulkApiUsed + this.localBulkApiCalls;
|
|
87
|
+
const restPercent = (currentRestUsage / this.baseRestApiLimit) * 100;
|
|
88
|
+
const bulkPercent = (currentBulkUsage / this.baseBulkApiLimit) * 100;
|
|
89
|
+
// Check if we need to wait due to danger threshold
|
|
90
|
+
if (apiType === 'REST' && restPercent >= this.DANGER_THRESHOLD) {
|
|
91
|
+
await this.waitForLimitReset('REST', restPercent);
|
|
92
|
+
}
|
|
93
|
+
if (apiType === 'BULK' && bulkPercent >= this.DANGER_THRESHOLD) {
|
|
94
|
+
await this.waitForLimitReset('BULK', bulkPercent);
|
|
95
|
+
}
|
|
96
|
+
} // Wait for API limits to reset
|
|
97
|
+
async waitForLimitReset(apiType, currentPercent) {
|
|
98
|
+
const WAIT_INTERVAL = 300; // 5 minutes
|
|
99
|
+
const MAX_CYCLES = 12; // 1 hour max
|
|
100
|
+
uxLog("warning", this.commandThis, c.yellow(`${apiType} API at ${currentPercent.toFixed(1)}%. Waiting for limits to reset...`));
|
|
101
|
+
for (let cycle = 0; cycle < MAX_CYCLES; cycle++) {
|
|
102
|
+
uxLog("action", this.commandThis, c.cyan(`Waiting ${WAIT_INTERVAL}s for ${apiType} API reset (${cycle + 1}/${MAX_CYCLES})...`));
|
|
103
|
+
// Wait in 1-second intervals
|
|
104
|
+
for (let i = 0; i < WAIT_INTERVAL; i++) {
|
|
105
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
106
|
+
}
|
|
107
|
+
// Check if limits have reset
|
|
108
|
+
await this.refreshLimits();
|
|
109
|
+
const currentUsage = apiType === 'REST'
|
|
110
|
+
? this.baseRestApiUsed + this.localRestApiCalls
|
|
111
|
+
: this.baseBulkApiUsed + this.localBulkApiCalls;
|
|
112
|
+
const limit = apiType === 'REST' ? this.baseRestApiLimit : this.baseBulkApiLimit;
|
|
113
|
+
const percent = (currentUsage / limit) * 100;
|
|
114
|
+
if (percent < this.WARNING_THRESHOLD) {
|
|
115
|
+
uxLog("success", this.commandThis, c.green(`${apiType} API usage dropped to ${percent.toFixed(1)}%. Resuming operations.`));
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
throw new SfError(`${apiType} API limits did not reset after ${MAX_CYCLES * WAIT_INTERVAL / 60} minutes.`);
|
|
120
|
+
}
|
|
121
|
+
// Get current API usage status for display
|
|
122
|
+
getUsageStatus() {
|
|
123
|
+
const currentRestUsage = this.baseRestApiUsed + this.localRestApiCalls;
|
|
124
|
+
const currentBulkUsage = this.baseBulkApiUsed + this.localBulkApiCalls;
|
|
125
|
+
const restPercent = (currentRestUsage / this.baseRestApiLimit) * 100;
|
|
126
|
+
const bulkPercent = (currentBulkUsage / this.baseBulkApiLimit) * 100;
|
|
127
|
+
return {
|
|
128
|
+
rest: restPercent,
|
|
129
|
+
bulk: bulkPercent,
|
|
130
|
+
message: `[REST: ${restPercent.toFixed(1)}% | Bulk: ${bulkPercent.toFixed(1)}%]`
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
// Get current usage for API consumption estimation
|
|
134
|
+
getCurrentUsage() {
|
|
135
|
+
const currentRestUsage = this.baseRestApiUsed + this.localRestApiCalls;
|
|
136
|
+
const currentBulkUsage = this.baseBulkApiUsed + this.localBulkApiCalls;
|
|
137
|
+
return {
|
|
138
|
+
restUsed: currentRestUsage,
|
|
139
|
+
restLimit: this.baseRestApiLimit,
|
|
140
|
+
bulkUsed: currentBulkUsage,
|
|
141
|
+
bulkLimit: this.baseBulkApiLimit,
|
|
142
|
+
restRemaining: this.baseRestApiLimit - currentRestUsage,
|
|
143
|
+
bulkRemaining: this.baseBulkApiLimit - currentBulkUsage
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
// Get final usage for reporting (forces a fresh refresh)
|
|
147
|
+
async getFinalUsage() {
|
|
148
|
+
await this.refreshLimits(); // Get fresh data
|
|
149
|
+
// Try to get fresh limits from Salesforce
|
|
150
|
+
const currentLimits = this.cachedLimits;
|
|
151
|
+
const restUsed = currentLimits.DailyApiRequests.Max - currentLimits.DailyApiRequests.Remaining;
|
|
152
|
+
const bulkUsed = currentLimits.DailyBulkV2QueryJobs.Max - currentLimits.DailyBulkV2QueryJobs.Remaining;
|
|
153
|
+
return {
|
|
154
|
+
restUsed: restUsed,
|
|
155
|
+
restLimit: currentLimits.DailyApiRequests.Max,
|
|
156
|
+
restRemaining: currentLimits.DailyApiRequests.Remaining,
|
|
157
|
+
bulkUsed: bulkUsed,
|
|
158
|
+
bulkLimit: currentLimits.DailyBulkV2QueryJobs.Max,
|
|
159
|
+
bulkRemaining: currentLimits.DailyBulkV2QueryJobs.Remaining
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=limitUtils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"limitUtils.js","sourceRoot":"","sources":["../../../src/common/utils/limitUtils.ts"],"names":[],"mappings":"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"}
|