@limetech/n8n-nodes-lime 0.3.8 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/.prettierignore +3 -1
  2. package/CHANGELOG.md +100 -0
  3. package/README.md +1 -8
  4. package/credentials/LimeCrmApi.credentials.ts +6 -6
  5. package/dist/nodes/lime-crm/LimeCrmNode.node.js +13 -0
  6. package/dist/nodes/lime-crm/LimeCrmNode.node.js.map +1 -1
  7. package/dist/nodes/lime-crm/commons/constants.d.ts +1 -0
  8. package/dist/nodes/lime-crm/commons/constants.js +2 -1
  9. package/dist/nodes/lime-crm/commons/constants.js.map +1 -1
  10. package/dist/nodes/lime-crm/commons/index.d.ts +1 -1
  11. package/dist/nodes/lime-crm/commons/index.js +2 -1
  12. package/dist/nodes/lime-crm/commons/index.js.map +1 -1
  13. package/dist/nodes/lime-crm/resources/limeQuery/index.d.ts +6 -0
  14. package/dist/nodes/lime-crm/resources/limeQuery/index.js +66 -0
  15. package/dist/nodes/lime-crm/resources/limeQuery/index.js.map +1 -0
  16. package/dist/nodes/lime-crm/resources/limeQuery/operations/query.operation.d.ts +9 -0
  17. package/dist/nodes/lime-crm/resources/limeQuery/operations/query.operation.js +191 -0
  18. package/dist/nodes/lime-crm/resources/limeQuery/operations/query.operation.js.map +1 -0
  19. package/dist/nodes/lime-crm/resources/limeType/index.d.ts +3 -3
  20. package/dist/nodes/lime-crm/transport/index.d.ts +1 -0
  21. package/dist/nodes/lime-crm/transport/index.js +3 -1
  22. package/dist/nodes/lime-crm/transport/index.js.map +1 -1
  23. package/dist/nodes/lime-crm/transport/limeQuery.d.ts +10 -0
  24. package/dist/nodes/lime-crm/transport/limeQuery.js +15 -0
  25. package/dist/nodes/lime-crm/transport/limeQuery.js.map +1 -0
  26. package/dist/package.json +1 -1
  27. package/dist/tsconfig.tsbuildinfo +1 -1
  28. package/docker-compose.yml +9 -3
  29. package/nodes/fortnox/Fortnox.node.ts +3 -3
  30. package/nodes/fortnox/FortnoxTrigger.node.ts +2 -2
  31. package/nodes/lime-crm/LimeCrmNode.node.ts +54 -53
  32. package/nodes/lime-crm/LimeCrmTrigger.node.ts +17 -24
  33. package/nodes/lime-crm/commons/constants.ts +2 -2
  34. package/nodes/lime-crm/commons/files.ts +162 -0
  35. package/nodes/lime-crm/commons/index.ts +4 -3
  36. package/nodes/lime-crm/commons/webhook.ts +15 -3
  37. package/nodes/lime-crm/methods/getLimetypeProperties.ts +67 -0
  38. package/nodes/lime-crm/methods/getLimetypes.ts +21 -0
  39. package/nodes/lime-crm/methods/index.ts +6 -2
  40. package/nodes/lime-crm/model.ts +22 -0
  41. package/nodes/lime-crm/resources/data/index.ts +80 -0
  42. package/nodes/lime-crm/resources/{limeObject/operations/create.operation.ts → data/operations/createSingleObject.ts} +53 -30
  43. package/nodes/lime-crm/resources/{limeObject/operations/delete.operation.ts → data/operations/deleteSingleObject.ts} +15 -15
  44. package/nodes/lime-crm/resources/data/operations/getManyObjects.ts +356 -0
  45. package/nodes/lime-crm/resources/data/operations/getSingleFile.ts +138 -0
  46. package/nodes/lime-crm/resources/data/operations/getSingleObject.ts +83 -0
  47. package/nodes/lime-crm/resources/{limeObject/operations/update.operation.ts → data/operations/updateSingleObject.operation.ts} +51 -23
  48. package/nodes/lime-crm/resources/erpConnector/index.ts +3 -3
  49. package/nodes/lime-crm/resources/erpConnector/operations/transform.operation.ts +14 -14
  50. package/nodes/lime-crm/resources/erpConnector/transform.ts +3 -3
  51. package/nodes/lime-crm/resources/erpConnector/transformers/baseTransformer.ts +2 -2
  52. package/nodes/lime-crm/resources/erpConnector/transformers/fortnox.ts +8 -8
  53. package/nodes/lime-crm/resources/metadata/index.ts +57 -0
  54. package/nodes/lime-crm/resources/metadata/operations/getAllLimetypes.operation.ts +18 -0
  55. package/nodes/lime-crm/resources/metadata/operations/getSingleFileMetadata.ts +130 -0
  56. package/nodes/lime-crm/resources/metadata/operations/getSingleLimetype.ts +36 -0
  57. package/nodes/lime-crm/transport/commons.ts +14 -2
  58. package/nodes/lime-crm/transport/files.ts +155 -0
  59. package/nodes/lime-crm/transport/index.ts +14 -6
  60. package/nodes/lime-crm/transport/limeQuery.ts +26 -0
  61. package/nodes/lime-crm/transport/limeobjects.ts +79 -44
  62. package/nodes/lime-crm/transport/limetypes.ts +80 -24
  63. package/package.json +4 -3
  64. package/restore_script/README +42 -0
  65. package/restore_script/api_key_download.txt +0 -0
  66. package/restore_script/api_key_upload.txt +0 -0
  67. package/restore_script/cli.py +73 -0
  68. package/restore_script/download.py +73 -0
  69. package/restore_script/main.py +19 -0
  70. package/restore_script/poetry.lock +162 -0
  71. package/restore_script/pyproject.toml +15 -0
  72. package/restore_script/transfer.py +41 -0
  73. package/restore_script/upload.py +66 -0
  74. package/restore_script/utils.py +42 -0
  75. package/tests/transform.spec.ts +6 -6
  76. package/nodes/lime-crm/commons/limetype.ts +0 -11
  77. package/nodes/lime-crm/methods/getLimeTypeProperties.ts +0 -27
  78. package/nodes/lime-crm/methods/getLimeTypes.ts +0 -23
  79. package/nodes/lime-crm/resources/limeObject/index.ts +0 -64
  80. package/nodes/lime-crm/resources/limeObject/operations/fetchMany.operation.ts +0 -112
  81. package/nodes/lime-crm/resources/limeObject/operations/get.operation.ts +0 -54
  82. package/nodes/lime-crm/resources/limeType/index.ts +0 -58
  83. package/nodes/lime-crm/resources/limeType/operations/getProperties.operation.ts +0 -42
  84. package/nodes/lime-crm/resources/limeType/operations/getType.operation.ts +0 -36
  85. package/nodes/lime-crm/resources/limeType/operations/listTypes.operation.ts +0 -18
@@ -16,8 +16,11 @@ services:
16
16
  - DB_POSTGRESDB_PASSWORD=n8n
17
17
  - N8N_SECURE_COOKIE=false
18
18
  - N8N_LOG_LEVEL=debug
19
+ - N8N_LOG_OUTPUT=console
20
+ - N8N_LOG_FORMAT=text
21
+ - NODES_EXCLUDE=["n8n-nodes-base.executeCommand", "n8n-nodes-base.readWriteFile", "n8n-nodes-base.n8n", "n8n-nodes-base.ssh"]
19
22
  volumes:
20
- - ./dist:/home/node/.n8n/custom
23
+ - n8n_dist:/home/node/.n8n/custom
21
24
  depends_on:
22
25
  - postgres
23
26
 
@@ -28,8 +31,10 @@ services:
28
31
  command: -c "cd /source && tsc --watch"
29
32
  entrypoint: /bin/sh
30
33
  volumes:
31
- - .:/source
32
- - ./dist:/source/dist
34
+ - ./nodes:/source/nodes
35
+ - ./credentials:/source/credentials
36
+ - ./tsconfig.json:/source/tsconfig.json
37
+ - n8n_dist:/source/dist
33
38
 
34
39
  postgres:
35
40
  image: postgres:14
@@ -44,3 +49,4 @@ services:
44
49
 
45
50
  volumes:
46
51
  postgres_data:
52
+ n8n_dist:
@@ -5,7 +5,7 @@ import {
5
5
  INodeProperties,
6
6
  INodeType,
7
7
  INodeTypeDescription,
8
- NodeConnectionType,
8
+ NodeConnectionTypes,
9
9
  NodeOperationError,
10
10
  NodePropertyTypes,
11
11
  } from 'n8n-workflow';
@@ -27,8 +27,8 @@ export class Fortnox implements INodeType {
27
27
  defaults: {
28
28
  name: 'Fortnox',
29
29
  },
30
- inputs: [NodeConnectionType.Main],
31
- outputs: [NodeConnectionType.Main],
30
+ inputs: [NodeConnectionTypes.Main],
31
+ outputs: [NodeConnectionTypes.Main],
32
32
  credentials: [
33
33
  {
34
34
  name: FORTNOX_API_CREDENTIAL_KEY,
@@ -3,7 +3,7 @@ import {
3
3
  INodeTypeDescription,
4
4
  ITriggerFunctions,
5
5
  ITriggerResponse,
6
- NodeConnectionType,
6
+ NodeConnectionTypes,
7
7
  NodeOperationError,
8
8
  } from 'n8n-workflow';
9
9
  import WebSocket from 'ws';
@@ -32,7 +32,7 @@ export class FortnoxTrigger implements INodeType {
32
32
  name: 'Fortnox Trigger',
33
33
  },
34
34
  inputs: [],
35
- outputs: [NodeConnectionType.Main],
35
+ outputs: [NodeConnectionTypes.Main],
36
36
  credentials: [
37
37
  {
38
38
  name: FORTNOX_API_CREDENTIAL_KEY,
@@ -4,30 +4,32 @@ import {
4
4
  INodeProperties,
5
5
  INodeType,
6
6
  INodeTypeDescription,
7
- NodeConnectionType,
7
+ NodeConnectionTypes,
8
8
  NodePropertyTypes,
9
9
  } from 'n8n-workflow';
10
10
 
11
- import {
12
- erpConnectorFields,
13
- erpConnectorOperations,
14
- } from './resources/erpConnector';
15
- import { limeTypeFields, limeTypeOperations } from './resources/limeType';
16
- import { limeObjectFields, limeObjectOperations } from './resources/limeObject';
11
+ import { metadataFields, metadataOperations } from './resources/metadata';
12
+ import { dataFields, dataOperations } from './resources/data';
17
13
 
18
14
  import {
19
- LIMEOBJECT_RESOURCE,
20
- LIMETYPE_RESOURCE,
15
+ DATA_RESOURCE,
16
+ METADATA_RESOURCE,
21
17
  LIME_CRM_API_CREDENTIAL_KEY,
22
- ERP_CONNECTOR_RESOURCE,
23
18
  } from './commons';
24
19
 
25
20
  import {
26
21
  getEntitiesForErpSystem,
27
- getLimeTypeProperties,
28
- getLimeTypes,
22
+ getFileProperties,
23
+ getLimetypeProperties,
24
+ getLimetypes,
25
+ getNoHasManyProperties,
29
26
  } from './methods';
30
27
 
28
+ type OperationFn = (
29
+ this: IExecuteFunctions,
30
+ args: { operation: string; i: number }
31
+ ) => Promise<unknown>;
32
+
31
33
  export class LimeCrmNode implements INodeType {
32
34
  description: INodeTypeDescription = {
33
35
  displayName: 'Lime CRM',
@@ -41,8 +43,8 @@ export class LimeCrmNode implements INodeType {
41
43
  defaults: {
42
44
  name: 'Lime CRM',
43
45
  },
44
- inputs: [NodeConnectionType.Main],
45
- outputs: [NodeConnectionType.Main],
46
+ inputs: [NodeConnectionTypes.Main],
47
+ outputs: [NodeConnectionTypes.Main],
46
48
  credentials: [
47
49
  {
48
50
  name: LIME_CRM_API_CREDENTIAL_KEY,
@@ -57,35 +59,33 @@ export class LimeCrmNode implements INodeType {
57
59
  noDataExpression: true,
58
60
  options: [
59
61
  {
60
- name: 'Lime Type',
61
- value: LIMETYPE_RESOURCE,
62
- description: 'Work with entity type definitions',
62
+ name: 'Metadata',
63
+ value: METADATA_RESOURCE,
64
+ description:
65
+ 'Work with the structure of available ' +
66
+ 'Limetypes and their properties',
63
67
  },
64
68
  {
65
- name: 'Lime Object',
66
- value: LIMEOBJECT_RESOURCE,
67
- description: 'Work with actual data records',
68
- },
69
- {
70
- name: 'ERP Connector',
71
- value: ERP_CONNECTOR_RESOURCE,
72
- description: 'Integrate data between ERP and Lime CRM',
69
+ name: 'Data',
70
+ value: DATA_RESOURCE,
71
+ description: 'Work with CRM data',
73
72
  },
74
73
  ],
75
- default: LIMEOBJECT_RESOURCE,
74
+ default: DATA_RESOURCE,
76
75
  },
77
76
 
78
- ...(limeTypeFields as INodeProperties[]),
79
- ...(limeObjectFields as INodeProperties[]),
80
- ...(erpConnectorFields as INodeProperties[]),
77
+ ...(metadataFields as INodeProperties[]),
78
+ ...(dataFields as INodeProperties[]),
81
79
  ],
82
80
  };
83
81
 
84
82
  methods = {
85
83
  loadOptions: {
86
84
  getEntitiesForErpSystem,
87
- getLimeTypes,
88
- getLimeTypeProperties,
85
+ getLimetypes,
86
+ getFileProperties,
87
+ getLimetypeProperties,
88
+ getNoHasManyProperties,
89
89
  },
90
90
  };
91
91
 
@@ -96,38 +96,39 @@ export class LimeCrmNode implements INodeType {
96
96
  const resource = this.getNodeParameter('resource', 0) as string;
97
97
  const operation = this.getNodeParameter('operation', 0) as string;
98
98
 
99
+ let operationFn: OperationFn | undefined;
100
+ switch (resource) {
101
+ case METADATA_RESOURCE: {
102
+ operationFn = metadataOperations;
103
+ break;
104
+ }
105
+ case DATA_RESOURCE: {
106
+ operationFn = dataOperations;
107
+ break;
108
+ }
109
+ }
110
+
99
111
  for (let i = 0; i < items.length; i++) {
100
- let responseData;
112
+ if (!operationFn) continue;
101
113
  try {
102
- if (resource === LIMETYPE_RESOURCE) {
103
- responseData = await limeTypeOperations.call(this, {
104
- operation,
105
- i,
106
- });
107
- } else if (resource === LIMEOBJECT_RESOURCE) {
108
- responseData = await limeObjectOperations.call(this, {
109
- operation,
110
- i,
111
- });
112
- } else if (resource === ERP_CONNECTOR_RESOURCE) {
113
- responseData = await erpConnectorOperations.call(this, {
114
- operation,
115
- i,
116
- });
114
+ const responseData = await operationFn.call(this, {
115
+ operation,
116
+ i,
117
+ });
118
+ if (responseData !== undefined) {
119
+ returnData.push(
120
+ responseData as unknown as INodeExecutionData
121
+ );
117
122
  }
118
-
119
- returnData.push({ json: responseData });
120
123
  } catch (error) {
121
124
  if (this.continueOnFail()) {
122
- returnData.push({
123
- error: error.message,
124
- json: { error: error.message },
125
- });
125
+ returnData.push({ error: error.message });
126
126
  continue;
127
127
  }
128
128
  throw error;
129
129
  }
130
130
  }
131
+
131
132
  return [this.helpers.returnJsonArray(returnData)];
132
133
  }
133
134
  }
@@ -7,11 +7,11 @@ import {
7
7
  IWebhookResponseData,
8
8
  NodeOperationError,
9
9
  LoggerProxy as Logger,
10
- NodeConnectionType,
10
+ NodeConnectionTypes,
11
11
  } from 'n8n-workflow';
12
12
 
13
13
  import { getWebhook, LIME_CRM_API_CREDENTIAL_KEY } from './commons';
14
- import { getLimeTypes } from './methods';
14
+ import { getLimetypes } from './methods';
15
15
  import {
16
16
  createSubscription,
17
17
  deleteSubscription,
@@ -19,7 +19,7 @@ import {
19
19
  listSubscriptionsWithExistingData,
20
20
  } from './transport';
21
21
 
22
- import { verifyHmac } from './commons/hmac';
22
+ import { verifyHmac } from './commons';
23
23
 
24
24
  export class LimeCrmTrigger implements INodeType {
25
25
  description: INodeTypeDescription = {
@@ -30,12 +30,12 @@ export class LimeCrmTrigger implements INodeType {
30
30
  version: 1,
31
31
  description:
32
32
  'Trigger which handles webhooks coming from Lime, e.g when ' +
33
- 'LimeObject is updated',
33
+ 'an object is updated',
34
34
  defaults: {
35
35
  name: 'Lime CRM Trigger',
36
36
  },
37
37
  inputs: [],
38
- outputs: [NodeConnectionType.Main],
38
+ outputs: [NodeConnectionTypes.Main],
39
39
  credentials: [
40
40
  {
41
41
  name: LIME_CRM_API_CREDENTIAL_KEY,
@@ -68,18 +68,18 @@ export class LimeCrmTrigger implements INodeType {
68
68
  displayName: 'Event',
69
69
  values: [
70
70
  {
71
- displayName: 'Lime Type',
72
- name: 'limeType',
71
+ displayName: 'Limetype',
72
+ name: 'limetype',
73
73
  type: 'options',
74
74
  typeOptions: {
75
- loadOptionsMethod: 'getLimeTypes',
75
+ loadOptionsMethod: 'getLimetypes',
76
76
  },
77
77
  default: '',
78
78
  description:
79
- 'Lime Type to subscribe to events for',
79
+ 'Limetype to subscribe to events for',
80
80
  },
81
81
  {
82
- displayName: 'Event Type',
82
+ displayName: 'Event',
83
83
  name: 'eventType',
84
84
  type: 'options',
85
85
  options: [
@@ -87,41 +87,34 @@ export class LimeCrmTrigger implements INodeType {
87
87
  name: 'New',
88
88
  value: 'new',
89
89
  description:
90
- 'When a new record is created',
90
+ 'When a new object is created',
91
91
  },
92
92
  {
93
93
  name: 'Update',
94
94
  value: 'update',
95
- description: 'When a record is updated',
95
+ description:
96
+ 'When an object is updated',
96
97
  },
97
98
  {
98
99
  name: 'Delete',
99
100
  value: 'delete',
100
- description: 'When a record is deleted',
101
+ description:
102
+ 'When an object is deleted',
101
103
  },
102
104
  ],
103
105
  default: 'new',
104
- description: 'Type of event to subscribe to',
106
+ description: 'Event to subscribe to',
105
107
  },
106
108
  ],
107
109
  },
108
110
  ],
109
111
  },
110
- {
111
- displayName: 'Name',
112
- name: 'name',
113
- type: 'string',
114
- default: '',
115
- placeholder: 'my-lime-webhook',
116
- required: true,
117
- description: 'Name for this webhook subscription',
118
- },
119
112
  ],
120
113
  };
121
114
 
122
115
  methods = {
123
116
  loadOptions: {
124
- getLimeTypes,
117
+ getLimetypes,
125
118
  },
126
119
  };
127
120
 
@@ -4,6 +4,6 @@ export const LIME_CRM_API_CREDENTIAL_KEY = 'limeCrmApi';
4
4
 
5
5
  // Resources
6
6
 
7
- export const LIMEOBJECT_RESOURCE = 'limeObject';
8
- export const LIMETYPE_RESOURCE = 'limeType';
7
+ export const DATA_RESOURCE = 'data';
8
+ export const METADATA_RESOURCE = 'metadata';
9
9
  export const ERP_CONNECTOR_RESOURCE = 'erpConnector';
@@ -0,0 +1,162 @@
1
+ import {
2
+ IBinaryData,
3
+ IDataObject,
4
+ IExecuteFunctions,
5
+ LoggerProxy as Logger,
6
+ } from 'n8n-workflow';
7
+ import {
8
+ createFile,
9
+ getFileContent,
10
+ getFileMetadata,
11
+ getProperties,
12
+ } from '../transport';
13
+ import { NodeResponse } from '../../nodeResponse';
14
+
15
+ type FileResponse<T> = {
16
+ json: NodeResponse<T>;
17
+ binary?: Record<string, IBinaryData>;
18
+ };
19
+
20
+ export const setFilename = (
21
+ preparedBinaryData: IBinaryData,
22
+ responseFileName: string
23
+ ) => {
24
+ if (!preparedBinaryData.fileName && preparedBinaryData.fileExtension) {
25
+ return responseFileName;
26
+ }
27
+
28
+ return preparedBinaryData.fileName;
29
+ };
30
+
31
+ export function getFilenameFromHeader(
32
+ headers: Record<string, string | string[] | undefined>
33
+ ): string | null {
34
+ let contentDisposition =
35
+ headers['content-disposition'] || headers['Content-Disposition'];
36
+ if (!contentDisposition) return null;
37
+
38
+ if (Array.isArray(contentDisposition)) {
39
+ contentDisposition = contentDisposition[0];
40
+ }
41
+
42
+ // Try RFC 5987 filename* format
43
+ const filenameStarMatch = /filename\*\s*=\s*UTF-8''([^;]+)/i.exec(
44
+ contentDisposition
45
+ );
46
+ if (filenameStarMatch) {
47
+ try {
48
+ return decodeURIComponent(filenameStarMatch[1]);
49
+ } catch {
50
+ return filenameStarMatch[1];
51
+ }
52
+ }
53
+
54
+ // Try regular filename="..." or filename=...
55
+ const filenameMatch =
56
+ /filename\s*=\s*"([^"]+)"|filename\s*=\s*([^;]+)/i.exec(
57
+ contentDisposition
58
+ );
59
+ if (filenameMatch) {
60
+ return filenameMatch[1] || filenameMatch[2];
61
+ }
62
+
63
+ return null;
64
+ }
65
+
66
+ export async function getFileProperties(
67
+ nodeContext: IExecuteFunctions,
68
+ limetype: string,
69
+ allowedProperties?: Set<string>
70
+ ): Promise<Set<string>> {
71
+ const response = await getProperties(nodeContext, limetype);
72
+
73
+ if (!response.success) return new Set();
74
+ return new Set(
75
+ response.data
76
+ .filter(
77
+ (property) =>
78
+ property.type === 'file' &&
79
+ (!allowedProperties || allowedProperties.has(property.name))
80
+ )
81
+ .map((property) => property.name)
82
+ );
83
+ }
84
+
85
+ export async function setFileProperties(
86
+ context: IExecuteFunctions,
87
+ i: number,
88
+ fileProperties: Set<string>,
89
+ definedProperties: IDataObject
90
+ ): Promise<NodeResponse<IDataObject>> {
91
+ for (const fileProperty of fileProperties) {
92
+ if (!(fileProperty in definedProperties)) continue;
93
+ let binaryData: IBinaryData;
94
+ try {
95
+ Logger.info(
96
+ `Checking whether "${definedProperties[fileProperty]}" is a valid binary object for property "${fileProperty}"...`
97
+ );
98
+ binaryData = context.helpers.assertBinaryData(
99
+ i,
100
+ definedProperties[fileProperty] as string
101
+ );
102
+ } catch {
103
+ Logger.info(
104
+ `Invalid or missing binary data for "${fileProperty}". Using original value instead.`
105
+ );
106
+ continue;
107
+ }
108
+ const response = await createFile(
109
+ context,
110
+ binaryData,
111
+ definedProperties[fileProperty] as string
112
+ );
113
+
114
+ if (response.success) {
115
+ definedProperties[fileProperty] = response.data.id;
116
+ } else return response;
117
+ }
118
+ return {
119
+ success: true,
120
+ data: definedProperties,
121
+ };
122
+ }
123
+
124
+ export async function processFileResponse<T extends Record<string, unknown>>(
125
+ nodeContext: IExecuteFunctions,
126
+ fileProperties: Set<string>,
127
+ data: T,
128
+ includeFileContent: boolean = false
129
+ ): Promise<FileResponse<T>> {
130
+ let updatedData = { ...data };
131
+ const binaryData: Record<string, IBinaryData> = {};
132
+ for (const fileProperty of fileProperties) {
133
+ if (!data[fileProperty]) continue;
134
+ const fileMetadataResponse = await getFileMetadata(
135
+ nodeContext,
136
+ data[fileProperty] as string
137
+ );
138
+ if (!fileMetadataResponse.success)
139
+ return { json: fileMetadataResponse };
140
+
141
+ updatedData = {
142
+ ...updatedData,
143
+ [fileProperty]: fileMetadataResponse.data,
144
+ };
145
+
146
+ if (includeFileContent) {
147
+ const fileResponse = await getFileContent(
148
+ nodeContext,
149
+ fileMetadataResponse.data.id
150
+ );
151
+ if (!fileResponse.success) return { json: fileResponse };
152
+ binaryData[fileProperty] = fileResponse.data;
153
+ }
154
+ }
155
+ return {
156
+ json: {
157
+ success: true,
158
+ data: updatedData,
159
+ },
160
+ binary: binaryData,
161
+ };
162
+ }
@@ -1,9 +1,10 @@
1
1
  export {
2
2
  LIME_CRM_API_CREDENTIAL_KEY,
3
- LIMEOBJECT_RESOURCE,
4
- LIMETYPE_RESOURCE,
3
+ DATA_RESOURCE,
4
+ METADATA_RESOURCE,
5
5
  ERP_CONNECTOR_RESOURCE,
6
6
  } from './constants';
7
7
  export { Webhook, getWebhook } from './webhook';
8
8
 
9
- export { LimeType, LimeTypeProperty } from './limetype';
9
+ export { verifyHmac } from './hmac';
10
+ export { setFilename, getFilenameFromHeader } from './files';
@@ -24,18 +24,30 @@ export interface CreateWebhook extends Webhook {
24
24
  function _getEvents(hookData: WebhookFunctions): string[] {
25
25
  const eventData = hookData.getNodeParameter('events', []) as {
26
26
  event: Array<{
27
- limeType: string;
27
+ limetype: string;
28
28
  eventType: string;
29
29
  }>;
30
30
  };
31
31
  const eventItems = eventData.event;
32
32
  const events: string[] = [];
33
33
  for (const eventItem of eventItems) {
34
- events.push(`${eventItem.limeType}.${eventItem.eventType}`);
34
+ events.push(`${eventItem.limetype}.${eventItem.eventType}`);
35
35
  }
36
36
  return events;
37
37
  }
38
38
 
39
+ function _createWebhookName(hookData: WebhookFunctions): string {
40
+ interface Events {
41
+ event: Array<{
42
+ limetype: string;
43
+ eventType: string;
44
+ }>;
45
+ }
46
+
47
+ const events = hookData.getNodeParameter('events') as Events;
48
+ return `${events.event[0].limetype}-${events.event[0].eventType}-${Date.now()}`;
49
+ }
50
+
39
51
  export function getWebhook(hookData: WebhookFunctions): Webhook {
40
52
  const node = hookData.getNode();
41
53
  const workflow = hookData.getWorkflow();
@@ -51,6 +63,6 @@ export function getWebhook(hookData: WebhookFunctions): Webhook {
51
63
  events: _getEvents(hookData),
52
64
  url: hookData.getNodeWebhookUrl('default'),
53
65
  context: context,
54
- name: hookData.getNodeParameter('name') as string,
66
+ name: _createWebhookName(hookData),
55
67
  };
56
68
  }
@@ -0,0 +1,67 @@
1
+ import {
2
+ ILoadOptionsFunctions,
3
+ INodePropertyOptions,
4
+ LoggerProxy as Logger,
5
+ } from 'n8n-workflow';
6
+ import { getProperties } from '../transport/';
7
+
8
+ async function _getProperties(nodeContext: ILoadOptionsFunctions) {
9
+ const limetype = nodeContext.getNodeParameter('limetype', '') as string;
10
+ Logger.info(`Fetching file properties for Lime type: ${limetype}`);
11
+ if (!limetype) return [];
12
+
13
+ const response = await getProperties(nodeContext, limetype);
14
+
15
+ return response.success ? response.data : [];
16
+ }
17
+
18
+ /**
19
+ * Gets property options from a specific Limetype
20
+ *
21
+ * It's not meant to be used directly in 'loadOptionsMethod'
22
+ *
23
+ * This function fetches properties for the specified Limetype and optionally filters them
24
+ * based on allowed types.
25
+ *
26
+ * @param [loader] - The n8n load options context
27
+ * @param [allowedTypes] - Optional set of property types to filter by
28
+ * @param [forbiddenType] - Optional set of property types to exclude
29
+ * @returns Array of formatted property options
30
+ */
31
+ export async function getFilteredLimetypeProperties(
32
+ loader: ILoadOptionsFunctions,
33
+ allowedTypes?: Set<string>,
34
+ forbiddenType?: Set<string>
35
+ ): Promise<INodePropertyOptions[]> {
36
+ const properties = await _getProperties(loader);
37
+
38
+ return properties
39
+ .filter(
40
+ (property) =>
41
+ (!allowedTypes || allowedTypes.has(property.type)) &&
42
+ (!forbiddenType || !forbiddenType.has(property.type))
43
+ )
44
+ .map((property) => ({
45
+ name: (property.localname as string) || (property.name as string),
46
+ value: property.name as string,
47
+ description: `Type: ${property.type as string}${(property.required as boolean) ? ' (Required)' : ''}`,
48
+ }));
49
+ }
50
+
51
+ export async function getLimetypeProperties(
52
+ this: ILoadOptionsFunctions
53
+ ): Promise<INodePropertyOptions[]> {
54
+ return getFilteredLimetypeProperties(this);
55
+ }
56
+
57
+ export async function getFileProperties(
58
+ this: ILoadOptionsFunctions
59
+ ): Promise<INodePropertyOptions[]> {
60
+ return getFilteredLimetypeProperties(this, new Set(['file']));
61
+ }
62
+
63
+ export async function getNoHasManyProperties(
64
+ this: ILoadOptionsFunctions
65
+ ): Promise<INodePropertyOptions[]> {
66
+ return getFilteredLimetypeProperties(this, undefined, new Set(['hasmany']));
67
+ }
@@ -0,0 +1,21 @@
1
+ import { ILoadOptionsFunctions, INodePropertyOptions } from 'n8n-workflow';
2
+ import { getLimetypesFromApi } from '../transport';
3
+
4
+ /**
5
+ * Load available Lime types from the API
6
+ */
7
+ export async function getLimetypes(
8
+ this: ILoadOptionsFunctions
9
+ ): Promise<INodePropertyOptions[]> {
10
+ const data: INodePropertyOptions[] = [];
11
+ const response = await getLimetypesFromApi(this);
12
+ if (response.success && response.data) {
13
+ for (const limetype of response.data) {
14
+ data.push({
15
+ name: limetype.localname?.singular || limetype.name,
16
+ value: limetype.name,
17
+ });
18
+ }
19
+ }
20
+ return data;
21
+ }
@@ -1,3 +1,7 @@
1
1
  export { getEntitiesForErpSystem } from './getEntitiesForErpSystem';
2
- export { getLimeTypes } from './getLimeTypes';
3
- export { getLimeTypeProperties } from './getLimeTypeProperties';
2
+ export { getLimetypes } from './getLimetypes';
3
+ export {
4
+ getFileProperties,
5
+ getLimetypeProperties,
6
+ getNoHasManyProperties,
7
+ } from './getLimetypeProperties';