@mspcopilot/n8n-nodes-connectwise 0.2.4-beta.1 → 0.3.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/{dist-beta → dist-community}/credentials/ConnectWisePsaApi.credentials.js +3 -17
- package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/ConnectWisePsa.node.js +2 -14
- package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/ConnectWisePsaTrigger.node.js +3 -3
- package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/descriptions/common.properties.js +1 -16
- package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/helpers/field-collector.js +10 -1
- package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/helpers/hint-collector.js +1 -1
- package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/methods/fieldOptions.js +0 -1
- package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/resources/alert-consolidation.js +1 -3
- package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/resources/custom.schema.js +1 -38
- package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/resources/ticket.schema.js +1 -11
- package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/resources/timeEntry.schema.js +7 -0
- package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/transport/cache.js +6 -84
- package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/transport/client.js +5 -46
- package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/transport/version-check.js +13 -9
- package/package.json +5 -6
- package/dist-beta/nodes/ConnectWise/PSA/IfSchedule.node.js +0 -333
- package/dist-beta/nodes/ConnectWise/PSA/schema/resources/diagnostics.schema.js +0 -103
- package/dist-beta/nodes/ConnectWise/PSA/schema/resources/reports.schema.js +0 -216
- /package/{dist-beta → dist-community}/LICENSE.md +0 -0
- /package/{dist-beta → dist-community}/credentials/connectwise-dark.svg +0 -0
- /package/{dist-beta → dist-community}/credentials/connectwise-light.svg +0 -0
- /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/connectwise-dark.svg +0 -0
- /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/connectwise-light.svg +0 -0
- /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/descriptions/common.descriptions.js +0 -0
- /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/descriptions/index.js +0 -0
- /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/helpers/customFields.js +0 -0
- /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/helpers/field-conditions.js +0 -0
- /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/helpers/index.js +0 -0
- /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/helpers/logging.js +0 -0
- /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/helpers/utils.js +0 -0
- /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/methods/generated.js +0 -0
- /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/methods/index.js +0 -0
- /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/converter/index.js +0 -0
- /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/converter/reference.generator.js +0 -0
- /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/index.js +0 -0
- /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/references.js +0 -0
- /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/reports-descriptions.js +0 -0
- /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/resources/activity.schema.js +0 -0
- /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/resources/company.schema.js +0 -0
- /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/resources/contact.schema.js +0 -0
- /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/resources/index.js +0 -0
- /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/resources/members.schema.js +0 -0
- /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/resources/ticketNote.schema.js +0 -0
- /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/resources/ticketTask.schema.js +0 -0
- /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/static-fields.js +0 -0
- /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/transformer.js +0 -0
- /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/types/index.js +0 -0
- /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/types/reference.types.js +0 -0
- /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/types/resource.types.js +0 -0
- /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/transport/access-key.js +0 -0
- /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/transport/index.js +0 -0
- /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/transport/operations.js +0 -0
- /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/transport/response-transformer.js +0 -0
- /package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/types/n8n-augmentation.d.js +0 -0
- /package/{dist-beta → dist-community}/nodes/ConnectWisePsa.node.json +0 -0
|
@@ -112,28 +112,14 @@ class ConnectWisePsaApi {
|
|
|
112
112
|
placeholder: import_transport.DEFAULT_API_PATH,
|
|
113
113
|
hint: `Leave blank to use the default API path (${import_transport.DEFAULT_API_PATH})`,
|
|
114
114
|
description: "Custom API version path. Leave empty to use the default."
|
|
115
|
-
},
|
|
115
|
+
}, {
|
|
116
116
|
displayName: "Check for Updates",
|
|
117
117
|
name: "checkForUpdates",
|
|
118
118
|
type: "boolean",
|
|
119
119
|
default: !0,
|
|
120
|
-
hint: "Current version: 0.
|
|
120
|
+
hint: "Current version: 0.3.0 (community edition)",
|
|
121
121
|
description: "Check for new versions of this node package and show notifications when updates are available"
|
|
122
|
-
} ]
|
|
123
|
-
displayName: "Current version: 0.2.4-beta.1 (beta)",
|
|
124
|
-
name: "versionInfo",
|
|
125
|
-
type: "notice",
|
|
126
|
-
default: ""
|
|
127
|
-
} ] : [], ...process.env.MSPCOPILOT_BETA === "true" ? [ {
|
|
128
|
-
displayName: "Access Key",
|
|
129
|
-
name: "accessKey",
|
|
130
|
-
type: "string",
|
|
131
|
-
typeOptions: {
|
|
132
|
-
password: !0
|
|
133
|
-
},
|
|
134
|
-
default: "",
|
|
135
|
-
hint: "To enable beta or server-side features"
|
|
136
|
-
} ] : [] ];
|
|
122
|
+
} ];
|
|
137
123
|
async authenticate(credentials, requestOptions) {
|
|
138
124
|
const serverUrl = credentials.site === "custom" ? credentials.customServer : credentials.site, base64Auth = Buffer.from(`${credentials.companyId}+${credentials.publicKey}:${credentials.privateKey}`).toString("base64");
|
|
139
125
|
return requestOptions.baseURL || (requestOptions.baseURL = `https://${serverUrl}`),
|
|
@@ -46,20 +46,10 @@ const resources = {
|
|
|
46
46
|
schema: import_contact.contactSchema,
|
|
47
47
|
execute: import_contact.execute
|
|
48
48
|
},
|
|
49
|
-
...process.env.MSPCOPILOT_BETA === "true" ? {
|
|
50
|
-
diagnostics: {
|
|
51
|
-
schema: require("./schema/resources/diagnostics.schema").diagnosticsSchema,
|
|
52
|
-
execute: require("./schema/resources/diagnostics.schema").execute
|
|
53
|
-
}
|
|
54
|
-
} : {},
|
|
55
49
|
members: {
|
|
56
50
|
schema: import_members.membersSchema,
|
|
57
51
|
execute: import_members.execute
|
|
58
52
|
},
|
|
59
|
-
reports: {
|
|
60
|
-
schema: require("./schema/resources/reports.schema").reportsSchema,
|
|
61
|
-
execute: require("./schema/resources/reports.schema").execute
|
|
62
|
-
},
|
|
63
53
|
ticket: {
|
|
64
54
|
schema: import_ticket.ticketSchema,
|
|
65
55
|
execute: import_ticket.execute
|
|
@@ -76,7 +66,6 @@ const resources = {
|
|
|
76
66
|
schema: import_timeEntry.timeEntrySchema,
|
|
77
67
|
execute: import_timeEntry.execute
|
|
78
68
|
},
|
|
79
|
-
...process.env.MSPCOPILOT_BETA === "true" ? {} : {},
|
|
80
69
|
custom: {
|
|
81
70
|
schema: import_custom.customSchema,
|
|
82
71
|
execute: import_custom.execute
|
|
@@ -85,7 +74,7 @@ const resources = {
|
|
|
85
74
|
|
|
86
75
|
class ConnectWisePsa {
|
|
87
76
|
constructor() {
|
|
88
|
-
console.log(`🔌 ConnectWise PSA Node Loaded | 📦 v0.
|
|
77
|
+
console.log(`🔌 ConnectWise PSA Node Loaded | 📦 v0.3.0 | 🏗️ Build: ${"community".toUpperCase()} (${"prod".toUpperCase()} mode)`);
|
|
89
78
|
}
|
|
90
79
|
description={
|
|
91
80
|
displayName: "ConnectWise PSA",
|
|
@@ -163,8 +152,7 @@ class ConnectWisePsa {
|
|
|
163
152
|
...import_methods.loadOptions,
|
|
164
153
|
loadFieldsOptions: import_fieldOptions.loadFieldsOptions,
|
|
165
154
|
loadOrderByFieldsOptions: import_fieldOptions.loadOrderByFieldsOptions,
|
|
166
|
-
loadCustomFieldsOptions: import_fieldOptions.loadCustomFieldsOptions
|
|
167
|
-
loadReportColumns: require("./schema/resources/reports.schema").loadReportColumns
|
|
155
|
+
loadCustomFieldsOptions: import_fieldOptions.loadCustomFieldsOptions
|
|
168
156
|
},
|
|
169
157
|
listSearch: import_methods.listSearch
|
|
170
158
|
};
|
|
@@ -60,7 +60,7 @@ function formatWebhookError(error) {
|
|
|
60
60
|
|
|
61
61
|
async function notifyWebhookAction(context, options) {
|
|
62
62
|
const {action: action, webhookUrl: webhookUrl, webhookId: webhookId, type: type, query: query, options: triggerOptions, isTest: isTest, metadata: metadata} = options, credentials = await context.getCredentials("connectWisePsaApi"), companyId = credentials.companyId, accessKey = credentials.accessKey;
|
|
63
|
-
if (!accessKey) throw new Error("Access Key is required
|
|
63
|
+
if (!accessKey) throw new Error("An Access Key is required to use this trigger. Get one at https://link.mspcopilot.io/settings?tab=support, then edit this node's ConnectWise PSA credentials in n8n and paste it into the Access Key field.");
|
|
64
64
|
await context.helpers.httpRequest({
|
|
65
65
|
method: "POST",
|
|
66
66
|
url: WEBHOOK_REGISTRY_URL,
|
|
@@ -108,7 +108,7 @@ function getFilterParameters(context) {
|
|
|
108
108
|
options.onCreate = triggerOn.includes("create"), options.onUpdate = triggerOn.includes("update"),
|
|
109
109
|
options.onDelete = triggerOn.includes("delete"), triggerOn.includes("repeat")) {
|
|
110
110
|
const repeatEvery = getParam("repeatEvery", "");
|
|
111
|
-
if (!repeatEvery) throw new
|
|
111
|
+
if (!repeatEvery) throw new import_n8n_workflow.NodeOperationError(context.getNode(), "Repeat Every is required when Repeat lifecycle event is selected");
|
|
112
112
|
options.repeatEvery = repeatEvery;
|
|
113
113
|
const maxRepeats = getParam("maxRepeats", "");
|
|
114
114
|
options.maxRepeats = maxRepeats !== "" && Number(maxRepeats) > 0 ? Number(maxRepeats) : 0;
|
|
@@ -118,7 +118,7 @@ function getFilterParameters(context) {
|
|
|
118
118
|
const rearm = getParam("rearm", "never");
|
|
119
119
|
if (options.rearm = rearm, rearm === "cooldown") {
|
|
120
120
|
const cooldown = getParam("cooldown", "");
|
|
121
|
-
if (!cooldown) throw new
|
|
121
|
+
if (!cooldown) throw new import_n8n_workflow.NodeOperationError(context.getNode(), "Cooldown Duration is required when rearm is set to Notify After Cooldown");
|
|
122
122
|
options.cooldown = cooldown;
|
|
123
123
|
}
|
|
124
124
|
return {
|
package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/descriptions/common.properties.js
RENAMED
|
@@ -336,22 +336,7 @@ function getCommonFields(options) {
|
|
|
336
336
|
operation: [ "getAll", "getReport" ]
|
|
337
337
|
}
|
|
338
338
|
}
|
|
339
|
-
}
|
|
340
|
-
...queryOptions.cacheResponse,
|
|
341
|
-
displayOptions: {
|
|
342
|
-
show: {
|
|
343
|
-
operation: [ "get", "getAll", "getReport" ]
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
}, {
|
|
347
|
-
...queryOptions.cacheDuration,
|
|
348
|
-
displayOptions: {
|
|
349
|
-
show: {
|
|
350
|
-
operation: [ "get", "getAll", "getReport" ],
|
|
351
|
-
cacheResponse: [ !0 ]
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
} ] : [] ];
|
|
339
|
+
} ];
|
|
355
340
|
return options?.only ? fields = fields.filter(f => options.only.includes(f.name)) : options?.exclude && (fields = fields.filter(f => !options.exclude.includes(f.name))),
|
|
356
341
|
options?.overrides && (fields = fields.map(field => options.overrides[field.name] ? {
|
|
357
342
|
...field,
|
|
@@ -31,6 +31,12 @@ __export(field_collector_exports, {
|
|
|
31
31
|
|
|
32
32
|
module.exports = __toCommonJS(field_collector_exports);
|
|
33
33
|
|
|
34
|
+
function isEmptyFixedCollection(value) {
|
|
35
|
+
if (!value || typeof value != "object" || Array.isArray(value)) return !1;
|
|
36
|
+
const entries = Object.entries(value);
|
|
37
|
+
return entries.length === 0 ? !0 : entries.every(([, v]) => Array.isArray(v) && v.length === 0);
|
|
38
|
+
}
|
|
39
|
+
|
|
34
40
|
function collectFieldData(context, schema, operation, index) {
|
|
35
41
|
const schemaFields = {}, additionalFields = {}, assignments = {}, relevantProperties = [], isPropertyShown = property => {
|
|
36
42
|
if (!property.displayOptions?.show?.operation) return !0;
|
|
@@ -40,7 +46,10 @@ function collectFieldData(context, schema, operation, index) {
|
|
|
40
46
|
const fullName = prefix + property.name;
|
|
41
47
|
try {
|
|
42
48
|
const value = context.getNodeParameter(fullName, index, void 0);
|
|
43
|
-
if (value != null && value !== "")
|
|
49
|
+
if (value != null && value !== "") {
|
|
50
|
+
if (property.type === "fixedCollection" && isEmptyFixedCollection(value)) return;
|
|
51
|
+
if (property.type === "collection" && typeof value == "object") for (const [collectionField, collectionValue] of Object.entries(value)) collectionValue != null && collectionValue !== "" && (target[`${fullName}.${collectionField}`] = collectionValue); else target[fullName] = value;
|
|
52
|
+
}
|
|
44
53
|
} catch {}
|
|
45
54
|
}, UI_CONTROL_FIELDS = [ "operation", "assignments", "endpoint", "ticketType", "parentId", "id" ];
|
|
46
55
|
for (const field of schema.fields) if (!UI_CONTROL_FIELDS.includes(field.name) && field.x_noSubmit !== !0 && isPropertyShown(field)) if (relevantProperties.push(field),
|
|
@@ -95,7 +95,7 @@ const HINT_TYPES = {
|
|
|
95
95
|
accesskey_missing: {
|
|
96
96
|
aggregate: "dedupe",
|
|
97
97
|
type: "warning",
|
|
98
|
-
template: () =>
|
|
98
|
+
template: () => `🔑 An access key is needed to use this feature. Get one at <a href="https://link.mspcopilot.io/settings?tab=support" target="_blank">link.mspcopilot.io</a>, then edit this node's ConnectWise PSA credentials and paste it into the Access Key field.`
|
|
99
99
|
},
|
|
100
100
|
accesskey_invalid: {
|
|
101
101
|
aggregate: "dedupe",
|
|
@@ -44,7 +44,6 @@ const resourceSchemas = {
|
|
|
44
44
|
ticketNote: import_ticketNote.ticketNoteSchema,
|
|
45
45
|
ticketTask: import_ticketTask.ticketTaskSchema,
|
|
46
46
|
timeEntry: import_timeEntry.timeEntrySchema,
|
|
47
|
-
reports: require("../schema/resources/reports.schema").reportsSchema,
|
|
48
47
|
custom: import_custom.customSchema
|
|
49
48
|
};
|
|
50
49
|
|
package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/resources/alert-consolidation.js
RENAMED
|
@@ -442,9 +442,7 @@ const executeSmartConsolidationPro = async function(itemIndex) {
|
|
|
442
442
|
description: error.description
|
|
443
443
|
});
|
|
444
444
|
}
|
|
445
|
-
},
|
|
446
|
-
return (0, import_utils.returnProOnlyMessage)(this, itemIndex);
|
|
447
|
-
}, executeSmartConsolidation = process.env.MSPCOPILOT_BETA === "true" ? executeSmartConsolidationPro : executeSmartConsolidationStub;
|
|
445
|
+
}, executeSmartConsolidation = executeSmartConsolidationPro;
|
|
448
446
|
|
|
449
447
|
0 && (module.exports = {
|
|
450
448
|
executeSmartConsolidation: executeSmartConsolidation
|
package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/resources/custom.schema.js
RENAMED
|
@@ -85,44 +85,7 @@ const customFields = [ {
|
|
|
85
85
|
hint: `View list of endpoints in the <a href="https://${import_common2.DOCURL_PREFIX}/connectwise-api" target="_blank">documentation</a>`,
|
|
86
86
|
placeholder: "e.g., /company/companies/:id or https://api.connectwise.com/...",
|
|
87
87
|
description: "The API endpoint. Can be a full URL or a partial path. Include any parameters like the ID directly in the URL."
|
|
88
|
-
}, ...
|
|
89
|
-
displayName: "Custom Fields",
|
|
90
|
-
name: "customFields",
|
|
91
|
-
type: "fixedCollection",
|
|
92
|
-
placeholder: "Add Custom Field",
|
|
93
|
-
default: {},
|
|
94
|
-
displayOptions: {
|
|
95
|
-
show: {
|
|
96
|
-
resource: [ "custom" ],
|
|
97
|
-
operation: [ "create", "update" ]
|
|
98
|
-
}
|
|
99
|
-
},
|
|
100
|
-
typeOptions: {
|
|
101
|
-
multipleValues: !0
|
|
102
|
-
},
|
|
103
|
-
options: [ {
|
|
104
|
-
name: "field",
|
|
105
|
-
displayName: "Custom Field",
|
|
106
|
-
values: [ {
|
|
107
|
-
displayName: "Field",
|
|
108
|
-
name: "id",
|
|
109
|
-
type: "options",
|
|
110
|
-
required: !0,
|
|
111
|
-
typeOptions: {
|
|
112
|
-
loadOptionsMethod: "loadCustomFieldsOptions",
|
|
113
|
-
loadOptionsDependsOn: [ "endpoint" ]
|
|
114
|
-
},
|
|
115
|
-
default: "",
|
|
116
|
-
description: "Choose from available custom fields for this endpoint"
|
|
117
|
-
}, {
|
|
118
|
-
displayName: "Value",
|
|
119
|
-
name: "value",
|
|
120
|
-
type: "string",
|
|
121
|
-
default: "",
|
|
122
|
-
description: "Value for the custom field. Leave empty to nullify. Ensure you pass a value compatible with the field type. Checkbox can be true/false/1/0/on/off."
|
|
123
|
-
} ]
|
|
124
|
-
} ]
|
|
125
|
-
} ] : [], ...(0, import_common.getCommonFields)({
|
|
88
|
+
}, ...(0, import_common.getCommonFields)({
|
|
126
89
|
overrides: {
|
|
127
90
|
fields: {
|
|
128
91
|
type: "string",
|
package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/resources/ticket.schema.js
RENAMED
|
@@ -95,10 +95,6 @@ const ticketFields = [ {
|
|
|
95
95
|
}, {
|
|
96
96
|
name: "Project Ticket",
|
|
97
97
|
value: "project"
|
|
98
|
-
}, {
|
|
99
|
-
name: "Auto ✨",
|
|
100
|
-
value: "auto",
|
|
101
|
-
description: "Automatically detect ticket type"
|
|
102
98
|
} ],
|
|
103
99
|
displayOptions: {
|
|
104
100
|
show: {
|
|
@@ -511,8 +507,7 @@ const ticketFields = [ {
|
|
|
511
507
|
ticketType: [ "project" ]
|
|
512
508
|
}
|
|
513
509
|
}
|
|
514
|
-
}, ...
|
|
515
|
-
import_common.getCommonFields)(), {
|
|
510
|
+
}, ...(0, import_common.getCommonFields)(), {
|
|
516
511
|
displayName: `New to Smart Alert Consolidation? Start with the <a href="https://${import_common2.DOCURL_PREFIX}/smart-alert-consolidation${import_common2.DOCURL_SUFFIX}" target="_blank">setup guide</a> for a walkthrough of all options.`,
|
|
517
512
|
name: "smartAlertConsolidationNotice",
|
|
518
513
|
type: "notice",
|
|
@@ -1005,11 +1000,6 @@ import_common.getCommonFields)(), {
|
|
|
1005
1000
|
|
|
1006
1001
|
async function execute(operation, i) {
|
|
1007
1002
|
if (operation === "smartAlertConsolidation") {
|
|
1008
|
-
{
|
|
1009
|
-
if (process.env.MSPCOPILOT_BETA !== "true") return (0, import_utils.returnProOnlyMessage)(this, i);
|
|
1010
|
-
const {requireAccessKey: requireAccessKey} = await import("../../transport/access-key.js");
|
|
1011
|
-
if (!await requireAccessKey(this, "beta")) return (0, import_utils.returnAccessKeyRequired)(this, i);
|
|
1012
|
-
}
|
|
1013
1003
|
const {executeSmartConsolidation: executeSmartConsolidation} = await import("./alert-consolidation.js");
|
|
1014
1004
|
return executeSmartConsolidation.call(this, i);
|
|
1015
1005
|
}
|
package/{dist-beta → dist-community}/nodes/ConnectWise/PSA/schema/resources/timeEntry.schema.js
RENAMED
|
@@ -353,6 +353,13 @@ const timeEntryFields = [ {
|
|
|
353
353
|
default: !1,
|
|
354
354
|
description: "Whether to email the resource about this time entry",
|
|
355
355
|
x_submitAs: "emailResourceFlag"
|
|
356
|
+
}, {
|
|
357
|
+
displayName: "Email CC",
|
|
358
|
+
name: "emailCcFlag",
|
|
359
|
+
type: "boolean",
|
|
360
|
+
default: !1,
|
|
361
|
+
description: "Whether to email the CC list on the ticket about this time entry",
|
|
362
|
+
x_submitAs: "emailCcFlag"
|
|
356
363
|
}, {
|
|
357
364
|
displayName: "Email Contact",
|
|
358
365
|
name: "emailContactFlag",
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
var __create = Object.create;
|
|
2
|
-
|
|
3
1
|
var __defProp = Object.defineProperty;
|
|
4
2
|
|
|
5
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
4
|
|
|
7
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
8
6
|
|
|
9
|
-
var
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
10
8
|
|
|
11
9
|
var __export = (target, all) => {
|
|
12
10
|
for (var name in all) __defProp(target, name, {
|
|
@@ -21,11 +19,7 @@ var __export = (target, all) => {
|
|
|
21
19
|
return to;
|
|
22
20
|
};
|
|
23
21
|
|
|
24
|
-
var
|
|
25
|
-
__copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
26
|
-
value: mod,
|
|
27
|
-
enumerable: !0
|
|
28
|
-
}) : target, mod)), __toCommonJS = mod => __copyProps(__defProp({}, "__esModule", {
|
|
22
|
+
var __toCommonJS = mod => __copyProps(__defProp({}, "__esModule", {
|
|
29
23
|
value: !0
|
|
30
24
|
}), mod);
|
|
31
25
|
|
|
@@ -50,95 +44,23 @@ function getBestErrorMessage(operationError) {
|
|
|
50
44
|
}
|
|
51
45
|
|
|
52
46
|
async function getCacheClient() {
|
|
53
|
-
|
|
54
|
-
if (!Redis && process.env.MSPCOPILOT_BETA === "true") try {
|
|
55
|
-
Redis = (await import("ioredis")).default;
|
|
56
|
-
} catch (error) {
|
|
57
|
-
return console.error("Failed to load cache module:", error), null;
|
|
58
|
-
}
|
|
59
|
-
if (cacheClient && cacheClient.status === "ready") return cacheClient;
|
|
60
|
-
if (cacheClient && [ "end", "close" ].includes(cacheClient.status)) {
|
|
61
|
-
try {
|
|
62
|
-
cacheClient.disconnect(!1);
|
|
63
|
-
} catch {}
|
|
64
|
-
cacheClient = null;
|
|
65
|
-
}
|
|
66
|
-
if (!cacheClient && Redis) try {
|
|
67
|
-
cacheClient = new Redis({
|
|
68
|
-
host: process.env.QUEUE_BULL_REDIS_HOST || "localhost",
|
|
69
|
-
port: parseInt(process.env.QUEUE_BULL_REDIS_PORT || "6379"),
|
|
70
|
-
password: process.env.QUEUE_BULL_REDIS_PASSWORD || "",
|
|
71
|
-
db: 1,
|
|
72
|
-
retryStrategy: () => null,
|
|
73
|
-
lazyConnect: !0,
|
|
74
|
-
enableOfflineQueue: !1,
|
|
75
|
-
connectTimeout: 1e3
|
|
76
|
-
}), cacheClient.on("error", err => {
|
|
77
|
-
console.error("Cache connection error:", err.message), lastConnectionError = err.message;
|
|
78
|
-
});
|
|
79
|
-
} catch (error) {
|
|
80
|
-
console.error("Failed to create cache client:", error), cacheClient = null;
|
|
81
|
-
}
|
|
82
|
-
return cacheClient;
|
|
47
|
+
return null;
|
|
83
48
|
}
|
|
84
49
|
|
|
85
50
|
async function getCached(key) {
|
|
86
|
-
|
|
51
|
+
return {
|
|
87
52
|
data: null
|
|
88
53
|
};
|
|
89
|
-
const redis = await getCacheClient();
|
|
90
|
-
if (!redis) return {
|
|
91
|
-
data: null,
|
|
92
|
-
error: "Redis not available"
|
|
93
|
-
};
|
|
94
|
-
try {
|
|
95
|
-
const cached = await redis.get(key);
|
|
96
|
-
return cached !== null ? {
|
|
97
|
-
data: JSON.parse(cached)
|
|
98
|
-
} : {
|
|
99
|
-
data: null
|
|
100
|
-
};
|
|
101
|
-
} catch (error) {
|
|
102
|
-
return console.error("Cache get error:", error.message), {
|
|
103
|
-
data: null,
|
|
104
|
-
error: getBestErrorMessage(error.message)
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
54
|
}
|
|
108
55
|
|
|
109
56
|
async function setCached(key, data, ttl) {
|
|
110
|
-
|
|
111
|
-
success: !1
|
|
112
|
-
};
|
|
113
|
-
const redis = await getCacheClient();
|
|
114
|
-
if (!redis) return {
|
|
115
|
-
success: !1,
|
|
116
|
-
error: "Redis not available"
|
|
117
|
-
};
|
|
118
|
-
if (ttl <= 0) return {
|
|
57
|
+
return {
|
|
119
58
|
success: !1
|
|
120
59
|
};
|
|
121
|
-
try {
|
|
122
|
-
return await redis.setex(key, ttl, JSON.stringify(data)), {
|
|
123
|
-
success: !0
|
|
124
|
-
};
|
|
125
|
-
} catch (error) {
|
|
126
|
-
return console.error("Cache set error:", error.message), {
|
|
127
|
-
success: !1,
|
|
128
|
-
error: getBestErrorMessage(error.message)
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
60
|
}
|
|
132
61
|
|
|
133
62
|
async function deleteCached(key) {
|
|
134
|
-
|
|
135
|
-
const redis = await getCacheClient();
|
|
136
|
-
if (!redis) return !1;
|
|
137
|
-
try {
|
|
138
|
-
return await redis.del(key) > 0;
|
|
139
|
-
} catch (error) {
|
|
140
|
-
return console.error("Cache del error:", error.message), !1;
|
|
141
|
-
}
|
|
63
|
+
return !1;
|
|
142
64
|
}
|
|
143
65
|
|
|
144
66
|
async function clearAllCached() {
|
|
@@ -43,7 +43,7 @@ module.exports = __toCommonJS(client_exports);
|
|
|
43
43
|
|
|
44
44
|
var import_n8n_workflow = require("n8n-workflow"), import_logging = require("../helpers/logging"), import_hint_collector = require("../helpers/hint-collector");
|
|
45
45
|
|
|
46
|
-
const
|
|
46
|
+
const DEFAULT_API_PATH = "v4_6_release/apis/3.0";
|
|
47
47
|
|
|
48
48
|
function extractApiError(error) {
|
|
49
49
|
let errorMessage = "Request failed";
|
|
@@ -91,51 +91,10 @@ async function connectWiseApiRequest(method, endpoint, body = {}, qs = {}, optio
|
|
|
91
91
|
} catch (error) {
|
|
92
92
|
console.warn("Version check module load failed:", error);
|
|
93
93
|
}
|
|
94
|
-
if (
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
ttl: 0
|
|
99
|
-
};
|
|
100
|
-
if ("getNodeParameter" in this && method === "GET") try {
|
|
101
|
-
cacheConfig = getCacheConfig(this, 0);
|
|
102
|
-
} catch {}
|
|
103
|
-
process.env.MSPCOPILOT_BETA === "true" && options.optionsCache === !0 && method === "GET" && (cacheConfig = {
|
|
104
|
-
enabled: !0,
|
|
105
|
-
ttl: OPTIONS_CACHE_TTL
|
|
106
|
-
});
|
|
107
|
-
let cacheKey;
|
|
108
|
-
if (cacheConfig.enabled) {
|
|
109
|
-
const credentials = await this.getCredentials("connectWisePsaApi"), cacheKeyData = {
|
|
110
|
-
endpoint: endpoint,
|
|
111
|
-
qs: qs,
|
|
112
|
-
options: options
|
|
113
|
-
}, hash = createHash("sha256").update(JSON.stringify(cacheKeyData)).digest("hex").substring(0, 16);
|
|
114
|
-
if (cacheKey = `cw:psa:${credentials.companyId}:${hash}`, cacheConfig.ttl === 0) await deleteCached(cacheKey),
|
|
115
|
-
console.log("🗑️ Cache invalidated for", endpoint), options.optionsCache || (0,
|
|
116
|
-
import_hint_collector.hint)(this, "cache_invalidated"); else {
|
|
117
|
-
const cacheResult = await getCached(cacheKey);
|
|
118
|
-
if (console.log(`💾 Cache lookup for ${endpoint}: ${cacheResult.data ? "✅ HIT" : "❌ MISS"}`, {
|
|
119
|
-
qs: qs,
|
|
120
|
-
options: options
|
|
121
|
-
}), cacheResult.error && !options.optionsCache && (0, import_hint_collector.hint)(this, "cache_error", cacheResult.error),
|
|
122
|
-
cacheResult.data) return options.optionsCache || (0, import_hint_collector.hint)(this, "cache_hit"),
|
|
123
|
-
cacheResult.data;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
const response = await connectWiseHttpRequest.call(this, method, endpoint, body, qs, options);
|
|
127
|
-
if (cacheKey && cacheConfig.ttl > 0) {
|
|
128
|
-
const setResult = await setCached(cacheKey, response, cacheConfig.ttl);
|
|
129
|
-
if (console.log(`💾 Storing response in cache for ${endpoint} - TTL=${cacheConfig.ttl}s, Data=${Array.isArray(response) ? `${response.length} items` : "single item"}, Key=${cacheKey}`),
|
|
130
|
-
!options.optionsCache) {
|
|
131
|
-
if (setResult.error) (0, import_hint_collector.hint)(this, "cache_error", setResult.error); else if (setResult.success) {
|
|
132
|
-
const minutes = Math.floor(cacheConfig.ttl / 60), ttlMessage = minutes > 0 ? `${minutes} minutes` : `${cacheConfig.ttl} seconds`;
|
|
133
|
-
(0, import_hint_collector.hint)(this, "cache_stored", ttlMessage);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
return response;
|
|
138
|
-
} else return await connectWiseHttpRequest.call(this, method, endpoint, body, qs, options);
|
|
94
|
+
if ("getNodeParameter" in this && method === "GET") try {
|
|
95
|
+
const cacheResponse = this.getNodeParameter("cacheResponse", 0, !1);
|
|
96
|
+
} catch {}
|
|
97
|
+
return await connectWiseHttpRequest.call(this, method, endpoint, body, qs, options);
|
|
139
98
|
}
|
|
140
99
|
|
|
141
100
|
async function connectWiseHttpRequest(method, endpoint, body = {}, qs = {}, options = {}) {
|
|
@@ -39,7 +39,7 @@ module.exports = __toCommonJS(version_check_exports);
|
|
|
39
39
|
|
|
40
40
|
var fs = __toESM(require("fs/promises")), path = __toESM(require("path")), os = __toESM(require("os")), import_common = require("../descriptions/common.descriptions"), import_hint_collector = require("../helpers/hint-collector");
|
|
41
41
|
|
|
42
|
-
const CACHE_FILE_PATH = path.join(os.tmpdir(), "connectwise-n8n-version-cache.json"), CURRENT_VERSION = "0.
|
|
42
|
+
const CACHE_FILE_PATH = path.join(os.tmpdir(), "connectwise-n8n-version-cache.json"), CURRENT_VERSION = "0.3.0";
|
|
43
43
|
|
|
44
44
|
let inMemoryCache = null, cacheLoadPromise = null, fetchInProgress = !1;
|
|
45
45
|
|
|
@@ -48,7 +48,7 @@ async function initializeCache() {
|
|
|
48
48
|
const fileContent = await fs.readFile(CACHE_FILE_PATH, "utf-8"), cacheEntry = JSON.parse(fileContent);
|
|
49
49
|
if (Date.now() < cacheEntry.expires ? (cacheEntry.data.updateAvailable && cacheEntry.data.latest === CURRENT_VERSION && (cacheEntry.data.updateAvailable = !1),
|
|
50
50
|
inMemoryCache = cacheEntry.data, inMemoryCache.updateAvailable && (console.log(`🎉 ConnectWise PSA Node v${inMemoryCache.latest} is available! (current: v${CURRENT_VERSION})`),
|
|
51
|
-
console.log(` Beta upgrade guide: https://${import_common.DOCURL_PREFIX}/beta-upgrade${import_common.DOCURL_SUFFIX}`))) : cacheEntry.data?.accessKeyInfo && (inMemoryCache = cacheEntry.data),
|
|
51
|
+
process.env.MSPCOPILOT_BETA === "true" ? console.log(` Beta upgrade guide: https://${import_common.DOCURL_PREFIX}/beta-upgrade${import_common.DOCURL_SUFFIX}`) : console.log(` View changelog: https://${import_common.CHANGELOG_URL}`))) : cacheEntry.data?.accessKeyInfo && (inMemoryCache = cacheEntry.data),
|
|
52
52
|
inMemoryCache?.accessKeyInfo) try {
|
|
53
53
|
const {updateAccessKeyFromServer: updateAccessKeyFromServer} = await import("./access-key.js");
|
|
54
54
|
updateAccessKeyFromServer(inMemoryCache.accessKeyInfo);
|
|
@@ -64,7 +64,7 @@ async function saveCache(versionInfo) {
|
|
|
64
64
|
};
|
|
65
65
|
try {
|
|
66
66
|
await fs.writeFile(CACHE_FILE_PATH, JSON.stringify(cacheEntry, null, 2), "utf-8"),
|
|
67
|
-
console.log("📦 Version check cache saved to disk (
|
|
67
|
+
console.log("📦 Version check cache saved to disk (community build)");
|
|
68
68
|
} catch (error) {
|
|
69
69
|
console.warn("⚠️ Failed to save version check cache to disk:", error);
|
|
70
70
|
}
|
|
@@ -77,7 +77,7 @@ async function fetchLatestVersion(accessKey) {
|
|
|
77
77
|
lastChecked: Date.now()
|
|
78
78
|
};
|
|
79
79
|
try {
|
|
80
|
-
const effectiveBuild =
|
|
80
|
+
const effectiveBuild = process.env.MSPCOPILOT_BETA === "true" ? "beta" : "community";
|
|
81
81
|
console.log(`🔍 Checking for updates (${effectiveBuild} v${CURRENT_VERSION})...`);
|
|
82
82
|
const controller = new AbortController, timeoutId = setTimeout(() => controller.abort(), 5e3), url = `${import_common.VERSION_CHECK_URL}?version=${CURRENT_VERSION}&build=${effectiveBuild}`, headers = {
|
|
83
83
|
Accept: "application/json"
|
|
@@ -124,13 +124,17 @@ function checkForUpdatesAsync(accessKey) {
|
|
|
124
124
|
|
|
125
125
|
async function checkAndNotifyUpdate(context) {
|
|
126
126
|
try {
|
|
127
|
-
process.env.MSPCOPILOT_BETA;
|
|
128
|
-
const
|
|
129
|
-
if (
|
|
130
|
-
checkForUpdatesAsync(accessKey), inMemoryCache?.updateAvailable && (
|
|
127
|
+
process.env.MSPCOPILOT_BETA === "true" && (0, import_hint_collector.hint)(context, "beta_downgrade");
|
|
128
|
+
const credentials = await context.getCredentials("connectWisePsaApi"), accessKey = credentials.accessKey;
|
|
129
|
+
if (!(process.env.MSPCOPILOT_BETA === "true" ? !0 : credentials.checkForUpdates)) return;
|
|
130
|
+
checkForUpdatesAsync(accessKey), inMemoryCache?.updateAvailable && (process.env.MSPCOPILOT_BETA === "true" ? (0,
|
|
131
|
+
import_hint_collector.hint)(context, "beta_update", {
|
|
131
132
|
version: inMemoryCache.latest,
|
|
132
133
|
message: inMemoryCache.message
|
|
133
|
-
})
|
|
134
|
+
}) : (0, import_hint_collector.hint)(context, "version_update", {
|
|
135
|
+
version: inMemoryCache.latest,
|
|
136
|
+
message: inMemoryCache.message
|
|
137
|
+
}));
|
|
134
138
|
} catch (error) {
|
|
135
139
|
console.warn("⚠️ Version check failed:", error);
|
|
136
140
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mspcopilot/n8n-nodes-connectwise",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "n8n node to integrate with ConnectWise PSA",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"n8n-community-node-package"
|
|
@@ -24,17 +24,16 @@
|
|
|
24
24
|
"postinstall": "echo 'ConnectWise PSA node installed successfully'"
|
|
25
25
|
},
|
|
26
26
|
"files": [
|
|
27
|
-
"dist-
|
|
27
|
+
"dist-community"
|
|
28
28
|
],
|
|
29
29
|
"n8n": {
|
|
30
30
|
"n8nNodesApiVersion": 1,
|
|
31
31
|
"credentials": [
|
|
32
|
-
"dist-
|
|
32
|
+
"dist-community/credentials/ConnectWisePsaApi.credentials.js"
|
|
33
33
|
],
|
|
34
34
|
"nodes": [
|
|
35
|
-
"dist-
|
|
36
|
-
"dist-
|
|
37
|
-
"dist-beta/nodes/ConnectWise/PSA/IfSchedule.node.js"
|
|
35
|
+
"dist-community/nodes/ConnectWise/PSA/ConnectWisePsa.node.js",
|
|
36
|
+
"dist-community/nodes/ConnectWise/PSA/ConnectWisePsaTrigger.node.js"
|
|
38
37
|
]
|
|
39
38
|
},
|
|
40
39
|
"dependencies": {
|