@simplysf/simply-apex 1.6.8 → 1.6.10
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/lib/commands/simply/apex/execute.d.ts +2 -11
- package/lib/commands/simply/apex/execute.js +16 -19
- package/lib/commands/simply/apex/execute.js.map +1 -1
- package/lib/commands/simply/apex/logs/purge.d.ts +2 -14
- package/lib/commands/simply/apex/logs/purge.js +7 -81
- package/lib/commands/simply/apex/logs/purge.js.map +1 -1
- package/lib/commands/simply/apex/trace/setup.d.ts +2 -13
- package/lib/commands/simply/apex/trace/setup.js +47 -87
- package/lib/commands/simply/apex/trace/setup.js.map +1 -1
- package/lib/commands/simply/apex/trace/silence.d.ts +2 -6
- package/lib/commands/simply/apex/trace/silence.js +51 -143
- package/lib/commands/simply/apex/trace/silence.js.map +1 -1
- package/lib/common/apexExecute.d.ts +31 -0
- package/lib/common/apexExecute.js +60 -0
- package/lib/common/apexExecute.js.map +1 -0
- package/lib/common/apexLogsPurge.d.ts +34 -0
- package/lib/common/apexLogsPurge.js +100 -0
- package/lib/common/apexLogsPurge.js.map +1 -0
- package/lib/common/apexTraceSetup.d.ts +57 -0
- package/lib/common/apexTraceSetup.js +142 -0
- package/lib/common/apexTraceSetup.js.map +1 -0
- package/lib/common/apexTraceSilence.d.ts +65 -0
- package/lib/common/apexTraceSilence.js +171 -0
- package/lib/common/apexTraceSilence.js.map +1 -0
- package/lib/common/schemas/classesToSilence.js.map +1 -0
- package/package.json +3 -14
- package/lib/schemas/silence/classesToSilence.js.map +0 -1
- /package/lib/{schemas/silence → common/schemas}/classesToSilence.d.ts +0 -0
- /package/lib/{schemas/silence → common/schemas}/classesToSilence.js +0 -0
|
@@ -16,58 +16,9 @@
|
|
|
16
16
|
import { Messages } from '@salesforce/core';
|
|
17
17
|
import { SfCommand, Flags } from '@salesforce/sf-plugins-core';
|
|
18
18
|
import { requireConnection, targetOrgFlags } from '@simplysf/simply-plugin-kit';
|
|
19
|
-
import {
|
|
20
|
-
import { ClassesToSilenceSchema } from '../../../../schemas/silence/classesToSilence.js';
|
|
19
|
+
import { ApexTraceSilenceError, resolveClasses, silenceApexClasses, } from '../../../../common/apexTraceSilence.js';
|
|
21
20
|
Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
|
|
22
21
|
const messages = Messages.loadMessages('@simplysf/simply-apex', 'simply.apex.trace.silence');
|
|
23
|
-
/** DeveloperName used for the fully-suppressed (NONE) debug level created for class silencing. */
|
|
24
|
-
const DEBUG_LEVEL_NAME = 'Silence';
|
|
25
|
-
/** How long a configured trace flag stays active before expiring, in milliseconds (24 hours). */
|
|
26
|
-
const TRACE_DURATION_MS = 24 * 60 * 60 * 1000;
|
|
27
|
-
/** Classes silenced by the `--fflib` flag. */
|
|
28
|
-
const FFLIB_CLASSES = ['fflib_SObjectDescribe', 'fflib_SObjectDomain'];
|
|
29
|
-
/** Classes silenced by the `--at4dx` flag. */
|
|
30
|
-
const AT4DX_CLASSES = ['ApplicationSObjectDomain'];
|
|
31
|
-
/** Classes silenced by the `--force-di` flag. */
|
|
32
|
-
const FORCE_DI_CLASSES = ['di_Binding', 'di_Module', 'di_PlatformCache', 'di_Injector'];
|
|
33
|
-
/**
|
|
34
|
-
* Resolve the list of Apex class names to silence from the `--classes` flag (a comma-separated
|
|
35
|
-
* list), the `--classes-file` flag (a JSON config file matching {@link ClassesToSilenceSchema}),
|
|
36
|
-
* and the `--fflib`, `--at4dx`, and `--force-di` preset flags. All sources are combined and
|
|
37
|
-
* deduplicated.
|
|
38
|
-
*
|
|
39
|
-
* @param classesFlag - The raw `--classes` flag value, if provided.
|
|
40
|
-
* @param classesFileFlag - The raw `--classes-file` flag value, if provided.
|
|
41
|
-
* @param presetFlags - Which of the built-in class presets were requested.
|
|
42
|
-
* @returns The resolved, trimmed, deduplicated list of Apex class names.
|
|
43
|
-
* @throws {SfError} If `--classes-file` was provided but fails schema validation.
|
|
44
|
-
*/
|
|
45
|
-
function resolveClasses(classesFlag, classesFileFlag, presetFlags) {
|
|
46
|
-
const classes = [];
|
|
47
|
-
if (classesFlag) {
|
|
48
|
-
classes.push(...classesFlag
|
|
49
|
-
.split(',')
|
|
50
|
-
.map((className) => className.trim())
|
|
51
|
-
.filter(Boolean));
|
|
52
|
-
}
|
|
53
|
-
if (classesFileFlag) {
|
|
54
|
-
const parsed = loadJsonConfigSync(classesFileFlag, ClassesToSilenceSchema);
|
|
55
|
-
if (!parsed.success) {
|
|
56
|
-
throw messages.createError('error.invalidClassesFile', [parsed.message]);
|
|
57
|
-
}
|
|
58
|
-
classes.push(...parsed.data.classes);
|
|
59
|
-
}
|
|
60
|
-
if (presetFlags.fflib) {
|
|
61
|
-
classes.push(...FFLIB_CLASSES);
|
|
62
|
-
}
|
|
63
|
-
if (presetFlags.at4dx) {
|
|
64
|
-
classes.push(...AT4DX_CLASSES);
|
|
65
|
-
}
|
|
66
|
-
if (presetFlags.forceDi) {
|
|
67
|
-
classes.push(...FORCE_DI_CLASSES);
|
|
68
|
-
}
|
|
69
|
-
return [...new Set(classes)];
|
|
70
|
-
}
|
|
71
22
|
/**
|
|
72
23
|
* Creates or updates a 24-hour CLASS_TRACING trace flag with a fully suppressed (NONE) debug
|
|
73
24
|
* level for each specified Apex class, preventing those classes from generating debug log
|
|
@@ -117,118 +68,75 @@ export default class ApexTraceSilence extends SfCommand {
|
|
|
117
68
|
async run() {
|
|
118
69
|
const { flags } = await this.parse(ApexTraceSilence);
|
|
119
70
|
const targetOrgConnection = requireConnection(flags);
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
71
|
+
const classNames = flags.classes
|
|
72
|
+
? flags.classes
|
|
73
|
+
.split(',')
|
|
74
|
+
.map((className) => className.trim())
|
|
75
|
+
.filter(Boolean)
|
|
76
|
+
: [];
|
|
77
|
+
let classes;
|
|
78
|
+
try {
|
|
79
|
+
classes = resolveClasses(classNames, flags['classes-file'], {
|
|
80
|
+
fflib: flags.fflib,
|
|
81
|
+
at4dx: flags.at4dx,
|
|
82
|
+
forceDi: flags['force-di'],
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
if (error instanceof ApexTraceSilenceError && error.code === 'invalid-classes-file') {
|
|
87
|
+
throw messages.createError('error.invalidClassesFile', [error.message]);
|
|
88
|
+
}
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
125
91
|
if (classes.length === 0) {
|
|
126
92
|
throw messages.createError('error.noClassesSpecified');
|
|
127
93
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
Visualforce: 'NONE',
|
|
145
|
-
Workflow: 'NONE',
|
|
94
|
+
let outcome;
|
|
95
|
+
try {
|
|
96
|
+
outcome = await silenceApexClasses(targetOrgConnection, classes, (phase) => {
|
|
97
|
+
switch (phase) {
|
|
98
|
+
case 'checking-debug-level':
|
|
99
|
+
this.spinner.start(messages.getMessage('info.checkingDebugLevel'));
|
|
100
|
+
break;
|
|
101
|
+
case 'finding-classes':
|
|
102
|
+
this.spinner.stop();
|
|
103
|
+
this.spinner.start(messages.getMessage('info.findingClasses'));
|
|
104
|
+
break;
|
|
105
|
+
case 'creating-trace-flags':
|
|
106
|
+
this.spinner.stop();
|
|
107
|
+
this.spinner.start(messages.getMessage('info.creatingTraceFlags'));
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
146
110
|
});
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
this.spinner.stop();
|
|
114
|
+
if (error instanceof ApexTraceSilenceError && error.code === 'debug-level-create-failed') {
|
|
115
|
+
throw messages.createError('error.debugLevelCreateFailed', [error.message]);
|
|
151
116
|
}
|
|
152
|
-
|
|
117
|
+
throw error;
|
|
153
118
|
}
|
|
154
119
|
this.spinner.stop();
|
|
155
|
-
|
|
156
|
-
const classesClause = classes.map((className) => `'${className}'`).join(',');
|
|
157
|
-
const classResult = await targetOrgConnection.tooling.query(`SELECT Id, Name FROM ApexClass WHERE Name IN (${classesClause})`);
|
|
158
|
-
this.spinner.stop();
|
|
159
|
-
if (classResult.records.length === 0) {
|
|
120
|
+
if (outcome.results.length === 0 && outcome.missingClassNames.length === classes.length) {
|
|
160
121
|
this.warn(messages.getMessage('warning.noClassesFound'));
|
|
161
122
|
return [];
|
|
162
123
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
if (missingNames.length > 0) {
|
|
166
|
-
this.warn(messages.getMessage('warning.someClassesNotFound', [missingNames.join(', ')]));
|
|
124
|
+
if (outcome.missingClassNames.length > 0) {
|
|
125
|
+
this.warn(messages.getMessage('warning.someClassesNotFound', [outcome.missingClassNames.join(', ')]));
|
|
167
126
|
}
|
|
168
|
-
const
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
const expirationDate = expiration.toISOString();
|
|
172
|
-
const classIdsClause = classResult.records.map((record) => `'${record.Id}'`).join(',');
|
|
173
|
-
const existingTraceFlagResult = await targetOrgConnection.tooling.query(`SELECT Id, TracedEntityId FROM TraceFlag WHERE LogType = 'CLASS_TRACING' AND TracedEntityId IN (${classIdsClause})`);
|
|
174
|
-
const existingTraceFlagIdByClassId = new Map(existingTraceFlagResult.records.map((record) => [record.TracedEntityId, record.Id]));
|
|
175
|
-
const results = [];
|
|
176
|
-
this.spinner.start(messages.getMessage('info.creatingTraceFlags'));
|
|
177
|
-
for (const classRecord of classResult.records) {
|
|
178
|
-
const existingTraceFlagId = existingTraceFlagIdByClassId.get(classRecord.Id);
|
|
179
|
-
if (existingTraceFlagId) {
|
|
180
|
-
// eslint-disable-next-line no-await-in-loop
|
|
181
|
-
const updateResult = await targetOrgConnection.tooling.sobject('TraceFlag').update({
|
|
182
|
-
Id: existingTraceFlagId,
|
|
183
|
-
DebugLevelId: debugLevelId,
|
|
184
|
-
StartDate: startDate,
|
|
185
|
-
ExpirationDate: expirationDate,
|
|
186
|
-
});
|
|
187
|
-
if (!updateResult.success) {
|
|
188
|
-
this.warn(messages.getMessage('warning.traceFlagUpdateFailed', [
|
|
189
|
-
classRecord.Name,
|
|
190
|
-
updateResult.errors.map((e) => e.message).join(', '),
|
|
191
|
-
]));
|
|
192
|
-
continue;
|
|
193
|
-
}
|
|
194
|
-
results.push({
|
|
195
|
-
class: classRecord.Name,
|
|
196
|
-
classId: classRecord.Id,
|
|
197
|
-
traceFlagId: existingTraceFlagId,
|
|
198
|
-
});
|
|
199
|
-
continue;
|
|
200
|
-
}
|
|
201
|
-
// eslint-disable-next-line no-await-in-loop
|
|
202
|
-
const createResult = await targetOrgConnection.tooling.sobject('TraceFlag').create({
|
|
203
|
-
StartDate: startDate,
|
|
204
|
-
ExpirationDate: expirationDate,
|
|
205
|
-
DebugLevelId: debugLevelId,
|
|
206
|
-
TracedEntityId: classRecord.Id,
|
|
207
|
-
LogType: 'CLASS_TRACING',
|
|
208
|
-
});
|
|
209
|
-
if (!createResult.success) {
|
|
210
|
-
this.warn(messages.getMessage('warning.traceFlagCreateFailed', [
|
|
211
|
-
classRecord.Name,
|
|
212
|
-
createResult.errors.map((e) => e.message).join(', '),
|
|
213
|
-
]));
|
|
214
|
-
continue;
|
|
215
|
-
}
|
|
216
|
-
results.push({
|
|
217
|
-
class: classRecord.Name,
|
|
218
|
-
classId: classRecord.Id,
|
|
219
|
-
traceFlagId: createResult.id,
|
|
220
|
-
});
|
|
127
|
+
for (const failure of outcome.failures) {
|
|
128
|
+
const key = failure.action === 'update' ? 'warning.traceFlagUpdateFailed' : 'warning.traceFlagCreateFailed';
|
|
129
|
+
this.warn(messages.getMessage(key, [failure.class, failure.error]));
|
|
221
130
|
}
|
|
222
|
-
this.spinner.stop();
|
|
223
131
|
this.table({
|
|
224
|
-
data: results,
|
|
132
|
+
data: outcome.results,
|
|
225
133
|
columns: [
|
|
226
134
|
{ key: 'class', name: 'CLASS' },
|
|
227
135
|
{ key: 'classId', name: 'CLASS ID' },
|
|
228
136
|
{ key: 'traceFlagId', name: 'TRACE FLAG ID' },
|
|
229
137
|
],
|
|
230
138
|
});
|
|
231
|
-
return results;
|
|
139
|
+
return outcome.results;
|
|
232
140
|
}
|
|
233
141
|
}
|
|
234
142
|
//# sourceMappingURL=silence.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"silence.js","sourceRoot":"","sources":["../../../../../src/commands/simply/apex/trace/silence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAChF,OAAO,
|
|
1
|
+
{"version":3,"file":"silence.js","sourceRoot":"","sources":["../../../../../src/commands/simply/apex/trace/silence.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Connection } from '@salesforce/core';
|
|
2
|
+
/** Compile/execution outcome for an anonymous Apex execution, including any debug logs produced. */
|
|
3
|
+
export type ApexExecuteResult = {
|
|
4
|
+
success: boolean;
|
|
5
|
+
compiled: boolean;
|
|
6
|
+
compileProblem: string;
|
|
7
|
+
exceptionMessage: string;
|
|
8
|
+
exceptionStackTrace: string;
|
|
9
|
+
line: number;
|
|
10
|
+
column: number;
|
|
11
|
+
logs?: string;
|
|
12
|
+
};
|
|
13
|
+
/** The error conditions `executeApex` signals structurally (via `code`) rather than by message text, so a `Messages`-based caller (the CLI) can map each one to its own error key without string-matching. */
|
|
14
|
+
export type ApexExecuteErrorCode = 'compile-failed' | 'execute-failed';
|
|
15
|
+
export declare class ApexExecuteError extends Error {
|
|
16
|
+
readonly code: ApexExecuteErrorCode;
|
|
17
|
+
readonly result: ApexExecuteResult;
|
|
18
|
+
constructor(code: ApexExecuteErrorCode, message: string, result: ApexExecuteResult);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Executes an anonymous block of Apex code from a local file against `connection` and returns the
|
|
22
|
+
* compile/execution result, including any debug logs produced.
|
|
23
|
+
*
|
|
24
|
+
* @param connection - The org connection to execute against.
|
|
25
|
+
* @param apexFilePath - Path to the local `.apex` file to execute.
|
|
26
|
+
* @returns The compile/execution result.
|
|
27
|
+
* @throws {ApexExecuteError} `compile-failed` if the Apex didn't compile, `execute-failed` if it
|
|
28
|
+
* compiled but threw during execution. Either way, `error.result` carries the full result so a
|
|
29
|
+
* caller can still inspect line/column/logs.
|
|
30
|
+
*/
|
|
31
|
+
export declare function executeApex(connection: Connection, apexFilePath: string): Promise<ApexExecuteResult>;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2026, Clay Chipps.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
import { ExecuteService } from '@salesforce/apex-node';
|
|
17
|
+
export class ApexExecuteError extends Error {
|
|
18
|
+
code;
|
|
19
|
+
result;
|
|
20
|
+
constructor(code, message, result) {
|
|
21
|
+
super(message);
|
|
22
|
+
this.name = 'ApexExecuteError';
|
|
23
|
+
this.code = code;
|
|
24
|
+
this.result = result;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Executes an anonymous block of Apex code from a local file against `connection` and returns the
|
|
29
|
+
* compile/execution result, including any debug logs produced.
|
|
30
|
+
*
|
|
31
|
+
* @param connection - The org connection to execute against.
|
|
32
|
+
* @param apexFilePath - Path to the local `.apex` file to execute.
|
|
33
|
+
* @returns The compile/execution result.
|
|
34
|
+
* @throws {ApexExecuteError} `compile-failed` if the Apex didn't compile, `execute-failed` if it
|
|
35
|
+
* compiled but threw during execution. Either way, `error.result` carries the full result so a
|
|
36
|
+
* caller can still inspect line/column/logs.
|
|
37
|
+
*/
|
|
38
|
+
export async function executeApex(connection, apexFilePath) {
|
|
39
|
+
const executeService = new ExecuteService(connection);
|
|
40
|
+
const response = await executeService.executeAnonymous({ apexFilePath });
|
|
41
|
+
const diagnostic = response.diagnostic?.[0];
|
|
42
|
+
const result = {
|
|
43
|
+
success: response.success,
|
|
44
|
+
compiled: response.compiled,
|
|
45
|
+
compileProblem: diagnostic?.compileProblem ?? '',
|
|
46
|
+
exceptionMessage: diagnostic?.exceptionMessage ?? '',
|
|
47
|
+
exceptionStackTrace: diagnostic?.exceptionStackTrace ?? '',
|
|
48
|
+
line: diagnostic?.lineNumber ?? -1,
|
|
49
|
+
column: diagnostic?.columnNumber ?? -1,
|
|
50
|
+
logs: response.logs,
|
|
51
|
+
};
|
|
52
|
+
if (!response.compiled) {
|
|
53
|
+
throw new ApexExecuteError('compile-failed', `Compile failed at line ${result.line}, column ${result.column}: ${result.compileProblem}`, result);
|
|
54
|
+
}
|
|
55
|
+
if (!response.success) {
|
|
56
|
+
throw new ApexExecuteError('execute-failed', `Execution failed: ${result.exceptionMessage}`, result);
|
|
57
|
+
}
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=apexExecute.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apexExecute.js","sourceRoot":"","sources":["../../src/common/apexExecute.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAiBvD,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IACzB,IAAI,CAAuB;IAC3B,MAAM,CAAoB;IAE1C,YAAmB,IAA0B,EAAE,OAAe,EAAE,MAAyB;QACvF,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;QAC/B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,UAAsB,EAAE,YAAoB;IAC5E,MAAM,cAAc,GAAG,IAAI,cAAc,CAAC,UAAU,CAAC,CAAC;IACtD,MAAM,QAAQ,GAAG,MAAM,cAAc,CAAC,gBAAgB,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC;IAEzE,MAAM,UAAU,GAAG,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC;IAE5C,MAAM,MAAM,GAAsB;QAChC,OAAO,EAAE,QAAQ,CAAC,OAAO;QACzB,QAAQ,EAAE,QAAQ,CAAC,QAAQ;QAC3B,cAAc,EAAE,UAAU,EAAE,cAAc,IAAI,EAAE;QAChD,gBAAgB,EAAE,UAAU,EAAE,gBAAgB,IAAI,EAAE;QACpD,mBAAmB,EAAE,UAAU,EAAE,mBAAmB,IAAI,EAAE;QAC1D,IAAI,EAAE,UAAU,EAAE,UAAU,IAAI,CAAC,CAAC;QAClC,MAAM,EAAE,UAAU,EAAE,YAAY,IAAI,CAAC,CAAC;QACtC,IAAI,EAAE,QAAQ,CAAC,IAAI;KACpB,CAAC;IAEF,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;QACvB,MAAM,IAAI,gBAAgB,CACxB,gBAAgB,EAChB,0BAA0B,MAAM,CAAC,IAAI,YAAY,MAAM,CAAC,MAAM,KAAK,MAAM,CAAC,cAAc,EAAE,EAC1F,MAAM,CACP,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;QACtB,MAAM,IAAI,gBAAgB,CAAC,gBAAgB,EAAE,qBAAqB,MAAM,CAAC,gBAAgB,EAAE,EAAE,MAAM,CAAC,CAAC;IACvG,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Connection } from '@salesforce/core';
|
|
2
|
+
/** Outcome of deleting a single `ApexLog` record. */
|
|
3
|
+
export type ApexLogsPurgeResult = {
|
|
4
|
+
Id: string;
|
|
5
|
+
Success: boolean;
|
|
6
|
+
Error?: string;
|
|
7
|
+
};
|
|
8
|
+
/** @returns Every `ApexLog` Id matched by `query` (a full SOQL statement), via the Tooling API, which returns them in a single response. */
|
|
9
|
+
export declare function queryApexLogIdsViaRest(connection: Connection, query: string): Promise<string[]>;
|
|
10
|
+
/**
|
|
11
|
+
* @returns Every `ApexLog` Id matched by `query` (a full SOQL statement), via a Bulk API v2 query
|
|
12
|
+
* job. The job streams CSV back, so the IDs are gathered from the record stream rather than a
|
|
13
|
+
* single response body.
|
|
14
|
+
*/
|
|
15
|
+
export declare function queryApexLogIdsViaBulkApi(connection: Connection, query: string, pollTimeout: number): Promise<string[]>;
|
|
16
|
+
/**
|
|
17
|
+
* Deletes `ApexLog` records through the core connection's SObject Collections resource, 200
|
|
18
|
+
* records per call.
|
|
19
|
+
*
|
|
20
|
+
* Deliberately not `.tooling`: `ApexLog` is exposed on both APIs, but only core REST implements
|
|
21
|
+
* the Collections resource a bulk delete needs. `/tooling/composite/sobjects` does not exist and
|
|
22
|
+
* answers 404 "The requested resource does not exist".
|
|
23
|
+
*
|
|
24
|
+
* @param onChunkComplete - Called after each 200-record chunk is deleted, with the running total —
|
|
25
|
+
* a caller (the CLI) can use this to update a progress indicator. Optional; has no effect on the
|
|
26
|
+
* delete itself.
|
|
27
|
+
*/
|
|
28
|
+
export declare function deleteApexLogsViaCollections(connection: Connection, logIds: string[], onChunkComplete?: (purged: number, total: number) => void): Promise<ApexLogsPurgeResult[]>;
|
|
29
|
+
/**
|
|
30
|
+
* Deletes `ApexLog` records through a Bulk API v2 ingest job. The whole set goes up as one job
|
|
31
|
+
* rather than in 200-record chunks, and the org processes it asynchronously without spending REST
|
|
32
|
+
* request limit.
|
|
33
|
+
*/
|
|
34
|
+
export declare function deleteApexLogsViaBulkApi(connection: Connection, logIds: string[], pollTimeout: number): Promise<ApexLogsPurgeResult[]>;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2026, Clay Chipps.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
import { chunk } from '@simplysf/simply-core';
|
|
17
|
+
/**
|
|
18
|
+
* Maximum number of `ApexLog` records to delete per SObject Collections call, which is the API's
|
|
19
|
+
* own ceiling and matches jsforce's `MAX_DML_COUNT`.
|
|
20
|
+
*/
|
|
21
|
+
const CHUNK_SIZE = 200;
|
|
22
|
+
/** @returns Every `ApexLog` Id matched by `query` (a full SOQL statement), via the Tooling API, which returns them in a single response. */
|
|
23
|
+
export async function queryApexLogIdsViaRest(connection, query) {
|
|
24
|
+
const queryResult = await connection.tooling.query(query);
|
|
25
|
+
return queryResult.records.map((record) => record.Id);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* @returns Every `ApexLog` Id matched by `query` (a full SOQL statement), via a Bulk API v2 query
|
|
29
|
+
* job. The job streams CSV back, so the IDs are gathered from the record stream rather than a
|
|
30
|
+
* single response body.
|
|
31
|
+
*/
|
|
32
|
+
export async function queryApexLogIdsViaBulkApi(connection, query, pollTimeout) {
|
|
33
|
+
const recordStream = await connection.bulk2.query(query, { pollTimeout });
|
|
34
|
+
const logIds = [];
|
|
35
|
+
for await (const record of recordStream) {
|
|
36
|
+
const { Id: id } = record;
|
|
37
|
+
if (id) {
|
|
38
|
+
logIds.push(id);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return logIds;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Deletes `ApexLog` records through the core connection's SObject Collections resource, 200
|
|
45
|
+
* records per call.
|
|
46
|
+
*
|
|
47
|
+
* Deliberately not `.tooling`: `ApexLog` is exposed on both APIs, but only core REST implements
|
|
48
|
+
* the Collections resource a bulk delete needs. `/tooling/composite/sobjects` does not exist and
|
|
49
|
+
* answers 404 "The requested resource does not exist".
|
|
50
|
+
*
|
|
51
|
+
* @param onChunkComplete - Called after each 200-record chunk is deleted, with the running total —
|
|
52
|
+
* a caller (the CLI) can use this to update a progress indicator. Optional; has no effect on the
|
|
53
|
+
* delete itself.
|
|
54
|
+
*/
|
|
55
|
+
export async function deleteApexLogsViaCollections(connection, logIds, onChunkComplete) {
|
|
56
|
+
const results = [];
|
|
57
|
+
let purged = 0;
|
|
58
|
+
for (const idChunk of chunk(logIds, CHUNK_SIZE)) {
|
|
59
|
+
// eslint-disable-next-line no-await-in-loop -- batches are sequential so progress reporting tracks real progress
|
|
60
|
+
const deleteResults = await connection.delete('ApexLog', idChunk);
|
|
61
|
+
const deleteResultsArray = Array.isArray(deleteResults) ? deleteResults : [deleteResults];
|
|
62
|
+
deleteResultsArray.forEach((deleteResult, index) => {
|
|
63
|
+
results.push({
|
|
64
|
+
Id: deleteResult.id ?? idChunk[index] ?? 'unknown',
|
|
65
|
+
Success: deleteResult.success,
|
|
66
|
+
Error: deleteResult.success ? undefined : deleteResult.errors.map((e) => e.message).join(', '),
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
purged += idChunk.length;
|
|
70
|
+
onChunkComplete?.(purged, logIds.length);
|
|
71
|
+
}
|
|
72
|
+
return results;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Deletes `ApexLog` records through a Bulk API v2 ingest job. The whole set goes up as one job
|
|
76
|
+
* rather than in 200-record chunks, and the org processes it asynchronously without spending REST
|
|
77
|
+
* request limit.
|
|
78
|
+
*/
|
|
79
|
+
export async function deleteApexLogsViaBulkApi(connection, logIds, pollTimeout) {
|
|
80
|
+
const { successfulResults, failedResults } = await connection.bulk2.loadAndWaitForResults({
|
|
81
|
+
object: 'ApexLog',
|
|
82
|
+
operation: 'delete',
|
|
83
|
+
input: logIds.map((Id) => ({ Id })),
|
|
84
|
+
pollTimeout,
|
|
85
|
+
});
|
|
86
|
+
return [
|
|
87
|
+
...successfulResults.map((result) => ({ Id: result.sf__Id, Success: true })),
|
|
88
|
+
...failedResults.map((result) => {
|
|
89
|
+
// A failed row reports an empty (not absent) `sf__Id`; the submitted `Id` column is echoed
|
|
90
|
+
// back alongside it, so prefer that to keep every failure traceable to a specific log.
|
|
91
|
+
const submittedId = result.Id;
|
|
92
|
+
return {
|
|
93
|
+
Id: result.sf__Id.length > 0 ? result.sf__Id : (submittedId ?? 'unknown'),
|
|
94
|
+
Success: false,
|
|
95
|
+
Error: result.sf__Error,
|
|
96
|
+
};
|
|
97
|
+
}),
|
|
98
|
+
];
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=apexLogsPurge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apexLogsPurge.js","sourceRoot":"","sources":["../../src/common/apexLogsPurge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { Connection } from '@salesforce/core';
|
|
2
|
+
/** Matches the ISO 8601 date-time format `--start-date`/`--end-date` require. */
|
|
3
|
+
export declare const DATE_TIME_PATTERN: RegExp;
|
|
4
|
+
/**
|
|
5
|
+
* Matches `Field:Value` for `--on-behalf-of`. The field name is restricted to safe SOQL identifier
|
|
6
|
+
* characters since, unlike the value, it can't be quoted/escaped in the query.
|
|
7
|
+
*/
|
|
8
|
+
export declare const ON_BEHALF_OF_PATTERN: RegExp;
|
|
9
|
+
/** A `Field:Value` pair identifying the user to configure the trace flag for. */
|
|
10
|
+
export type OnBehalfOf = {
|
|
11
|
+
field: string;
|
|
12
|
+
value: string;
|
|
13
|
+
};
|
|
14
|
+
/** @returns `input` parsed as a `Field:Value` pair, or `undefined` if it doesn't match `ON_BEHALF_OF_PATTERN`. */
|
|
15
|
+
export declare function parseOnBehalfOf(input: string): OnBehalfOf | undefined;
|
|
16
|
+
export type ApexTraceSetupOptions = {
|
|
17
|
+
/** Field:Value pair identifying the target user. Defaults to the connection's own username. */
|
|
18
|
+
onBehalfOf?: OnBehalfOf;
|
|
19
|
+
/** DebugLevel DeveloperName to use. Defaults to (and, if absent, creates) `ReplayDebuggerLevels`. */
|
|
20
|
+
logLevel?: string;
|
|
21
|
+
/** ISO 8601 date-time. Defaults to now. */
|
|
22
|
+
startDate?: string;
|
|
23
|
+
/** ISO 8601 date-time. Defaults to 24 hours after `startDate`. */
|
|
24
|
+
endDate?: string;
|
|
25
|
+
};
|
|
26
|
+
/** IDs of the debug level and trace flag configured for the target user, and when it expires. */
|
|
27
|
+
export type ApexTraceSetupResult = {
|
|
28
|
+
userId: string;
|
|
29
|
+
debugLevelId: string;
|
|
30
|
+
traceFlagId: string;
|
|
31
|
+
expirationDate: string;
|
|
32
|
+
};
|
|
33
|
+
/** The error conditions `setupApexTrace` signals structurally (via `code`) rather than by message text, so a `Messages`-based caller (the CLI) can map each one to its own error key without string-matching. */
|
|
34
|
+
export type ApexTraceSetupErrorCode = 'user-not-found' | 'ambiguous-on-behalf-of' | 'debug-level-not-found' | 'debug-level-create-failed' | 'trace-flag-create-failed' | 'invalid-date-range';
|
|
35
|
+
export declare class ApexTraceSetupError extends Error {
|
|
36
|
+
readonly code: ApexTraceSetupErrorCode;
|
|
37
|
+
/** The raw values a `Messages`-based caller needs to reproduce its own error text (e.g. `[userIdentifier]`, `[expirationDate, startDate]`) — not necessarily the same as `message`, which is this error's own human-readable text. */
|
|
38
|
+
readonly args: string[];
|
|
39
|
+
constructor(code: ApexTraceSetupErrorCode, message: string, args?: string[]);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Creates or updates a DEVELOPER_LOG trace flag for a target user. The target user is the one
|
|
43
|
+
* `connection` authenticates as by default, or the user identified by `options.onBehalfOf` if
|
|
44
|
+
* given. By default the trace flag uses the FINEST/FINER `ReplayDebuggerLevels` debug level
|
|
45
|
+
* suitable for the Apex Replay Debugger and runs for 24 hours starting now;
|
|
46
|
+
* `options.logLevel`/`startDate`/`endDate` override those defaults.
|
|
47
|
+
*
|
|
48
|
+
* @param connection - The org connection to configure the trace flag in.
|
|
49
|
+
* @param options - See `ApexTraceSetupOptions`.
|
|
50
|
+
* @param onPhase - Called as each of the three phases (finding the user, checking the debug
|
|
51
|
+
* level, configuring the trace flag) starts — a caller (the CLI) can use this to update a
|
|
52
|
+
* spinner. Optional; has no effect on the operation itself.
|
|
53
|
+
* @returns The IDs of the debug level and trace flag that were created or updated, and the trace
|
|
54
|
+
* flag's new expiration date.
|
|
55
|
+
* @throws {ApexTraceSetupError} See `ApexTraceSetupErrorCode`.
|
|
56
|
+
*/
|
|
57
|
+
export declare function setupApexTrace(connection: Connection, options?: ApexTraceSetupOptions, onPhase?: (phase: 'finding-user' | 'checking-debug-level' | 'configuring-trace-flag') => void): Promise<ApexTraceSetupResult>;
|