@limetech/n8n-nodes-lime 2.5.4 → 2.5.5-dev.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/dist/package.json +0 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -2
- package/.github/workflows/lint.yml +0 -23
- package/.github/workflows/mark-stale.yml +0 -21
- package/.github/workflows/release.yml +0 -35
- package/.github/workflows/test-and-build.yml +0 -32
- package/.prettierrc.mjs +0 -1
- package/.releaserc.json +0 -36
- package/Dockerfile +0 -0
- package/eslint.config.mjs +0 -28
- package/jest.config.js +0 -11
- package/knip.json +0 -9
- package/tests/nodes/lime-crm/methods.spec.ts +0 -91
- package/tests/nodes/lime-crm/utils.spec.ts +0 -273
- package/tsconfig.json +0 -30
- package/typedoc.css +0 -9
- package/typedoc.json +0 -19
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@limetech/n8n-nodes-lime",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.5-dev.1",
|
|
4
4
|
"description": "n8n node to connect to Lime CRM",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "nodes/index.ts",
|
|
@@ -40,7 +40,6 @@
|
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@limetech/eslint-config": "^4.0.0",
|
|
42
42
|
"@semantic-release/changelog": "^6.0.3",
|
|
43
|
-
"@semantic-release/exec": "^7.1.0",
|
|
44
43
|
"@semantic-release/git": "^10.0.1",
|
|
45
44
|
"@types/jest": "^30.0.0",
|
|
46
45
|
"@types/node": "^24.10.1",
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
name: Lint
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
pull_request:
|
|
5
|
-
push:
|
|
6
|
-
branches:
|
|
7
|
-
- main
|
|
8
|
-
|
|
9
|
-
jobs:
|
|
10
|
-
lint:
|
|
11
|
-
runs-on: ubuntu-latest
|
|
12
|
-
steps:
|
|
13
|
-
- uses: actions/checkout@v4
|
|
14
|
-
- uses: actions/setup-node@v4
|
|
15
|
-
with:
|
|
16
|
-
node-version: 24
|
|
17
|
-
- run: npm ci
|
|
18
|
-
- name: Run eslint
|
|
19
|
-
run: npm run lint
|
|
20
|
-
- name: Run prettier
|
|
21
|
-
run: npm run format
|
|
22
|
-
- name: Run knip
|
|
23
|
-
run: npm run knip
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
name: 'Mark stale issues and PRs'
|
|
2
|
-
on:
|
|
3
|
-
schedule:
|
|
4
|
-
- cron: '30 1 * * *'
|
|
5
|
-
|
|
6
|
-
permissions:
|
|
7
|
-
actions: write
|
|
8
|
-
issues: write
|
|
9
|
-
pull-requests: write
|
|
10
|
-
|
|
11
|
-
jobs:
|
|
12
|
-
stale:
|
|
13
|
-
runs-on: ubuntu-latest
|
|
14
|
-
steps:
|
|
15
|
-
- uses: actions/stale@v10
|
|
16
|
-
with:
|
|
17
|
-
stale-issue-message: 'This issue is stale because it has been open 30 days with no activity.'
|
|
18
|
-
stale-pr-message: 'This PR is stale because it has been open 30 days with no activity.'
|
|
19
|
-
days-before-stale: 30
|
|
20
|
-
days-before-close: -1
|
|
21
|
-
days-before-pr-close: -1
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
name: Release and Push to NPM Registry
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches:
|
|
6
|
-
- main
|
|
7
|
-
- dev
|
|
8
|
-
- '*[0-9].*[0-9].x'
|
|
9
|
-
- '*[0-9].x.x'
|
|
10
|
-
|
|
11
|
-
jobs:
|
|
12
|
-
release:
|
|
13
|
-
name: Lime N8N Semantic Release
|
|
14
|
-
runs-on: ubuntu-latest
|
|
15
|
-
outputs:
|
|
16
|
-
version: ${{ steps.semantic_release.outputs.version }}
|
|
17
|
-
steps:
|
|
18
|
-
- uses: actions/checkout@v3
|
|
19
|
-
|
|
20
|
-
- uses: actions/setup-node@v3
|
|
21
|
-
with:
|
|
22
|
-
node-version: 24
|
|
23
|
-
|
|
24
|
-
- run: npm ci
|
|
25
|
-
|
|
26
|
-
- name: Semantic release
|
|
27
|
-
id: semantic_release
|
|
28
|
-
run: |
|
|
29
|
-
npx semantic-release
|
|
30
|
-
VERSION=$(cat VERSION)
|
|
31
|
-
echo "Successfully released version: $VERSION"
|
|
32
|
-
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
|
33
|
-
env:
|
|
34
|
-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
35
|
-
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
name: Test and build
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches:
|
|
6
|
-
- main
|
|
7
|
-
pull_request:
|
|
8
|
-
branches:
|
|
9
|
-
- main
|
|
10
|
-
|
|
11
|
-
jobs:
|
|
12
|
-
publish:
|
|
13
|
-
name: Test build
|
|
14
|
-
runs-on: ubuntu-latest
|
|
15
|
-
|
|
16
|
-
steps:
|
|
17
|
-
- name: Checkout code
|
|
18
|
-
uses: actions/checkout@v3
|
|
19
|
-
|
|
20
|
-
- name: Set up Node.js
|
|
21
|
-
uses: actions/setup-node@v3
|
|
22
|
-
with:
|
|
23
|
-
node-version: 24
|
|
24
|
-
|
|
25
|
-
- name: Install dependencies
|
|
26
|
-
run: npm install
|
|
27
|
-
|
|
28
|
-
- name: Build the package
|
|
29
|
-
run: npm run build
|
|
30
|
-
|
|
31
|
-
- name: Run tests
|
|
32
|
-
run: npm run test
|
package/.prettierrc.mjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { default } from '@limetech/eslint-config/prettier.config.js';
|
package/.releaserc.json
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"branches": [
|
|
3
|
-
"main",
|
|
4
|
-
{
|
|
5
|
-
"name": "dev",
|
|
6
|
-
"prerelease": true
|
|
7
|
-
}
|
|
8
|
-
],
|
|
9
|
-
"plugins": [
|
|
10
|
-
"@semantic-release/commit-analyzer",
|
|
11
|
-
"@semantic-release/release-notes-generator",
|
|
12
|
-
[
|
|
13
|
-
"@semantic-release/changelog",
|
|
14
|
-
{
|
|
15
|
-
"changelogFile": "CHANGELOG.md"
|
|
16
|
-
}
|
|
17
|
-
],
|
|
18
|
-
[
|
|
19
|
-
"@semantic-release/git",
|
|
20
|
-
{
|
|
21
|
-
"assets": ["package.json", "CHANGELOG.md"],
|
|
22
|
-
"message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
|
|
23
|
-
}
|
|
24
|
-
],
|
|
25
|
-
[
|
|
26
|
-
"@semantic-release/exec",
|
|
27
|
-
{
|
|
28
|
-
"prepareCmd": "npm run build",
|
|
29
|
-
"successCmd": "echo v${nextRelease.version} > VERSION",
|
|
30
|
-
"__note": "DO NOT CHANGE - this command is used in Release action"
|
|
31
|
-
}
|
|
32
|
-
],
|
|
33
|
-
"@semantic-release/github",
|
|
34
|
-
"@semantic-release/npm"
|
|
35
|
-
]
|
|
36
|
-
}
|
package/Dockerfile
DELETED
|
File without changes
|
package/eslint.config.mjs
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import config from '@limetech/eslint-config';
|
|
2
|
-
|
|
3
|
-
export default [
|
|
4
|
-
...config,
|
|
5
|
-
{
|
|
6
|
-
files: ['**/*.{ts,tsx}'],
|
|
7
|
-
rules: {
|
|
8
|
-
'jsdoc/require-returns': 'off',
|
|
9
|
-
'jsdoc/require-param-description': 'off',
|
|
10
|
-
'jsdoc/require-jsdoc': 'off',
|
|
11
|
-
// N8N prefers the upper camel case for file names
|
|
12
|
-
'unicorn/filename-case': 'off',
|
|
13
|
-
'unicorn/prefer-spread': 'off',
|
|
14
|
-
'no-unused-vars': 'off',
|
|
15
|
-
'@typescript-eslint/no-unused-vars': [
|
|
16
|
-
'warn',
|
|
17
|
-
{
|
|
18
|
-
argsIgnorePattern: '^_',
|
|
19
|
-
varsIgnorePattern: '^_',
|
|
20
|
-
caughtErrorsIgnorePattern: '^_',
|
|
21
|
-
},
|
|
22
|
-
],
|
|
23
|
-
},
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
ignores: ['jest.config.js', 'docs'],
|
|
27
|
-
},
|
|
28
|
-
];
|
package/jest.config.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
testEnvironment: 'node',
|
|
3
|
-
transform: {
|
|
4
|
-
'^.+\\.(ts|tsx)$': ['ts-jest', { tsconfig: 'tsconfig.json' }],
|
|
5
|
-
},
|
|
6
|
-
testMatch: ['**/tests/**/*.spec.ts'],
|
|
7
|
-
verbose: true,
|
|
8
|
-
testTimeout: 20_000,
|
|
9
|
-
testPathIgnorePatterns: ['<rootDir>/dist/'],
|
|
10
|
-
modulePathIgnorePatterns: ['<rootDir>/dist/'],
|
|
11
|
-
};
|
package/knip.json
DELETED
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
getCreateMappingColumns,
|
|
3
|
-
getUpdateMappingColumns,
|
|
4
|
-
LimetypeProperty,
|
|
5
|
-
SuccessResponse,
|
|
6
|
-
} from '../../../nodes';
|
|
7
|
-
import { ILoadOptionsFunctions } from 'n8n-workflow';
|
|
8
|
-
import * as transport from '../../../nodes/lime-crm/transport';
|
|
9
|
-
|
|
10
|
-
const mockILoadOptionFunctions = {
|
|
11
|
-
getNodeParameter: jest.fn().mockReturnValue('company'),
|
|
12
|
-
} as unknown as ILoadOptionsFunctions;
|
|
13
|
-
|
|
14
|
-
const propertiesResponseMock = {
|
|
15
|
-
success: true,
|
|
16
|
-
data: [
|
|
17
|
-
{ name: 'p1', localname: 'Property 1', type: 'yesno', required: true },
|
|
18
|
-
{
|
|
19
|
-
name: 'p2',
|
|
20
|
-
localname: 'Property 2',
|
|
21
|
-
type: 'string',
|
|
22
|
-
required: false,
|
|
23
|
-
length: 2137,
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
name: 'p3',
|
|
27
|
-
localname: 'Property 3',
|
|
28
|
-
type: 'option',
|
|
29
|
-
required: true,
|
|
30
|
-
options: [
|
|
31
|
-
{ key: 'op1', text: 'Option 1', inactive: false },
|
|
32
|
-
{ key: 'op2', text: 'Option 2', inactive: false },
|
|
33
|
-
{ key: 'op3', text: 'Option 3', inactive: true },
|
|
34
|
-
],
|
|
35
|
-
},
|
|
36
|
-
],
|
|
37
|
-
} as SuccessResponse<LimetypeProperty[]>;
|
|
38
|
-
|
|
39
|
-
describe('resourceMapping', () => {
|
|
40
|
-
beforeEach(() => {
|
|
41
|
-
jest.spyOn(transport, 'getProperties').mockResolvedValue(
|
|
42
|
-
propertiesResponseMock
|
|
43
|
-
);
|
|
44
|
-
});
|
|
45
|
-
it('gets valid resource mapping for create', async () => {
|
|
46
|
-
const columns = await getCreateMappingColumns.call(
|
|
47
|
-
mockILoadOptionFunctions
|
|
48
|
-
);
|
|
49
|
-
const property1 = columns.fields.find((p) => p.id == 'p1')!;
|
|
50
|
-
|
|
51
|
-
expect(property1.displayName).toBe('Property 1 [yesno]');
|
|
52
|
-
expect(property1.required).toBe(true);
|
|
53
|
-
expect(property1.defaultMatch).toBe(false);
|
|
54
|
-
expect(property1.display).toBe(true);
|
|
55
|
-
expect(property1.type).toBe('boolean');
|
|
56
|
-
expect(property1.options).toBe(undefined);
|
|
57
|
-
|
|
58
|
-
const property2 = columns.fields.find((p) => p.id == 'p2')!;
|
|
59
|
-
expect(property2.displayName).toBe('Property 2 [string(2137)]');
|
|
60
|
-
expect(property2.required).toBe(false);
|
|
61
|
-
expect(property2.defaultMatch).toBe(false);
|
|
62
|
-
expect(property2.display).toBe(true);
|
|
63
|
-
expect(property2.type).toBe('string');
|
|
64
|
-
expect(property2.options).toBe(undefined);
|
|
65
|
-
|
|
66
|
-
const property3 = columns.fields.find((p) => p.id == 'p3')!;
|
|
67
|
-
expect(property3.displayName).toBe('Property 3 [option]');
|
|
68
|
-
expect(property3.required).toBe(true);
|
|
69
|
-
expect(property3.defaultMatch).toBe(false);
|
|
70
|
-
expect(property3.display).toBe(true);
|
|
71
|
-
expect(property3.type).toBe('options');
|
|
72
|
-
|
|
73
|
-
const options = property3.options!;
|
|
74
|
-
expect(options).toContainEqual({
|
|
75
|
-
value: 'op1',
|
|
76
|
-
name: 'Option 1',
|
|
77
|
-
});
|
|
78
|
-
expect(options).toContainEqual({
|
|
79
|
-
value: 'op2',
|
|
80
|
-
name: 'Option 2',
|
|
81
|
-
});
|
|
82
|
-
expect(options.length).toBe(2);
|
|
83
|
-
});
|
|
84
|
-
it('gets proper required values for update', async () => {
|
|
85
|
-
const columns = await getUpdateMappingColumns.call(
|
|
86
|
-
mockILoadOptionFunctions
|
|
87
|
-
);
|
|
88
|
-
const requiredValues = columns.fields.map((p) => p.required);
|
|
89
|
-
expect(requiredValues).toEqual([false, false, false]);
|
|
90
|
-
});
|
|
91
|
-
});
|
|
@@ -1,273 +0,0 @@
|
|
|
1
|
-
jest.mock('../../../nodes/lime-crm/transport', () => ({
|
|
2
|
-
createFile: jest.fn().mockResolvedValue({
|
|
3
|
-
success: true,
|
|
4
|
-
data: { id: 1 },
|
|
5
|
-
}),
|
|
6
|
-
getFileMetadata: jest.fn().mockResolvedValue({
|
|
7
|
-
success: true,
|
|
8
|
-
data: {
|
|
9
|
-
id: '123',
|
|
10
|
-
name: 'file.txt',
|
|
11
|
-
},
|
|
12
|
-
}),
|
|
13
|
-
getFileContent: jest.fn().mockResolvedValue({
|
|
14
|
-
success: true,
|
|
15
|
-
data: 'some binary data',
|
|
16
|
-
}),
|
|
17
|
-
getTasks: jest.fn(),
|
|
18
|
-
}));
|
|
19
|
-
|
|
20
|
-
import {
|
|
21
|
-
createFile,
|
|
22
|
-
getFileContent,
|
|
23
|
-
getFileMetadata,
|
|
24
|
-
getFilenameFromHeader,
|
|
25
|
-
getFilePropertiesNames,
|
|
26
|
-
getWebhook,
|
|
27
|
-
processFileResponse,
|
|
28
|
-
setFilename,
|
|
29
|
-
setFileProperties,
|
|
30
|
-
verifyHmac,
|
|
31
|
-
WebhookFunctions,
|
|
32
|
-
} from '../../../nodes';
|
|
33
|
-
|
|
34
|
-
describe('files', () => {
|
|
35
|
-
describe('setFilename', () => {
|
|
36
|
-
it('returns responseFileName if fileName is missing', () => {
|
|
37
|
-
expect(
|
|
38
|
-
setFilename({ fileExtension: 'jpg' } as any, 'default.jpg')
|
|
39
|
-
).toBe('default.jpg');
|
|
40
|
-
});
|
|
41
|
-
it('returns existing fileName if present', () => {
|
|
42
|
-
expect(
|
|
43
|
-
setFilename({ fileName: 'aspen.jpg' } as any, 'default.jpg')
|
|
44
|
-
).toBe('aspen.jpg');
|
|
45
|
-
});
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
describe('getFilenameFromHeader', () => {
|
|
49
|
-
it('returns null if header is missing', () => {
|
|
50
|
-
expect(getFilenameFromHeader({})).toBeNull();
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
it('parses standard filename', () => {
|
|
54
|
-
expect(
|
|
55
|
-
getFilenameFromHeader({
|
|
56
|
-
'content-disposition': 'attachment; filename="test.txt"',
|
|
57
|
-
})
|
|
58
|
-
).toBe('test.txt');
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it('parses RFC 5987 filename*', () => {
|
|
62
|
-
expect(
|
|
63
|
-
getFilenameFromHeader({
|
|
64
|
-
'content-disposition':
|
|
65
|
-
"attachment; filename*=UTF-8''test%20file.txt",
|
|
66
|
-
})
|
|
67
|
-
).toBe('test file.txt');
|
|
68
|
-
});
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
describe('getFilePropertiesNames', () => {
|
|
72
|
-
const limetypes = [
|
|
73
|
-
{
|
|
74
|
-
name: 'company',
|
|
75
|
-
type: 'belongsto',
|
|
76
|
-
localname: 'company',
|
|
77
|
-
required: false,
|
|
78
|
-
},
|
|
79
|
-
{
|
|
80
|
-
name: 'name',
|
|
81
|
-
type: 'string',
|
|
82
|
-
localname: 'name',
|
|
83
|
-
required: false,
|
|
84
|
-
},
|
|
85
|
-
{
|
|
86
|
-
name: 'document',
|
|
87
|
-
type: 'file',
|
|
88
|
-
localname: 'document',
|
|
89
|
-
required: false,
|
|
90
|
-
},
|
|
91
|
-
{
|
|
92
|
-
name: 'photo',
|
|
93
|
-
type: 'file',
|
|
94
|
-
localname: 'photo',
|
|
95
|
-
required: false,
|
|
96
|
-
},
|
|
97
|
-
];
|
|
98
|
-
it('returns all file property names', async () => {
|
|
99
|
-
const result = getFilePropertiesNames(limetypes);
|
|
100
|
-
expect(result.has('document')).toBe(true);
|
|
101
|
-
expect(result.has('photo')).toBe(true);
|
|
102
|
-
expect(result.has('name')).toBe(false);
|
|
103
|
-
expect(result.has('company')).toBe(false);
|
|
104
|
-
});
|
|
105
|
-
it('returns allowed file property names', async () => {
|
|
106
|
-
const result = getFilePropertiesNames(
|
|
107
|
-
limetypes,
|
|
108
|
-
new Set(['document'])
|
|
109
|
-
);
|
|
110
|
-
expect(result.has('document')).toBe(true);
|
|
111
|
-
expect(result.has('photo')).toBe(false);
|
|
112
|
-
expect(result.has('name')).toBe(false);
|
|
113
|
-
expect(result.has('company')).toBe(false);
|
|
114
|
-
});
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
describe('setFileProperties', () => {
|
|
118
|
-
const mockContext: any = {
|
|
119
|
-
helpers: {
|
|
120
|
-
assertBinaryData: jest.fn(),
|
|
121
|
-
},
|
|
122
|
-
};
|
|
123
|
-
const mockBinaryData = { data: 'some binary data' };
|
|
124
|
-
|
|
125
|
-
beforeEach(() => {
|
|
126
|
-
(createFile as jest.Mock).mockClear();
|
|
127
|
-
mockContext.helpers.assertBinaryData.mockClear();
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
it('sets file properties successfully', async () => {
|
|
131
|
-
mockContext.helpers.assertBinaryData.mockReturnValue(
|
|
132
|
-
mockBinaryData
|
|
133
|
-
);
|
|
134
|
-
|
|
135
|
-
const definedProperties = { document: 'some binary data' };
|
|
136
|
-
const result = await setFileProperties(
|
|
137
|
-
mockContext,
|
|
138
|
-
0,
|
|
139
|
-
new Set(['document']),
|
|
140
|
-
definedProperties
|
|
141
|
-
);
|
|
142
|
-
expect(result.success).toBe(true);
|
|
143
|
-
if (result.success) {
|
|
144
|
-
expect(result.data.document).toBe(1);
|
|
145
|
-
}
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
it('sets file ID if assertBinaryData throws an error', async () => {
|
|
149
|
-
mockContext.helpers.assertBinaryData.mockImplementation(() => {
|
|
150
|
-
throw new Error('Invalid binary data');
|
|
151
|
-
});
|
|
152
|
-
const definedProperties = { document: 2 };
|
|
153
|
-
const result = await setFileProperties(
|
|
154
|
-
mockContext,
|
|
155
|
-
0,
|
|
156
|
-
new Set(['document']),
|
|
157
|
-
definedProperties
|
|
158
|
-
);
|
|
159
|
-
expect(result.success).toBe(true);
|
|
160
|
-
if (result.success) {
|
|
161
|
-
expect(result.data.document).toBe(2);
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
describe('processFileResponse', () => {
|
|
167
|
-
const mockNodeContext = {};
|
|
168
|
-
|
|
169
|
-
beforeEach(() => {
|
|
170
|
-
(getFileMetadata as jest.Mock).mockClear();
|
|
171
|
-
(getFileContent as jest.Mock).mockClear();
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
it('returns file metadata without file content', async () => {
|
|
175
|
-
const data = { document: 1 };
|
|
176
|
-
const result = await processFileResponse<{ document: number }>(
|
|
177
|
-
mockNodeContext as any,
|
|
178
|
-
new Set(['document']),
|
|
179
|
-
data
|
|
180
|
-
);
|
|
181
|
-
expect(result.json.success).toBe(true);
|
|
182
|
-
if (result.json.success) {
|
|
183
|
-
expect(result.json.data.document).toEqual({
|
|
184
|
-
id: '123',
|
|
185
|
-
name: 'file.txt',
|
|
186
|
-
});
|
|
187
|
-
expect(result.binary).toEqual({});
|
|
188
|
-
}
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
it('returns file metadata with file content', async () => {
|
|
192
|
-
const data = { document: 1 };
|
|
193
|
-
const result = await processFileResponse<{ document: number }>(
|
|
194
|
-
mockNodeContext as any,
|
|
195
|
-
new Set(['document']),
|
|
196
|
-
data,
|
|
197
|
-
true
|
|
198
|
-
);
|
|
199
|
-
if (result.json.success) {
|
|
200
|
-
expect(result.json.data.document).toEqual({
|
|
201
|
-
id: '123',
|
|
202
|
-
name: 'file.txt',
|
|
203
|
-
});
|
|
204
|
-
expect(result.binary?.document).toEqual('some binary data');
|
|
205
|
-
}
|
|
206
|
-
});
|
|
207
|
-
});
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
describe('hmac', () => {
|
|
211
|
-
describe('verifyHmac', () => {
|
|
212
|
-
const key = 'my-secret-key';
|
|
213
|
-
const data = Buffer.from('hello world');
|
|
214
|
-
const correctHmac =
|
|
215
|
-
'sha256=90eb182d8396f16d4341d582047f45c0a97d73388c5377d9ced478a2212295ad';
|
|
216
|
-
|
|
217
|
-
it('returns true when the HMAC matches', () => {
|
|
218
|
-
expect(verifyHmac(key, data, correctHmac)).toBe(true);
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
it('returns false when the HMAC does not match', () => {
|
|
222
|
-
expect(verifyHmac(key, data, 'wrongHmac')).toBe(false);
|
|
223
|
-
});
|
|
224
|
-
});
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
describe('webhook', () => {
|
|
228
|
-
describe('getWebhhok', () => {
|
|
229
|
-
let mockHookData: jest.Mocked<WebhookFunctions>;
|
|
230
|
-
|
|
231
|
-
beforeEach(() => {
|
|
232
|
-
jest.useFakeTimers().setSystemTime(
|
|
233
|
-
new Date('2025-11-12T12:00:00Z')
|
|
234
|
-
);
|
|
235
|
-
mockHookData = {
|
|
236
|
-
getNode: jest.fn().mockReturnValue({ id: '1', name: 'MyNode' }),
|
|
237
|
-
getWorkflow: jest
|
|
238
|
-
.fn()
|
|
239
|
-
.mockReturnValue({ id: '2', name: 'MyWorkflow' }),
|
|
240
|
-
getWorkflowStaticData: jest
|
|
241
|
-
.fn()
|
|
242
|
-
.mockReturnValue({ key: 'value' }),
|
|
243
|
-
getNodeWebhookUrl: jest
|
|
244
|
-
.fn()
|
|
245
|
-
.mockReturnValue('https://example.com/hook'),
|
|
246
|
-
getNodeParameter: jest.fn().mockReturnValue({
|
|
247
|
-
event: [{ limetype: 'company', eventType: 'new' }],
|
|
248
|
-
}),
|
|
249
|
-
} as unknown as jest.Mocked<WebhookFunctions>;
|
|
250
|
-
});
|
|
251
|
-
|
|
252
|
-
afterEach(() => {
|
|
253
|
-
jest.useRealTimers();
|
|
254
|
-
});
|
|
255
|
-
|
|
256
|
-
it('constructs a full webhook object correctly', () => {
|
|
257
|
-
const result = getWebhook(mockHookData);
|
|
258
|
-
|
|
259
|
-
expect(result).toEqual({
|
|
260
|
-
data: { key: 'value' },
|
|
261
|
-
events: ['company.new'],
|
|
262
|
-
url: 'https://example.com/hook',
|
|
263
|
-
context: {
|
|
264
|
-
nodeId: '1',
|
|
265
|
-
nodeName: 'MyNode',
|
|
266
|
-
workflowId: '2',
|
|
267
|
-
workflowName: 'MyWorkflow',
|
|
268
|
-
},
|
|
269
|
-
name: 'company-new-1762948800000',
|
|
270
|
-
});
|
|
271
|
-
});
|
|
272
|
-
});
|
|
273
|
-
});
|
package/tsconfig.json
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"strict": true,
|
|
4
|
-
"module": "commonjs",
|
|
5
|
-
"moduleResolution": "node",
|
|
6
|
-
"target": "es2019",
|
|
7
|
-
"lib": ["es2019", "es2020", "es2022"],
|
|
8
|
-
"removeComments": true,
|
|
9
|
-
"useUnknownInCatchVariables": false,
|
|
10
|
-
"forceConsistentCasingInFileNames": true,
|
|
11
|
-
"noImplicitAny": true,
|
|
12
|
-
"noImplicitReturns": true,
|
|
13
|
-
"noUnusedLocals": true,
|
|
14
|
-
"strictNullChecks": true,
|
|
15
|
-
"preserveConstEnums": true,
|
|
16
|
-
"esModuleInterop": true,
|
|
17
|
-
"resolveJsonModule": true,
|
|
18
|
-
"incremental": true,
|
|
19
|
-
"declaration": true,
|
|
20
|
-
"sourceMap": true,
|
|
21
|
-
"skipLibCheck": true,
|
|
22
|
-
"outDir": "./dist/"
|
|
23
|
-
},
|
|
24
|
-
"include": [
|
|
25
|
-
"credentials/**/*",
|
|
26
|
-
"nodes/**/*",
|
|
27
|
-
"nodes/**/*.json",
|
|
28
|
-
"package.json"
|
|
29
|
-
]
|
|
30
|
-
}
|
package/typedoc.css
DELETED
package/typedoc.json
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://typedoc.org/schema.json",
|
|
3
|
-
"entryPoints": [
|
|
4
|
-
"./nodes/lime-crm/index.ts",
|
|
5
|
-
"./nodes/response.ts",
|
|
6
|
-
"./credentials/index.ts"
|
|
7
|
-
],
|
|
8
|
-
"entryPointStrategy": "expand",
|
|
9
|
-
"name": "Lime N8N Documentation",
|
|
10
|
-
"customCss": "typedoc.css",
|
|
11
|
-
"out": "docs",
|
|
12
|
-
"includeVersion": true,
|
|
13
|
-
"readme": "README.md",
|
|
14
|
-
"tsconfig": "tsconfig.json",
|
|
15
|
-
"disableSources": true,
|
|
16
|
-
"hideGenerator": true,
|
|
17
|
-
"categorizeByGroup": true,
|
|
18
|
-
"cleanOutputDir": true
|
|
19
|
-
}
|