@mspcopilot/n8n-nodes-connectwise 0.2.1-beta.7 → 0.2.3

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.
Files changed (56) hide show
  1. package/{dist-beta → dist-community}/credentials/ConnectWisePsaApi.credentials.js +3 -17
  2. package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/ConnectWisePsa.node.js +2 -14
  3. package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/descriptions/common.properties.js +1 -16
  4. package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/helpers/hint-collector.js +1 -1
  5. package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/methods/fieldOptions.js +0 -1
  6. package/dist-community/nodes/ConnectWise/PSA/schema/resources/alert-consolidation.js +42 -0
  7. package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/resources/custom.schema.js +1 -38
  8. package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/resources/ticket.schema.js +1 -11
  9. package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/transport/cache.js +6 -84
  10. package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/transport/client.js +5 -46
  11. package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/transport/version-check.js +18 -12
  12. package/package.json +4 -6
  13. package/dist-beta/nodes/ConnectWise/PSA/ConnectWisePsaTrigger.node.js +0 -506
  14. package/dist-beta/nodes/ConnectWise/PSA/IfSchedule.node.js +0 -333
  15. package/dist-beta/nodes/ConnectWise/PSA/schema/resources/alert-consolidation.js +0 -451
  16. package/dist-beta/nodes/ConnectWise/PSA/schema/resources/diagnostics.schema.js +0 -103
  17. package/dist-beta/nodes/ConnectWise/PSA/schema/resources/reports.schema.js +0 -206
  18. /package/{dist-beta → dist-community}/LICENSE.md +0 -0
  19. /package/{dist-beta → dist-community}/credentials/connectwise-dark.svg +0 -0
  20. /package/{dist-beta → dist-community}/credentials/connectwise-light.svg +0 -0
  21. /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/connectwise-dark.svg +0 -0
  22. /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/connectwise-light.svg +0 -0
  23. /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/descriptions/common.descriptions.js +0 -0
  24. /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/descriptions/index.js +0 -0
  25. /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/helpers/customFields.js +0 -0
  26. /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/helpers/field-collector.js +0 -0
  27. /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/helpers/field-conditions.js +0 -0
  28. /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/helpers/index.js +0 -0
  29. /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/helpers/logging.js +0 -0
  30. /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/helpers/utils.js +0 -0
  31. /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/methods/generated.js +0 -0
  32. /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/methods/index.js +0 -0
  33. /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/converter/index.js +0 -0
  34. /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/converter/reference.generator.js +0 -0
  35. /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/index.js +0 -0
  36. /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/references.js +0 -0
  37. /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/reports-descriptions.js +0 -0
  38. /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/resources/activity.schema.js +0 -0
  39. /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/resources/company.schema.js +0 -0
  40. /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/resources/contact.schema.js +0 -0
  41. /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/resources/index.js +0 -0
  42. /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/resources/members.schema.js +0 -0
  43. /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/resources/ticketNote.schema.js +0 -0
  44. /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/resources/ticketTask.schema.js +0 -0
  45. /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/resources/timeEntry.schema.js +0 -0
  46. /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/static-fields.js +0 -0
  47. /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/transformer.js +0 -0
  48. /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/types/index.js +0 -0
  49. /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/types/reference.types.js +0 -0
  50. /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/types/resource.types.js +0 -0
  51. /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/transport/access-key.js +0 -0
  52. /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/transport/index.js +0 -0
  53. /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/transport/operations.js +0 -0
  54. /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/transport/response-transformer.js +0 -0
  55. /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/types/n8n-augmentation.d.js +0 -0
  56. /package/{dist-beta → dist-community}/nodes/ConnectWisePsa.node.json +0 -0
@@ -1,451 +0,0 @@
1
- var __defProp = Object.defineProperty;
2
-
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
-
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
-
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
-
9
- var __export = (target, all) => {
10
- for (var name in all) __defProp(target, name, {
11
- get: all[name],
12
- enumerable: !0
13
- });
14
- }, __copyProps = (to, from, except, desc) => {
15
- if (from && typeof from == "object" || typeof from == "function") for (let key of __getOwnPropNames(from)) !__hasOwnProp.call(to, key) && key !== except && __defProp(to, key, {
16
- get: () => from[key],
17
- enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
18
- });
19
- return to;
20
- };
21
-
22
- var __toCommonJS = mod => __copyProps(__defProp({}, "__esModule", {
23
- value: !0
24
- }), mod);
25
-
26
- var alert_consolidation_exports = {};
27
-
28
- __export(alert_consolidation_exports, {
29
- executeSmartConsolidation: () => executeSmartConsolidation
30
- });
31
-
32
- module.exports = __toCommonJS(alert_consolidation_exports);
33
-
34
- var import_n8n_workflow = require("n8n-workflow"), import_luxon = require("luxon"), import_crypto = require("crypto"), import_client = require("../../transport/client"), import_utils = require("../../helpers/utils");
35
-
36
- const FINGERPRINT = `\n\x3c!--msp-copilot--\x3e`, FINGERPRINT_FAILURE = `\n\x3c!--msp-copilot:failure--\x3e`, FINGERPRINT_SUCCESS = `\n\x3c!--msp-copilot:success--\x3e`;
37
-
38
- function buildStatus(value) {
39
- return typeof value == "number" ? {
40
- id: value
41
- } : {
42
- name: value
43
- };
44
- }
45
-
46
- async function resolvePriority(context, value) {
47
- if (value == null || value === "") return null;
48
- if (typeof value == "number") return {
49
- id: value
50
- };
51
- try {
52
- const priorities = await import_client.connectWiseApiRequest.call(context, "GET", "/service/priorities", {}, {
53
- pageSize: 1e3,
54
- fields: "id,name",
55
- optionsCache: !0
56
- }), normalizedName = value.trim().toLowerCase(), priority = priorities.find(p => p.name.toLowerCase() === normalizedName);
57
- return priority ? {
58
- id: priority.id
59
- } : (console.warn(`⚠️ Priority "${value}" not found in API response`), null);
60
- } catch (error) {
61
- return console.error("Error fetching priorities:", error), null;
62
- }
63
- }
64
-
65
- function trimSummary(summary) {
66
- if (summary.length <= 100) return summary;
67
- let trimmed = summary.substring(0, 97).trim();
68
- return trimmed.endsWith(".") ? trimmed : trimmed + "...";
69
- }
70
-
71
- function formatTimestamp(date = /* @__PURE__ */ new Date) {
72
- return `\`${import_luxon.DateTime.fromJSDate(date).toFormat("yyyy-MM-dd ccc hh:mm:ss a")}\``;
73
- }
74
-
75
- function formatMacForSearch(mac) {
76
- if (!mac) return "";
77
- if (mac.includes("*")) return mac.replace(/[:\-\.\s]/g, "");
78
- const cleanMac = mac.replace(/[:\-\.\s]/g, "").toUpperCase();
79
- return cleanMac.length < 6 ? cleanMac : (cleanMac.match(/.{1,2}/g) || []).join("%");
80
- }
81
-
82
- async function findConfiguration(companyId, configurationTypeId, macAddress, ipAddress, hostnameFull, hostnameSearch) {
83
- try {
84
- const orConditions = [];
85
- if (macAddress) {
86
- const macSearchPattern = formatMacForSearch(macAddress);
87
- orConditions.push(`macAddress like "%${macSearchPattern}%"`);
88
- }
89
- if (ipAddress && orConditions.push(`ipAddress="${ipAddress}"`), hostnameFull) if (hostnameFull.includes("*")) {
90
- const hostnamePattern = hostnameFull.replace(/\*/g, "%");
91
- orConditions.push(`name like "${hostnamePattern}"`);
92
- } else orConditions.push(`name="${hostnameFull}"`);
93
- if (hostnameSearch && orConditions.push(`name="${hostnameSearch}"`, `name like "${hostnameSearch}.%"`),
94
- orConditions.length === 0) return console.log("⚠️ No configuration search criteria provided"),
95
- null;
96
- const fullCondition = [ `company/id=${companyId}`, "activeFlag=true", configurationTypeId ? Array.isArray(configurationTypeId) ? configurationTypeId.length > 0 ? `type/id in (${configurationTypeId.join(",")})` : null : `type/id=${configurationTypeId}` : null, `(${orConditions.join(" or ")})` ].filter(Boolean).join(" and ");
97
- console.log(`🔍 Searching configurations with condition: ${fullCondition}`);
98
- const configs = await import_client.connectWiseApiRequest.call(this, "GET", "/company/configurations", {}, {
99
- conditions: fullCondition,
100
- pageSize: 100,
101
- orderBy: "id desc",
102
- fields: "id,name,ipAddress,macAddress,serialNumber,modelNumber,tagNumber,notes"
103
- });
104
- if (!configs || configs.length === 0) return console.log("⚠️ No configuration found matching the provided identifiers"),
105
- null;
106
- if (console.log(`📊 Found ${configs.length} matching configuration(s), applying priority filter...`),
107
- macAddress) {
108
- const macPattern = formatMacForSearch(macAddress).toLowerCase();
109
- for (const config of configs) if (config.macAddress) {
110
- const configMac = config.macAddress.replace(/[:\-\.\s]/g, "").toLowerCase();
111
- if (new RegExp(macPattern.replace(/\*/g, ".*"), "i").test(configMac)) return console.log(`✅ Configuration found by MAC address: ${config.name} (MAC: ${config.macAddress})`),
112
- config;
113
- }
114
- }
115
- if (ipAddress) {
116
- if (ipAddress === "127.0.0.1") console.log("❗ Ignoring IP address 127.0.0.1 (localhost)"); else for (const config of configs) if (config.ipAddress === ipAddress) return console.log(`✅ Configuration found by IP address: ${config.name} (IP: ${config.ipAddress})`),
117
- config;
118
- }
119
- if (hostnameFull && !hostnameFull.includes("*")) {
120
- for (const config of configs) if (config.name && config.name.toLowerCase() === hostnameFull.toLowerCase()) return console.log(`✅ Configuration found by exact hostname: ${config.name}`),
121
- config;
122
- }
123
- if (hostnameFull && hostnameFull.includes("*")) {
124
- const pattern = new RegExp("^" + hostnameFull.replace(/\*/g, ".*") + "$", "i");
125
- for (const config of configs) if (config.name && pattern.test(config.name)) return console.log(`✅ Configuration found by hostname pattern: ${config.name}`),
126
- config;
127
- }
128
- if (hostnameSearch) {
129
- for (const config of configs) if (config.name && config.name.toLowerCase() === hostnameSearch.toLowerCase()) return console.log(`✅ Configuration found by smart hostname (exact): ${config.name}`),
130
- config;
131
- for (const config of configs) if (config.name && config.name.toLowerCase().startsWith(hostnameSearch.toLowerCase())) return console.log(`✅ Configuration found by smart hostname (prefix): ${config.name}`),
132
- config;
133
- }
134
- console.log("⚠️ No configurations matched priority filters. Found configurations:");
135
- for (const config of configs) console.log(` - ${config.name} (ID: ${config.id}, IP: ${config.ipAddress || "N/A"}, MAC: ${config.macAddress || "N/A"})`);
136
- return null;
137
- } catch (error) {
138
- return console.error("Error searching for configuration:", error), null;
139
- }
140
- }
141
-
142
- async function analyzeTicketNotes(ticketId, maxComments) {
143
- const fetchLimit = Math.max(10, maxComments), notes = await import_client.connectWiseApiRequest.call(this, "GET", `/service/tickets/${ticketId}/notes`, {}, {
144
- orderBy: "id desc",
145
- pageSize: fetchLimit
146
- }), atMaxComments = notes.length >= maxComments;
147
- let lastFingerprintedNote = null, lastFingerprintedNoteType = null, hasFailureFingerprint = !1, hasSuccessFingerprint = !1, successCount = 0, failureCount = 0;
148
- for (const note of notes) {
149
- const text = note.text || "";
150
- text.includes("\x3c!--msp-copilot:failure") && (hasFailureFingerprint = !0, failureCount++,
151
- lastFingerprintedNote || (lastFingerprintedNote = note, lastFingerprintedNoteType = "failure")),
152
- text.includes("\x3c!--msp-copilot:success") && (hasSuccessFingerprint = !0, successCount++,
153
- lastFingerprintedNote || (lastFingerprintedNote = note, lastFingerprintedNoteType = "success")),
154
- !lastFingerprintedNote && text.includes("\x3c!--msp-copilot--\x3e") && (lastFingerprintedNote = note,
155
- lastFingerprintedNoteType = "failure");
156
- }
157
- return {
158
- atMaxComments: atMaxComments,
159
- lastNote: notes[0] || null,
160
- lastFingerprintedNote: lastFingerprintedNote,
161
- lastFingerprintedNoteType: lastFingerprintedNoteType,
162
- hasFailureFingerprint: hasFailureFingerprint,
163
- hasSuccessFingerprint: hasSuccessFingerprint,
164
- successCount: successCount,
165
- failureCount: failureCount,
166
- isLastNoteFingerprinted: notes[0] === lastFingerprintedNote
167
- };
168
- }
169
-
170
- async function searchExistingTicket(searchKey, companyId, boardId, success, options) {
171
- try {
172
- const conditions = [ `company/id=${companyId}`, `externalXRef="${searchKey}"` ];
173
- if (success) {
174
- if (conditions.push("closedFlag=false", 'slaStatus!="Resolved"'), options.successStatus) {
175
- const statusObj = buildStatus(options.successStatus);
176
- "id" in statusObj ? conditions.push(`status/id!=${statusObj.id}`) : conditions.push(`status/name!="${statusObj.name}"`);
177
- }
178
- } else if (options.reopenSameBoardOnly && conditions.push(`board/id=${boardId}`),
179
- options.reopenClosedTicket) {
180
- const ageConditions = [];
181
- if (options.reopenTicketMaxAge) {
182
- const maxAge = (0, import_utils.parseDuration)(options.reopenTicketMaxAge);
183
- if (maxAge > 0) {
184
- const cutoffDate = new Date(Date.now() - maxAge).toISOString();
185
- ageConditions.push(`_info/dateEntered>=[${cutoffDate}]`);
186
- }
187
- }
188
- if (options.reopenTicketLastUpdateAge) {
189
- const maxUpdateAge = (0, import_utils.parseDuration)(options.reopenTicketLastUpdateAge);
190
- if (maxUpdateAge > 0) {
191
- const cutoffDate = new Date(Date.now() - maxUpdateAge).toISOString();
192
- ageConditions.push(`_info/lastUpdated>=[${cutoffDate}]`);
193
- }
194
- }
195
- ageConditions.length > 0 && conditions.push(`(closedFlag=false or (closedFlag=true and ${ageConditions.join(" and ")}))`);
196
- } else conditions.push("closedFlag=false");
197
- const tickets = await import_client.connectWiseApiRequest.call(this, "GET", "/service/tickets", {}, {
198
- conditions: conditions.join(" and "),
199
- orderBy: "id desc",
200
- pageSize: 1
201
- });
202
- return tickets && tickets.length > 0 ? tickets[0] : null;
203
- } catch (error) {
204
- return console.error("Error searching for ticket:", error), null;
205
- }
206
- }
207
-
208
- async function createTicket(data) {
209
- console.log(`📝 Creating new ticket with summary: ${data.summary}`);
210
- const response = await import_client.connectWiseApiRequest.call(this, "POST", "/service/tickets", data);
211
- return console.log(`✅ Created ticket #${response.id}`), response;
212
- }
213
-
214
- async function updateTicketStatus(ticketId, statusValue) {
215
- const statusObj = buildStatus(statusValue), path = "id" in statusObj ? "status/id" : "status/name", value = "id" in statusObj ? statusObj.id : statusObj.name;
216
- try {
217
- return await import_client.connectWiseApiRequest.call(this, "PATCH", `/service/tickets/${ticketId}`, [ {
218
- op: "replace",
219
- path: path,
220
- value: value
221
- } ]);
222
- } catch (error) {
223
- if (error.message && error.message.includes("ticket object is invalid") && /Status .* not found/.test(error.message)) return console.log(`⚠️ Status ${value} not valid for ticket #${ticketId}'s current board, skipping status update`),
224
- !1;
225
- throw error;
226
- }
227
- }
228
-
229
- async function createTicketNote(ticketId, text, internalNote) {
230
- console.log(`📝 Creating note on ticket #${ticketId}`), await import_client.connectWiseApiRequest.call(this, "POST", `/service/tickets/${ticketId}/notes`, {
231
- text: text,
232
- internalAnalysisFlag: internalNote,
233
- detailDescriptionFlag: !internalNote,
234
- processNotifications: !1
235
- });
236
- }
237
-
238
- async function updateTicketNote(ticketId, noteId, text) {
239
- console.log(`📝 Updating note #${noteId} on ticket #${ticketId}`), await import_client.connectWiseApiRequest.call(this, "PATCH", `/service/tickets/${ticketId}/notes/${noteId}`, [ {
240
- op: "replace",
241
- path: "text",
242
- value: text
243
- } ]);
244
- }
245
-
246
- async function processSmartTicket(params) {
247
- const {companyId: companyId, alertName: alertName, alertId: alertId, alertSuccess: alertSuccess, boardId: boardId, failStatus: failStatus, successStatus: successStatus, reopenStatus: reopenStatus, priority: priority, summary: summary, failMessageDetailed: failMessageDetailed, successMessageDetailed: successMessageDetailed, failMessageShort: failMessageShort, successMessageShort: successMessageShort, internalNote: internalNote = !1, reopenClosedTicket: reopenClosedTicket = !1, reopenSameBoardOnly: reopenSameBoardOnly = !0, reopenTicketMaxAge: reopenTicketMaxAge, reopenTicketLastUpdateAge: reopenTicketLastUpdateAge, maxComments: maxComments = 20, appendPreviousNote: appendPreviousNote = !1, appendPreviousNoteTimeframe: appendPreviousNoteTimeframe, appendPreviousNoteOnlyIfLastNote: appendPreviousNoteOnlyIfLastNote = !0, prependToNote: prependToNote = !0, configurationTypeId: configurationTypeId, macAddress: macAddress, ipAddress: ipAddress, hostnameFull: hostnameFull, hostnameSearch: hostnameSearch, skipIfNoConfiguration: skipIfNoConfiguration = !1, appendConfigurationDetails: appendConfigurationDetails = !1, previewMode: previewMode = !1} = params, messageShort = alertSuccess ? successMessageShort : failMessageShort, messageDetailed = alertSuccess ? successMessageDetailed : failMessageDetailed, initialMessage = messageDetailed || messageShort || (alertSuccess ? "Alert success" : "Alert failure"), searchKey = `${alertName}|${alertId}`;
248
- let noteMessageType, notePhase, fingerprintType = "";
249
- const existingTicket = await searchExistingTicket.call(this, searchKey, companyId, boardId, alertSuccess, {
250
- reopenClosedTicket: reopenClosedTicket,
251
- reopenSameBoardOnly: reopenSameBoardOnly,
252
- reopenTicketMaxAge: reopenTicketMaxAge,
253
- reopenTicketLastUpdateAge: reopenTicketLastUpdateAge,
254
- successStatus: successStatus,
255
- failStatus: failStatus
256
- });
257
- let action, ticket = null, ticketId = null, noteAction, notePreview, configuration = null;
258
- if (!existingTicket && alertSuccess) return action = "NO_TICKET_TO_RESOLVE", {
259
- action: action,
260
- ticket: null,
261
- ticketId: null,
262
- previewMode: previewMode,
263
- noteAction: void 0,
264
- notePreview: void 0,
265
- noteMessageType: noteMessageType,
266
- notePhase: notePhase
267
- };
268
- if (!existingTicket && !alertSuccess) {
269
- if (action = "CREATE_TICKET", (macAddress || ipAddress || hostnameFull || hostnameSearch) && (configuration = await findConfiguration.call(this, companyId, configurationTypeId, macAddress, ipAddress, hostnameFull, hostnameSearch),
270
- skipIfNoConfiguration && !configuration)) return action = "SKIP_NO_CONFIGURATION",
271
- {
272
- action: action,
273
- ticket: null,
274
- ticketId: null,
275
- previewMode: previewMode,
276
- reason: "No matching configuration found and skipIfNoConfiguration is enabled",
277
- noteAction: void 0,
278
- notePreview: void 0,
279
- noteMessageType: noteMessageType,
280
- notePhase: notePhase
281
- };
282
- let ticketDescription = initialMessage;
283
- if (appendPreviousNote && !alertSuccess && (ticketDescription += FINGERPRINT_FAILURE),
284
- appendConfigurationDetails && configuration) {
285
- let configDetails = "";
286
- const hardwareDetails = [];
287
- configuration.serialNumber && hardwareDetails.push(`*Serial Number:* ${configuration.serialNumber}`),
288
- configuration.modelNumber && hardwareDetails.push(`*Model Number:* ${configuration.modelNumber}`),
289
- configuration.tagNumber && hardwareDetails.push(`*Tag:* ${configuration.tagNumber}`),
290
- hardwareDetails.length > 0 && (configDetails += `\n` + hardwareDetails.join(`\n`)),
291
- configuration.notes && (configDetails += `\nNotes: ${configuration.notes}`), ticketDescription += configDetails;
292
- }
293
- const resolvedPriority = await resolvePriority(this, priority), newTicketData = {
294
- company: {
295
- id: companyId
296
- },
297
- board: {
298
- id: boardId
299
- },
300
- summary: summary,
301
- status: buildStatus(failStatus),
302
- initialDescription: ticketDescription,
303
- externalXRef: searchKey
304
- };
305
- if (resolvedPriority ? newTicketData.priority = resolvedPriority : priority && console.warn(`⚠️ Priority "${priority}" could not be resolved, ticket will be created without priority`),
306
- previewMode) ticket = {
307
- id: null,
308
- ...newTicketData
309
- }, ticketId = ticket.id; else if (ticket = await createTicket.call(this, newTicketData),
310
- ticketId = ticket.id, configuration && ticketId) try {
311
- await import_client.connectWiseApiRequest.call(this, "POST", `/service/tickets/${ticketId}/configurations`, {
312
- id: configuration.id
313
- });
314
- } catch (error) {
315
- console.error(`Warning: Could not attach configuration to ticket #${ticketId}:`, error.message);
316
- }
317
- } else if (existingTicket) {
318
- if (ticket = existingTicket, ticketId = ticket.id, existingTicket.closedFlag && !alertSuccess && reopenClosedTicket) {
319
- if (action = "REOPEN_TICKET", !previewMode && ticketId) {
320
- const statusForReopen = reopenStatus && reopenStatus !== "" ? reopenStatus : failStatus, updatedTicket = await updateTicketStatus.call(this, ticketId, statusForReopen);
321
- updatedTicket !== !1 ? ticket = updatedTicket : action = "REOPEN_TICKET_STATUS_ERROR";
322
- }
323
- } else if (alertSuccess && !existingTicket.closedFlag) {
324
- if (action = "CLOSE_TICKET", !previewMode && ticketId) {
325
- const updatedTicket = await updateTicketStatus.call(this, ticketId, successStatus);
326
- updatedTicket !== !1 ? ticket = updatedTicket : action = "CLOSE_TICKET_STATUS_ERROR";
327
- }
328
- } else if (!alertSuccess && !existingTicket.closedFlag) {
329
- if (action = "UPDATE_TICKET_STATUS", !previewMode && ticketId) {
330
- const statusForUpdate = reopenStatus && reopenStatus !== "" ? reopenStatus : failStatus, updatedTicket = await updateTicketStatus.call(this, ticketId, statusForUpdate);
331
- updatedTicket !== !1 ? ticket = updatedTicket : action = "UPDATE_TICKET_STATUS_ERROR";
332
- }
333
- } else action = "NO_STATUS_UPDATE";
334
- if (ticketId) {
335
- const noteAnalysis = await analyzeTicketNotes.call(this, ticketId, maxComments), isPostFirstSuccess = noteAnalysis.hasSuccessFingerprint;
336
- let shouldAppendToPrevious = !1;
337
- if (appendPreviousNote && noteAnalysis.lastFingerprintedNote) {
338
- let canAppend = !0;
339
- if (canAppend && appendPreviousNoteOnlyIfLastNote && !noteAnalysis.isLastNoteFingerprinted && (canAppend = !1),
340
- canAppend && appendPreviousNoteTimeframe) {
341
- const timeframeMs = (0, import_utils.parseDuration)(appendPreviousNoteTimeframe);
342
- if (timeframeMs > 0) {
343
- const noteDate = new Date(noteAnalysis.lastFingerprintedNote._info?.lastUpdated || noteAnalysis.lastFingerprintedNote.dateCreated);
344
- Date.now() - noteDate.getTime() > timeframeMs && (console.log(`📅 Note is too old to append to (note date: ${noteDate.toISOString()}, timeframe: ${appendPreviousNoteTimeframe})`),
345
- canAppend = !1);
346
- }
347
- }
348
- shouldAppendToPrevious = canAppend;
349
- }
350
- let noteContent, addFingerprint = !1;
351
- if (noteMessageType = "fallback", notePhase = "consolidation", !isPostFirstSuccess && !alertSuccess ? (noteContent = messageShort || messageDetailed || "Alert failure",
352
- noteMessageType = messageShort ? "short" : messageDetailed ? "detailed" : "fallback",
353
- notePhase = "pre-first-success", shouldAppendToPrevious || (addFingerprint = !0,
354
- fingerprintType = FINGERPRINT_FAILURE)) : alertSuccess && noteAnalysis.successCount === 0 ? (noteContent = messageDetailed || messageShort || "Alert success",
355
- noteMessageType = messageDetailed ? "detailed" : messageShort ? "short" : "fallback",
356
- notePhase = "first-success", shouldAppendToPrevious = !1, addFingerprint = !0, fingerprintType = FINGERPRINT_SUCCESS) : !alertSuccess && noteAnalysis.lastFingerprintedNoteType === "success" ? (noteContent = messageShort || messageDetailed || "Alert failure",
357
- noteMessageType = messageShort ? "short" : messageDetailed ? "detailed" : "fallback",
358
- notePhase = "post-first-success", shouldAppendToPrevious = !1, addFingerprint = !0,
359
- fingerprintType = FINGERPRINT_FAILURE) : (noteContent = messageShort || messageDetailed || (alertSuccess ? "Alert success" : "Alert failure"),
360
- noteMessageType = messageShort ? "short" : messageDetailed ? "detailed" : "fallback",
361
- notePhase = "consolidation", shouldAppendToPrevious || (addFingerprint = !0, fingerprintType = alertSuccess ? FINGERPRINT_SUCCESS : FINGERPRINT_FAILURE)),
362
- shouldAppendToPrevious && noteAnalysis.lastFingerprintedNote) {
363
- noteAction = "APPEND_TO_PREVIOUS_NOTE";
364
- const cleanedContent = noteAnalysis.lastFingerprintedNote.text.replace(/\n<!--msp-copilot[^>]*-->/g, ""), existingIsDetailed = !cleanedContent.match(/^`\d{4}-\d{2}-\d{2}/), appendingDetailedMessage = noteMessageType === "detailed", separator = existingIsDetailed || appendingDetailedMessage ? `\n\n` : `\n`, timestampSeparator = appendingDetailedMessage ? `\n` : " ", newEntry = `${formatTimestamp()}${timestampSeparator}${noteContent}`, combinedContent = prependToNote ? `${newEntry}${separator}${cleanedContent}` : `${cleanedContent}${separator}${newEntry}`;
365
- if (notePreview = newEntry, !previewMode) {
366
- const originalFingerprint = noteAnalysis.lastFingerprintedNote.text.match(/\n<!--msp-copilot[^>]*-->/)?.[0] || FINGERPRINT;
367
- await updateTicketNote.call(this, ticketId, noteAnalysis.lastFingerprintedNote.id, combinedContent + originalFingerprint);
368
- }
369
- } else if (noteAnalysis.atMaxComments) {
370
- if (noteAction = "UPDATE_LAST_NOTE", noteAnalysis.lastNote) {
371
- const cleanedContent = noteAnalysis.lastNote.text.replace(/\n<!--msp-copilot[^>]*-->/g, ""), existingIsDetailed = !cleanedContent.match(/^`\d{4}-\d{2}-\d{2}/), appendingDetailedMessage = noteMessageType === "detailed", separator = existingIsDetailed || appendingDetailedMessage ? `\n\n` : `\n`, timestampSeparator = appendingDetailedMessage ? `\n` : " ", newEntry = `${formatTimestamp()}${timestampSeparator}${noteContent}`, combinedContent = prependToNote ? `${newEntry}${separator}${cleanedContent}` : `${cleanedContent}${separator}${newEntry}`;
372
- notePreview = newEntry, previewMode || await updateTicketNote.call(this, ticketId, noteAnalysis.lastNote.id, combinedContent + fingerprintType);
373
- }
374
- } else {
375
- noteAction = "CREATE_NOTE";
376
- const isFirstSuccess = notePhase === "first-success", timestampSeparator = !isFirstSuccess && noteMessageType === "detailed" ? `\n` : " ", newEntry = isFirstSuccess ? noteContent : `${formatTimestamp()}${timestampSeparator}${noteContent}`;
377
- if (notePreview = newEntry, !previewMode) {
378
- const finalNoteText = addFingerprint ? newEntry + fingerprintType : newEntry;
379
- await createTicketNote.call(this, ticketId, finalNoteText, internalNote);
380
- }
381
- }
382
- }
383
- }
384
- return {
385
- action: action,
386
- noteAction: noteAction,
387
- notePreview: notePreview,
388
- noteMessageType: noteMessageType,
389
- notePhase: notePhase,
390
- ticketId: ticketId,
391
- previewMode: previewMode,
392
- ticket: ticket,
393
- configuration: configuration || void 0
394
- };
395
- }
396
-
397
- const executeSmartConsolidationPro = async function(itemIndex) {
398
- try {
399
- const companyId = this.getNodeParameter("company", itemIndex), alertName = this.getNodeParameter("alertName", itemIndex).trim().substring(0, 40), alertIdRaw = this.getNodeParameter("alertId", itemIndex).trim(), alertId = alertIdRaw.length <= 50 ? alertIdRaw : (0,
400
- import_crypto.createHash)("md5").update(alertIdRaw).digest("hex"), alertSuccess = this.getNodeParameter("alertSuccess", itemIndex), boardId = this.getNodeParameter("board", itemIndex), failStatus = this.getNodeParameter("failStatus", itemIndex), successStatus = this.getNodeParameter("successStatus", itemIndex), priority = this.getNodeParameter("priority", itemIndex), summary = trimSummary(this.getNodeParameter("summary", itemIndex)), failMessageDetailed = this.getNodeParameter("failMessageDetailed", itemIndex, ""), successMessageDetailed = this.getNodeParameter("successMessageDetailed", itemIndex, ""), failMessageShort = this.getNodeParameter("failMessageShort", itemIndex, ""), successMessageShort = this.getNodeParameter("successMessageShort", itemIndex, ""), internalNote = this.getNodeParameter("internalNote", itemIndex, !1), reopenClosedTicket = this.getNodeParameter("reopenClosedTicket", itemIndex, !1), reopenSameBoardOnly = this.getNodeParameter("reopenSameBoardOnly", itemIndex, !0), reopenStatus = this.getNodeParameter("reopenStatus", itemIndex, ""), reopenTicketMaxAge = this.getNodeParameter("reopenTicketMaxAge", itemIndex, ""), reopenTicketLastUpdateAge = this.getNodeParameter("reopenTicketLastUpdateAge", itemIndex, ""), maxComments = this.getNodeParameter("maxComments", itemIndex, 20), appendPreviousNote = this.getNodeParameter("appendPreviousNote", itemIndex, !1), appendPreviousNoteTimeframe = this.getNodeParameter("appendPreviousNoteTimeframe", itemIndex, ""), appendPreviousNoteOnlyIfLastNote = this.getNodeParameter("appendPreviousNoteOnlyIfLastNote", itemIndex, !0), prependToNote = this.getNodeParameter("prependToNote", itemIndex, !0), configAttachment = this.getNodeParameter("configAttachment", itemIndex, {}), configurationTypeId = configAttachment.configurationTypeId, macAddress = configAttachment.macAddress, ipAddress = configAttachment.ipAddress, hostnameFull = configAttachment.hostnameFull, hostnameSearch = configAttachment.hostnameSearch, skipIfNoConfiguration = configAttachment.skipIfNoConfiguration, appendConfigurationDetails = configAttachment.appendConfigurationDetails, previewMode = this.getNodeParameter("previewMode", itemIndex, !1), params = {
401
- companyId: companyId,
402
- alertName: alertName,
403
- alertId: alertId,
404
- alertSuccess: alertSuccess,
405
- boardId: boardId,
406
- failStatus: failStatus,
407
- successStatus: successStatus,
408
- reopenStatus: reopenStatus,
409
- priority: priority,
410
- summary: summary,
411
- failMessageDetailed: failMessageDetailed,
412
- successMessageDetailed: successMessageDetailed,
413
- failMessageShort: failMessageShort,
414
- successMessageShort: successMessageShort,
415
- internalNote: internalNote,
416
- reopenClosedTicket: reopenClosedTicket,
417
- reopenSameBoardOnly: reopenSameBoardOnly,
418
- reopenTicketMaxAge: reopenTicketMaxAge,
419
- reopenTicketLastUpdateAge: reopenTicketLastUpdateAge,
420
- maxComments: maxComments,
421
- appendPreviousNote: appendPreviousNote,
422
- appendPreviousNoteTimeframe: appendPreviousNoteTimeframe,
423
- appendPreviousNoteOnlyIfLastNote: appendPreviousNoteOnlyIfLastNote,
424
- prependToNote: prependToNote,
425
- configurationTypeId: configurationTypeId,
426
- macAddress: macAddress,
427
- ipAddress: ipAddress,
428
- hostnameFull: hostnameFull,
429
- hostnameSearch: hostnameSearch,
430
- skipIfNoConfiguration: skipIfNoConfiguration,
431
- appendConfigurationDetails: appendConfigurationDetails,
432
- previewMode: previewMode
433
- };
434
- return [ {
435
- json: await processSmartTicket.call(this, params),
436
- pairedItem: {
437
- item: itemIndex
438
- }
439
- } ];
440
- } catch (error) {
441
- throw new import_n8n_workflow.NodeOperationError(this.getNode(), `Smart Alert Consolidation failed: ${error.message}`, {
442
- description: error.description
443
- });
444
- }
445
- }, executeSmartConsolidationStub = async function(itemIndex) {
446
- return (0, import_utils.returnProOnlyMessage)(this, itemIndex);
447
- }, executeSmartConsolidation = process.env.MSPCOPILOT_BETA === "true" ? executeSmartConsolidationPro : executeSmartConsolidationStub;
448
-
449
- 0 && (module.exports = {
450
- executeSmartConsolidation: executeSmartConsolidation
451
- });
@@ -1,103 +0,0 @@
1
- var __create = Object.create;
2
-
3
- var __defProp = Object.defineProperty;
4
-
5
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
-
7
- var __getOwnPropNames = Object.getOwnPropertyNames;
8
-
9
- var __getProtoOf = Object.getPrototypeOf, __hasOwnProp = Object.prototype.hasOwnProperty;
10
-
11
- var __export = (target, all) => {
12
- for (var name in all) __defProp(target, name, {
13
- get: all[name],
14
- enumerable: !0
15
- });
16
- }, __copyProps = (to, from, except, desc) => {
17
- if (from && typeof from == "object" || typeof from == "function") for (let key of __getOwnPropNames(from)) !__hasOwnProp.call(to, key) && key !== except && __defProp(to, key, {
18
- get: () => from[key],
19
- enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
20
- });
21
- return to;
22
- };
23
-
24
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {},
25
- __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
26
- value: mod,
27
- enumerable: !0
28
- }) : target, mod)), __toCommonJS = mod => __copyProps(__defProp({}, "__esModule", {
29
- value: !0
30
- }), mod);
31
-
32
- var diagnostics_schema_exports = {};
33
-
34
- __export(diagnostics_schema_exports, {
35
- diagnosticsSchema: () => diagnosticsSchema,
36
- execute: () => execute
37
- });
38
-
39
- module.exports = __toCommonJS(diagnostics_schema_exports);
40
-
41
- var import_hint_collector = require("../../helpers/hint-collector");
42
-
43
- const diagnosticsFields = [ {
44
- displayName: "Operation",
45
- name: "operation",
46
- type: "options",
47
- noDataExpression: !0,
48
- displayOptions: {
49
- show: {
50
- resource: [ "diagnostics" ]
51
- }
52
- },
53
- options: [ {
54
- name: "Clear Cache",
55
- value: "clearCache",
56
- description: "Clear all cached ConnectWise PSA data",
57
- action: "Clear all cache entries"
58
- } ],
59
- default: "clearCache"
60
- } ], diagnosticsSchema = {
61
- resource: "diagnostics",
62
- displayName: "Diagnostics",
63
- description: "Diagnostic and maintenance operations",
64
- endpoints: {},
65
- fields: diagnosticsFields
66
- };
67
-
68
- async function execute(operation, i) {
69
- if (operation === "clearCache") try {
70
- const {clearAllCached: clearAllCached} = await import("../../transport/cache.js"), clearedCount = await clearAllCached(), result = {
71
- success: !0,
72
- clearedCount: clearedCount,
73
- message: `Cleared ${clearedCount} cache entries`
74
- };
75
- return (0, import_hint_collector.hint)(this, "custom", `Cache cleared: ${clearedCount} entries removed`),
76
- this.helpers.constructExecutionMetaData(this.helpers.returnJsonArray(result), {
77
- itemData: {
78
- item: i
79
- }
80
- });
81
- } catch (error) {
82
- const originalError = error.message || "Unknown error occurred";
83
- let friendlyMessage;
84
- originalError.includes("isn't writeable") || originalError.includes("ECONNREFUSED") || originalError.includes("Connection is closed") || originalError.includes("Redis cache is not available") ? friendlyMessage = "Redis cache server is not running or not accessible. Please start Redis and ensure it is configured correctly (check QUEUE_BULL_REDIS_HOST and QUEUE_BULL_REDIS_PORT environment variables)." : originalError.includes("only available in the pro version") ? friendlyMessage = "Cache clearing requires the pro version of this node." : friendlyMessage = "Failed to clear cache. Please check the error details and your Redis configuration.";
85
- const result = {
86
- success: !1,
87
- clearedCount: 0,
88
- error: originalError,
89
- message: friendlyMessage
90
- };
91
- return (0, import_hint_collector.hint)(this, "custom", friendlyMessage), this.helpers.constructExecutionMetaData(this.helpers.returnJsonArray(result), {
92
- itemData: {
93
- item: i
94
- }
95
- });
96
- }
97
- throw new Error(`Unsupported operation: ${operation}`);
98
- }
99
-
100
- 0 && (module.exports = {
101
- diagnosticsSchema: diagnosticsSchema,
102
- execute: execute
103
- });