n8n-nodes-version 0.2.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/README.md ADDED
@@ -0,0 +1,80 @@
1
+ # n8n-version-node
2
+
3
+ > [!NOTE]
4
+ > [n8n](https://n8n.io/) is a [fair-code licensed](https://docs.n8n.io/reference/license/) workflow automation platform.
5
+ >
6
+ > [Icon](https://icons8.com/icon/9sDRgODM0vNc/refresh) is from [icons8.com](https://icons8.com/)
7
+
8
+ ## Features
9
+
10
+ - Check current installed n8n version
11
+ - Fetch latest version from [npm](https://www.npmjs.com/package/n8n)
12
+ - Compare versions and determine if current is latest
13
+ - Fetch release notes from GitHub
14
+ - Trigger workflows based on version status
15
+
16
+ ## Nodes
17
+
18
+ ### Version Checker
19
+
20
+ Checks the current n8n version and provides various options:
21
+
22
+ **Options:**
23
+
24
+ - **Return Latest Version Info** (default: `true`): Fetches latest version from npm and compares with current
25
+ - **Fetch Changelog** (default: `false`): Retrieves release notes from GitHub
26
+ - **Changelog Version**: Choose between current or latest version
27
+ - **Strip Links from Changelog**: Remove markdown links from changelog text
28
+
29
+ **Output Example:**
30
+
31
+ ```json
32
+ {
33
+ "currentVersion": "1.0.0",
34
+ "latestVersion": "1.1.0",
35
+ "isLatest": false,
36
+ "changelog": "## Bug Fixes\n- Fixed issue with...",
37
+ "changelogVersion": "1.1.0"
38
+ }
39
+ ```
40
+
41
+ ### Version Trigger
42
+
43
+ Triggers workflows based on n8n version status using cron scheduling.
44
+
45
+ **Properties:**
46
+
47
+ - **Cron Expression**: Schedule for version checks (e.g., `0 * * * *` for hourly)
48
+ - **Trigger Condition**:
49
+ - **Update Available**: Trigger when new version exists
50
+ - **On Latest Version**: Trigger when already up-to-date
51
+ - **Always**: Trigger on every check
52
+
53
+ **Use Cases:**
54
+
55
+ - Automated update notifications
56
+ - Monitoring version status
57
+ - Scheduled version audits
58
+
59
+ ## Installation
60
+
61
+ ```bash
62
+ npm install n8n-nodes-version
63
+ ```
64
+
65
+ ## Development
66
+
67
+ ```bash
68
+ # Watch mode
69
+ npm run dev
70
+
71
+ # Build
72
+ npm run build
73
+
74
+ # Lint
75
+ npm run lint
76
+ ```
77
+
78
+ ## License
79
+
80
+ MIT
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ // This file is essentially empty in the project provided, but typically would contain exports.
3
+ // If n8n looks for an entry point, it usually just scans package.json 'n8n' field.
4
+ // However, 'main' is set to 'dist/index.js', so we should ensure source exists if tsconfig expects it.
5
+ // Since tsconfig rootDir is ./, we should create an index.ts if it doesn't exist, or just rely on nodes.
6
+ // But to be safe and clean, let's create a simple index.ts that exports nothing or acts as placeholder.
@@ -0,0 +1,178 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.N8nChangelog = void 0;
7
+ const https_1 = __importDefault(require("https"));
8
+ /**
9
+ * Fetch changelog from GitHub releases
10
+ */
11
+ function getChangelog(version) {
12
+ return new Promise((resolve) => {
13
+ try {
14
+ const options = {
15
+ hostname: 'api.github.com',
16
+ path: `/repos/n8n-io/n8n/releases/tags/n8n@${version}`,
17
+ headers: {
18
+ 'User-Agent': 'n8n-changelog-node',
19
+ },
20
+ };
21
+ https_1.default
22
+ .get(options, (res) => {
23
+ let data = '';
24
+ res.on('data', (chunk) => (data += chunk));
25
+ res.on('end', () => {
26
+ try {
27
+ if (res.statusCode === 404) {
28
+ resolve({ body: '', error: `Release n8n@${version} not found` });
29
+ return;
30
+ }
31
+ if (res.statusCode !== 200) {
32
+ resolve({ body: '', error: `GitHub API returned status ${res.statusCode}` });
33
+ return;
34
+ }
35
+ const parsed = JSON.parse(data);
36
+ resolve({ body: parsed.body || '' });
37
+ }
38
+ catch (err) {
39
+ console.error('[Changelog] Failed to parse GitHub response:', err);
40
+ resolve({ body: '', error: 'Failed to parse GitHub response' });
41
+ }
42
+ });
43
+ })
44
+ .on('error', (err) => {
45
+ console.error('[Changelog] Failed to fetch from GitHub:', err);
46
+ resolve({ body: '', error: `Failed to fetch from GitHub: ${err.message}` });
47
+ });
48
+ }
49
+ catch (err) {
50
+ console.error('[Changelog] Unexpected error:', err);
51
+ resolve({ body: '', error: `Unexpected error: ${err}` });
52
+ }
53
+ });
54
+ }
55
+ /**
56
+ * Strip markdown links from text
57
+ */
58
+ function stripMarkdownLinks(text) {
59
+ return text.replace(/\[([^\]]+)\]\([^\)]+\)/g, '$1');
60
+ }
61
+ class N8nChangelog {
62
+ constructor() {
63
+ this.description = {
64
+ displayName: 'n8n Changelog',
65
+ name: 'n8nChangelog',
66
+ icon: 'file:n8n-version.svg',
67
+ group: ['transform'],
68
+ version: 1,
69
+ description: 'Fetches changelog for a specific n8n version from GitHub',
70
+ defaults: {
71
+ name: 'n8n Changelog',
72
+ },
73
+ inputs: ['main'],
74
+ outputs: ['main'],
75
+ properties: [
76
+ {
77
+ displayName: 'Version Source',
78
+ name: 'versionSource',
79
+ type: 'options',
80
+ options: [
81
+ {
82
+ name: 'From Parameter',
83
+ value: 'parameter',
84
+ },
85
+ {
86
+ name: 'From Input',
87
+ value: 'input',
88
+ },
89
+ ],
90
+ default: 'parameter',
91
+ description: 'Where to get the version from',
92
+ },
93
+ {
94
+ displayName: 'Version',
95
+ name: 'version',
96
+ type: 'string',
97
+ default: '',
98
+ placeholder: '1.0.0',
99
+ description: 'The n8n version to fetch changelog for (e.g., "1.0.0")',
100
+ displayOptions: {
101
+ show: {
102
+ versionSource: ['parameter'],
103
+ },
104
+ },
105
+ },
106
+ {
107
+ displayName: 'Version Field',
108
+ name: 'versionField',
109
+ type: 'string',
110
+ default: 'latestVersion',
111
+ description: 'The field name containing the version in input data',
112
+ displayOptions: {
113
+ show: {
114
+ versionSource: ['input'],
115
+ },
116
+ },
117
+ },
118
+ {
119
+ displayName: 'Include Links',
120
+ name: 'includeLinks',
121
+ type: 'boolean',
122
+ default: true,
123
+ description: 'Whether to keep markdown links in the changelog text',
124
+ },
125
+ ],
126
+ };
127
+ }
128
+ async execute() {
129
+ const items = this.getInputData();
130
+ const returnData = [];
131
+ for (let i = 0; i < items.length; i++) {
132
+ try {
133
+ const versionSource = this.getNodeParameter('versionSource', i);
134
+ const includeLinks = this.getNodeParameter('includeLinks', i);
135
+ let version;
136
+ if (versionSource === 'input') {
137
+ const versionField = this.getNodeParameter('versionField', i);
138
+ version = items[i].json[versionField];
139
+ }
140
+ else {
141
+ version = this.getNodeParameter('version', i);
142
+ }
143
+ if (!version) {
144
+ returnData.push({
145
+ json: {
146
+ error: 'No version provided',
147
+ changelog: '',
148
+ },
149
+ });
150
+ continue;
151
+ }
152
+ const { body, error } = await getChangelog(version);
153
+ let changelog = body;
154
+ if (!includeLinks && changelog) {
155
+ changelog = stripMarkdownLinks(changelog);
156
+ }
157
+ returnData.push({
158
+ json: {
159
+ version,
160
+ changelog,
161
+ error: error || undefined,
162
+ },
163
+ });
164
+ }
165
+ catch (err) {
166
+ console.error('[Changelog] Error processing item:', err);
167
+ returnData.push({
168
+ json: {
169
+ error: `Failed to process: ${err}`,
170
+ changelog: '',
171
+ },
172
+ });
173
+ }
174
+ }
175
+ return [returnData];
176
+ }
177
+ }
178
+ exports.N8nChangelog = N8nChangelog;
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0,0,256,256" width="256px" height="256px" fill-rule="nonzero"><g fill="#f188a2" fill-rule="nonzero" stroke="none" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="10" stroke-dasharray="" stroke-dashoffset="0" font-family="none" font-weight="none" font-size="none" text-anchor="none" style="mix-blend-mode: normal"><g transform="scale(5.12,5.12)"><path d="M20,3c-5.514,0 -10,4.486 -10,10v20.17188l-3.58594,-3.58594c-0.37701,-0.38755 -0.89487,-0.60597 -1.43555,-0.60547c-0.81349,0.00101 -1.54533,0.49459 -1.85108,1.24844c-0.30574,0.75385 -0.12447,1.61777 0.4585,2.18515l7,7c0.78106,0.78074 2.04706,0.78074 2.82812,0l7,-7c0.52248,-0.50163 0.73295,-1.24653 0.55024,-1.94742c-0.18271,-0.70088 -0.73006,-1.24823 -1.43094,-1.43094c-0.70088,-0.18271 -1.44578,0.02776 -1.94742,0.55024l-3.58594,3.58594v-20.17187c0,-3.309 2.691,-6 6,-6h10.46875l0.26563,-4zM37.9707,10c-0.52023,0.00778 -1.01695,0.21796 -1.38477,0.58594l-7,7c-0.52248,0.50163 -0.73295,1.24653 -0.55024,1.94742c0.18271,0.70088 0.73006,1.24823 1.43094,1.43094c0.70088,0.18271 1.44578,-0.02776 1.94742,-0.55024l3.58594,-3.58594v20.17188c0,3.309 -2.691,6 -6,6h-10.49023l-0.25391,4h10.74414c5.514,0 10,-4.486 10,-10v-20.17187l3.58594,3.58594c0.50163,0.52248 1.24653,0.73295 1.94742,0.55024c0.70088,-0.18271 1.24823,-0.73006 1.43094,-1.43094c0.18271,-0.70088 -0.02776,-1.44578 -0.55024,-1.94742l-7,-7c-0.38217,-0.38233 -0.90283,-0.5937 -1.44336,-0.58594z"></path></g></g></svg>
@@ -0,0 +1,158 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.N8nVersion = void 0;
4
+ const n8n_workflow_1 = require("n8n-workflow");
5
+ const VersionUtils_1 = require("../VersionUtils");
6
+ class N8nVersion {
7
+ constructor() {
8
+ this.description = {
9
+ displayName: 'Version Checker',
10
+ name: 'versionChecker',
11
+ icon: 'file:n8n-version.svg',
12
+ group: ['transform'],
13
+ version: 1,
14
+ description: 'Check current n8n version and optionally fetch changelog from GitHub',
15
+ defaults: {
16
+ name: 'Version Checker',
17
+ },
18
+ inputs: ['main'],
19
+ outputs: ['main'],
20
+ properties: [
21
+ {
22
+ displayName: 'Options',
23
+ name: 'options',
24
+ type: 'collection',
25
+ placeholder: 'Add Option',
26
+ default: {},
27
+ options: [
28
+ {
29
+ displayName: 'Return Latest Version Info',
30
+ name: 'returnIsLatest',
31
+ type: 'boolean',
32
+ default: true,
33
+ description: 'Whether to check and return if the current version is the latest available on npm',
34
+ },
35
+ {
36
+ displayName: 'Fetch Changelog',
37
+ name: 'fetchChangelog',
38
+ type: 'boolean',
39
+ default: false,
40
+ description: 'Whether to fetch release notes from GitHub. Note: Subject to GitHub API rate limits.',
41
+ },
42
+ {
43
+ displayName: 'Changelog Version',
44
+ name: 'changelogVersion',
45
+ type: 'options',
46
+ default: 'latest',
47
+ description: 'Which version to fetch the changelog for',
48
+ displayOptions: {
49
+ show: {
50
+ fetchChangelog: [true],
51
+ },
52
+ },
53
+ options: [
54
+ {
55
+ name: 'Latest Version',
56
+ value: 'latest',
57
+ description: 'Fetch changelog for the latest version from npm',
58
+ },
59
+ {
60
+ name: 'Current Version',
61
+ value: 'current',
62
+ description: 'Fetch changelog for the currently installed version',
63
+ },
64
+ ],
65
+ },
66
+ {
67
+ displayName: 'Strip Links from Changelog',
68
+ name: 'stripLinks',
69
+ type: 'boolean',
70
+ default: false,
71
+ description: 'Whether to remove markdown links from the changelog text',
72
+ displayOptions: {
73
+ show: {
74
+ fetchChangelog: [true],
75
+ },
76
+ },
77
+ },
78
+ ],
79
+ },
80
+ ],
81
+ };
82
+ }
83
+ async execute() {
84
+ const items = this.getInputData();
85
+ const returnData = [];
86
+ for (let i = 0; i < items.length; i++) {
87
+ try {
88
+ const options = this.getNodeParameter('options', i, {});
89
+ const returnIsLatest = options.returnIsLatest !== false;
90
+ const fetchChangelog = options.fetchChangelog === true;
91
+ const changelogVersion = options.changelogVersion || 'latest';
92
+ const stripLinks = options.stripLinks === true;
93
+ const json = {};
94
+ if (returnIsLatest) {
95
+ const versions = await (0, VersionUtils_1.checkIsLatest)();
96
+ json.currentVersion = versions.currentVersion;
97
+ json.latestVersion = versions.latestVersion;
98
+ json.isLatest = versions.isLatest;
99
+ if (versions.error) {
100
+ json.versionError = versions.error;
101
+ }
102
+ }
103
+ else {
104
+ json.currentVersion = (0, VersionUtils_1.getCurrentN8nVersion)();
105
+ }
106
+ if (fetchChangelog) {
107
+ let versionToFetch;
108
+ if (changelogVersion === 'latest') {
109
+ if (returnIsLatest && json.latestVersion) {
110
+ versionToFetch = json.latestVersion;
111
+ }
112
+ else {
113
+ const latestVersion = await (0, VersionUtils_1.getLatestN8nVersion)();
114
+ versionToFetch = latestVersion;
115
+ }
116
+ }
117
+ else {
118
+ versionToFetch = json.currentVersion;
119
+ }
120
+ if (versionToFetch && versionToFetch !== 'unknown') {
121
+ const changelogInfo = await (0, VersionUtils_1.getChangelog)(versionToFetch);
122
+ let changelog = (0, VersionUtils_1.cleanChangelog)(changelogInfo.changelog);
123
+ if (stripLinks && changelog) {
124
+ changelog = (0, VersionUtils_1.stripMarkdownLinks)(changelog);
125
+ }
126
+ json.changelog = changelog;
127
+ json.changelogVersion = changelogInfo.version;
128
+ if (changelogInfo.error) {
129
+ json.changelogError = changelogInfo.error;
130
+ }
131
+ }
132
+ else {
133
+ json.changelogError = 'Unable to determine version for changelog fetch';
134
+ }
135
+ }
136
+ returnData.push({
137
+ json,
138
+ pairedItem: { item: i },
139
+ });
140
+ }
141
+ catch (error) {
142
+ if (this.continueOnFail()) {
143
+ returnData.push({
144
+ json: {
145
+ error: error instanceof Error ? error.message : String(error),
146
+ },
147
+ pairedItem: { item: i },
148
+ });
149
+ continue;
150
+ }
151
+ const errorMessage = error instanceof Error ? error.message : String(error);
152
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to process version information: ${errorMessage}`, { itemIndex: i });
153
+ }
154
+ }
155
+ return [returnData];
156
+ }
157
+ }
158
+ exports.N8nVersion = N8nVersion;
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0,0,256,256" width="256px" height="256px" fill-rule="nonzero"><g fill="#f188a2" fill-rule="nonzero" stroke="none" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="10" stroke-dasharray="" stroke-dashoffset="0" font-family="none" font-weight="none" font-size="none" text-anchor="none" style="mix-blend-mode: normal"><g transform="scale(5.12,5.12)"><path d="M20,3c-5.514,0 -10,4.486 -10,10v20.17188l-3.58594,-3.58594c-0.37701,-0.38755 -0.89487,-0.60597 -1.43555,-0.60547c-0.81349,0.00101 -1.54533,0.49459 -1.85108,1.24844c-0.30574,0.75385 -0.12447,1.61777 0.4585,2.18515l7,7c0.78106,0.78074 2.04706,0.78074 2.82812,0l7,-7c0.52248,-0.50163 0.73295,-1.24653 0.55024,-1.94742c-0.18271,-0.70088 -0.73006,-1.24823 -1.43094,-1.43094c-0.70088,-0.18271 -1.44578,0.02776 -1.94742,0.55024l-3.58594,3.58594v-20.17187c0,-3.309 2.691,-6 6,-6h10.46875l0.26563,-4zM37.9707,10c-0.52023,0.00778 -1.01695,0.21796 -1.38477,0.58594l-7,7c-0.52248,0.50163 -0.73295,1.24653 -0.55024,1.94742c0.18271,0.70088 0.73006,1.24823 1.43094,1.43094c0.70088,0.18271 1.44578,-0.02776 1.94742,-0.55024l3.58594,-3.58594v20.17188c0,3.309 -2.691,6 -6,6h-10.49023l-0.25391,4h10.74414c5.514,0 10,-4.486 10,-10v-20.17187l3.58594,3.58594c0.50163,0.52248 1.24653,0.73295 1.94742,0.55024c0.70088,-0.18271 1.24823,-0.73006 1.43094,-1.43094c0.18271,-0.70088 -0.02776,-1.44578 -0.55024,-1.94742l-7,-7c-0.38217,-0.38233 -0.90283,-0.5937 -1.44336,-0.58594z"></path></g></g></svg>
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.N8nVersionTrigger = void 0;
4
+ const n8n_workflow_1 = require("n8n-workflow");
5
+ const cron_1 = require("cron");
6
+ const VersionUtils_1 = require("../VersionUtils");
7
+ class N8nVersionTrigger {
8
+ constructor() {
9
+ this.description = {
10
+ displayName: 'Version Trigger',
11
+ name: 'versionTrigger',
12
+ icon: 'file:n8n-version.svg',
13
+ group: ['trigger'],
14
+ version: 1,
15
+ description: 'Triggers workflow based on n8n version status using cron schedule',
16
+ defaults: {
17
+ name: 'Version Trigger',
18
+ },
19
+ inputs: [],
20
+ outputs: ['main'],
21
+ properties: [
22
+ {
23
+ displayName: 'Cron Expression',
24
+ name: 'cronExpression',
25
+ type: 'string',
26
+ default: '0 * * * *',
27
+ required: true,
28
+ placeholder: '0 * * * *',
29
+ description: 'Cron expression for when to check version. Examples: "0 * * * *" (hourly), "0 0 * * *" (daily), "0 0 * * 0" (weekly).',
30
+ },
31
+ {
32
+ displayName: 'Trigger Condition',
33
+ name: 'triggerCondition',
34
+ type: 'options',
35
+ default: 'update',
36
+ required: true,
37
+ description: 'When should the workflow be triggered',
38
+ options: [
39
+ {
40
+ name: 'Update Available',
41
+ value: 'update',
42
+ description: 'Trigger only when a new version is available',
43
+ },
44
+ {
45
+ name: 'On Latest Version',
46
+ value: 'latest',
47
+ description: 'Trigger only when already on the latest version',
48
+ },
49
+ {
50
+ name: 'Always',
51
+ value: 'always',
52
+ description: 'Trigger on every check regardless of version status',
53
+ },
54
+ ],
55
+ },
56
+ ],
57
+ };
58
+ }
59
+ async trigger() {
60
+ const cronExpression = this.getNodeParameter('cronExpression');
61
+ const triggerCondition = this.getNodeParameter('triggerCondition');
62
+ let job;
63
+ try {
64
+ job = new cron_1.CronJob(cronExpression, async () => {
65
+ try {
66
+ const { isLatest, currentVersion, latestVersion, error } = await (0, VersionUtils_1.checkIsLatest)();
67
+ let shouldTrigger = false;
68
+ if (triggerCondition === 'always') {
69
+ shouldTrigger = true;
70
+ }
71
+ else if (triggerCondition === 'update') {
72
+ shouldTrigger = !isLatest;
73
+ }
74
+ else if (triggerCondition === 'latest') {
75
+ shouldTrigger = isLatest === true;
76
+ }
77
+ if (shouldTrigger) {
78
+ this.emit([
79
+ [
80
+ {
81
+ json: {
82
+ currentVersion,
83
+ latestVersion,
84
+ isLatest,
85
+ error: error || undefined,
86
+ triggeredAt: new Date().toISOString(),
87
+ triggerCondition,
88
+ },
89
+ },
90
+ ],
91
+ ]);
92
+ }
93
+ }
94
+ catch (err) {
95
+ console.error('[VersionTrigger] Error during cron execution:', err);
96
+ // Don't stop the cron job on errors, just log them
97
+ }
98
+ }, null, true);
99
+ }
100
+ catch (err) {
101
+ const errorMessage = err instanceof Error ? err.message : String(err);
102
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Invalid cron expression: ${errorMessage}. Please use standard cron format (e.g., "0 * * * *" for hourly).`);
103
+ }
104
+ async function closeFunction() {
105
+ if (job) {
106
+ job.stop();
107
+ }
108
+ }
109
+ return {
110
+ closeFunction,
111
+ };
112
+ }
113
+ }
114
+ exports.N8nVersionTrigger = N8nVersionTrigger;
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0,0,256,256" width="256px" height="256px" fill-rule="nonzero"><g fill="#f188a2" fill-rule="nonzero" stroke="none" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="10" stroke-dasharray="" stroke-dashoffset="0" font-family="none" font-weight="none" font-size="none" text-anchor="none" style="mix-blend-mode: normal"><g transform="scale(5.12,5.12)"><path d="M20,3c-5.514,0 -10,4.486 -10,10v20.17188l-3.58594,-3.58594c-0.37701,-0.38755 -0.89487,-0.60597 -1.43555,-0.60547c-0.81349,0.00101 -1.54533,0.49459 -1.85108,1.24844c-0.30574,0.75385 -0.12447,1.61777 0.4585,2.18515l7,7c0.78106,0.78074 2.04706,0.78074 2.82812,0l7,-7c0.52248,-0.50163 0.73295,-1.24653 0.55024,-1.94742c-0.18271,-0.70088 -0.73006,-1.24823 -1.43094,-1.43094c-0.70088,-0.18271 -1.44578,0.02776 -1.94742,0.55024l-3.58594,3.58594v-20.17187c0,-3.309 2.691,-6 6,-6h10.46875l0.26563,-4zM37.9707,10c-0.52023,0.00778 -1.01695,0.21796 -1.38477,0.58594l-7,7c-0.52248,0.50163 -0.73295,1.24653 -0.55024,1.94742c0.18271,0.70088 0.73006,1.24823 1.43094,1.43094c0.70088,0.18271 1.44578,-0.02776 1.94742,-0.55024l3.58594,-3.58594v20.17188c0,3.309 -2.691,6 -6,6h-10.49023l-0.25391,4h10.74414c5.514,0 10,-4.486 10,-10v-20.17187l3.58594,3.58594c0.50163,0.52248 1.24653,0.73295 1.94742,0.55024c0.70088,-0.18271 1.24823,-0.73006 1.43094,-1.43094c0.18271,-0.70088 -0.02776,-1.44578 -0.55024,-1.94742l-7,-7c-0.38217,-0.38233 -0.90283,-0.5937 -1.44336,-0.58594z"></path></g></g></svg>
@@ -0,0 +1,185 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.stripMarkdownLinks = exports.cleanChangelog = exports.getChangelog = exports.checkIsLatest = exports.getCurrentN8nVersion = exports.getLatestN8nVersion = void 0;
7
+ const child_process_1 = require("child_process");
8
+ const https_1 = __importDefault(require("https"));
9
+ /**
10
+ * Fetches the latest n8n version from npm registry
11
+ * @returns Promise resolving to version string or 'unknown' on error
12
+ */
13
+ function getLatestN8nVersion() {
14
+ return new Promise((resolve) => {
15
+ try {
16
+ https_1.default
17
+ .get('https://registry.npmjs.org/n8n/stable', (res) => {
18
+ let data = '';
19
+ res.on('data', (chunk) => (data += chunk));
20
+ res.on('end', () => {
21
+ var _a;
22
+ try {
23
+ const parsed = JSON.parse(data);
24
+ resolve((_a = parsed.version) !== null && _a !== void 0 ? _a : 'unknown');
25
+ }
26
+ catch (err) {
27
+ console.error('[VersionUtils] Failed to parse npm registry response:', err);
28
+ resolve('unknown');
29
+ }
30
+ });
31
+ })
32
+ .on('error', (err) => {
33
+ console.error('[VersionUtils] Failed to fetch latest version from npm:', err);
34
+ resolve('unknown');
35
+ });
36
+ }
37
+ catch (err) {
38
+ console.error('[VersionUtils] Unexpected error in getLatestN8nVersion:', err);
39
+ resolve('unknown');
40
+ }
41
+ });
42
+ }
43
+ exports.getLatestN8nVersion = getLatestN8nVersion;
44
+ /**
45
+ * Gets the currently installed n8n version
46
+ * Tries multiple methods: N8N_VERSION env var, n8n --version command, env var scan
47
+ * @returns Current version string or 'unknown' if not found
48
+ */
49
+ function getCurrentN8nVersion() {
50
+ let currentVersion = process.env.N8N_VERSION;
51
+ // ENV first
52
+ if (!currentVersion) {
53
+ try {
54
+ const stdout = (0, child_process_1.execSync)('n8n --version').toString();
55
+ if (stdout) {
56
+ currentVersion = stdout.trim();
57
+ }
58
+ }
59
+ catch (err) {
60
+ console.error('[VersionUtils] Failed to execute n8n --version:', err);
61
+ }
62
+ }
63
+ // ENV scan fallback
64
+ if (!currentVersion) {
65
+ const versionKey = Object.keys(process.env).find((key) => key.includes('VERSION') && key.includes('N8N'));
66
+ if (versionKey) {
67
+ currentVersion = process.env[versionKey];
68
+ }
69
+ }
70
+ return currentVersion || 'unknown';
71
+ }
72
+ exports.getCurrentN8nVersion = getCurrentN8nVersion;
73
+ /**
74
+ * Checks if the current n8n version is the latest available
75
+ * @returns Object with currentVersion, latestVersion, and isLatest flag
76
+ */
77
+ async function checkIsLatest() {
78
+ const currentVersion = getCurrentN8nVersion();
79
+ const latestVersion = await getLatestN8nVersion();
80
+ const isLatest = currentVersion !== 'unknown' &&
81
+ latestVersion !== 'unknown' &&
82
+ currentVersion === latestVersion;
83
+ return {
84
+ currentVersion,
85
+ latestVersion,
86
+ isLatest,
87
+ };
88
+ }
89
+ exports.checkIsLatest = checkIsLatest;
90
+ /**
91
+ * Fetches changelog from GitHub releases for a specific n8n version
92
+ * @param version - The n8n version to fetch changelog for (e.g., "1.0.0")
93
+ * @returns Promise resolving to changelog info with body and optional error
94
+ */
95
+ function getChangelog(version) {
96
+ return new Promise((resolve) => {
97
+ try {
98
+ const options = {
99
+ hostname: 'api.github.com',
100
+ path: `/repos/n8n-io/n8n/releases/tags/n8n@${version}`,
101
+ headers: {
102
+ 'User-Agent': 'n8n-version-node',
103
+ },
104
+ };
105
+ https_1.default
106
+ .get(options, (res) => {
107
+ let data = '';
108
+ res.on('data', (chunk) => (data += chunk));
109
+ res.on('end', () => {
110
+ try {
111
+ if (res.statusCode === 404) {
112
+ resolve({
113
+ version,
114
+ changelog: '',
115
+ error: `Release n8n@${version} not found on GitHub`,
116
+ });
117
+ return;
118
+ }
119
+ if (res.statusCode !== 200) {
120
+ resolve({
121
+ version,
122
+ changelog: '',
123
+ error: `GitHub API returned status ${res.statusCode}`,
124
+ });
125
+ return;
126
+ }
127
+ const parsed = JSON.parse(data);
128
+ resolve({
129
+ version,
130
+ changelog: cleanChangelog(parsed.body || ''),
131
+ });
132
+ }
133
+ catch (err) {
134
+ console.error('[VersionUtils] Failed to parse GitHub response:', err);
135
+ resolve({
136
+ version,
137
+ changelog: '',
138
+ error: 'Failed to parse GitHub response',
139
+ });
140
+ }
141
+ });
142
+ })
143
+ .on('error', (err) => {
144
+ console.error('[VersionUtils] Failed to fetch from GitHub:', err);
145
+ resolve({
146
+ version,
147
+ changelog: '',
148
+ error: `Failed to fetch from GitHub: ${err.message}`,
149
+ });
150
+ });
151
+ }
152
+ catch (err) {
153
+ console.error('[VersionUtils] Unexpected error in getChangelog:', err);
154
+ resolve({
155
+ version,
156
+ changelog: '',
157
+ error: `Unexpected error: ${err}`,
158
+ });
159
+ }
160
+ });
161
+ }
162
+ exports.getChangelog = getChangelog;
163
+ /**
164
+ * Cleans changelog text by normalizing line breaks and removing artifacts
165
+ * @param text - Raw changelog text
166
+ * @returns Cleaned text
167
+ */
168
+ function cleanChangelog(text) {
169
+ if (!text)
170
+ return '';
171
+ return text
172
+ .replace(/\r\n/g, '\n') // Normalize Windows line endings
173
+ .replace(/\n{3,}/g, '\n\n') // Max 2 consecutive newlines
174
+ .trim();
175
+ }
176
+ exports.cleanChangelog = cleanChangelog;
177
+ /**
178
+ * Strips markdown links from text, converting [text](url) to text
179
+ * @param text - Text containing markdown links
180
+ * @returns Text with links stripped
181
+ */
182
+ function stripMarkdownLinks(text) {
183
+ return text.replace(/\[([^\]]+)\]\([^\)]+\)/g, '$1');
184
+ }
185
+ exports.stripMarkdownLinks = stripMarkdownLinks;
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "n8n-nodes-version",
3
+ "version": "0.2.0",
4
+ "description": "n8n nodes to check version, monitor updates, and fetch changelogs",
5
+ "keywords": [
6
+ "n8n-community-node-package"
7
+ ],
8
+ "license": "MIT",
9
+ "homepage": "",
10
+ "author": {
11
+ "name": "Community",
12
+ "email": "example@example.com"
13
+ },
14
+ "scripts": {
15
+ "build": "tsc && gulp build:icons",
16
+ "dev": "tsc --watch",
17
+ "lint": "tslint -p tsconfig.json -c tslint.json",
18
+ "test": "echo \"Error: no test specified\" && exit 1",
19
+ "prepublishOnly": "npm run build"
20
+ },
21
+ "main": "dist/index.js",
22
+ "n8n": {
23
+ "nodes": [
24
+ "dist/nodes/N8nVersion/N8nVersion.node.js",
25
+ "dist/nodes/N8nVersionTrigger/N8nVersionTrigger.node.js"
26
+ ]
27
+ },
28
+ "files": [
29
+ "dist"
30
+ ],
31
+ "devDependencies": {
32
+ "@types/cron": "^2.0.1",
33
+ "@types/node": "^14.14.31",
34
+ "gulp": "^4.0.2",
35
+ "n8n-core": "^0.116.0",
36
+ "n8n-workflow": "^0.114.0",
37
+ "tslint": "^6.1.2",
38
+ "typescript": "^4.1.3"
39
+ },
40
+ "peerDependencies": {
41
+ "n8n-workflow": "*"
42
+ },
43
+ "dependencies": {
44
+ "cron": "^4.4.0"
45
+ }
46
+ }