n8n-nodes-ntfy-next 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
package/LICENSE.md ADDED
@@ -0,0 +1,19 @@
1
+ © 2025 Iván Ovejero
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the "Software"), to deal in
5
+ the Software without restriction, including without limitation the rights to
6
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7
+ of the Software, and to permit persons to whom the Software is furnished to do
8
+ so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,14 @@
1
+ # n8n-nodes-ntfy
2
+
3
+ [n8n community package](https://docs.n8n.io/integrations/community-nodes/installation/gui-install/) to push messages via [ntfy.sh](https://ntfy.sh/)
4
+
5
+ - Set headers via fields or JSON
6
+ - Support for self-hosted ntfy instances
7
+ - Credentials for basic + bearer + query auth
8
+
9
+ <img src="docs/ndv.png" width="400">
10
+
11
+ ## Docs
12
+
13
+ - [`development.md`](docs/development.md)
14
+ - [`self-hosting.md`](docs/self-hosting.md)
@@ -0,0 +1,170 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Ntfy = void 0;
4
+ class Ntfy {
5
+ constructor() {
6
+ this.description = {
7
+ displayName: "ntfy",
8
+ name: "ntfy",
9
+ icon: { light: "file:ntfy.light.svg", dark: "file:ntfy.dark.svg" },
10
+ group: ["transform"],
11
+ version: 1,
12
+ subtitle: '={{ $parameter["topic"] }}',
13
+ description: "Push messages via ntfy.sh",
14
+ defaults: {
15
+ name: "ntfy",
16
+ },
17
+ inputs: ["main" /* NodeConnectionType.Main */],
18
+ outputs: ["main" /* NodeConnectionType.Main */],
19
+ requestDefaults: {
20
+ baseURL: '={{ $credentials.baseUrl.replace(new RegExp("/$"), "") }}',
21
+ },
22
+ credentials: [
23
+ {
24
+ name: "ntfyApi",
25
+ required: true,
26
+ },
27
+ ],
28
+ properties: [
29
+ {
30
+ displayName: "Topic",
31
+ name: "topic",
32
+ type: "string",
33
+ description: 'Topic to <a href="https://docs.ntfy.sh/publish/#publishing">push</a> a message to',
34
+ required: true,
35
+ default: "",
36
+ placeholder: "e.g. mytopic",
37
+ routing: {
38
+ request: {
39
+ method: "POST",
40
+ url: "=/{{ $parameter.topic }}",
41
+ },
42
+ },
43
+ },
44
+ {
45
+ displayName: "Message",
46
+ name: "message",
47
+ type: "string",
48
+ description: "Message to publish to a topic",
49
+ required: true,
50
+ default: "",
51
+ placeholder: "e.g. Hello world!",
52
+ routing: {
53
+ send: { preSend: [populateMessage] },
54
+ },
55
+ },
56
+ {
57
+ displayName: "Send Additional Headers",
58
+ name: "sendAdditionalHeaders",
59
+ type: "boolean",
60
+ default: false,
61
+ noDataExpression: true,
62
+ description: 'Whether to send <a href="https://docs.ntfy.sh/publish/#list-of-all-parameters">additional headers</a> with the request',
63
+ },
64
+ {
65
+ displayName: "Specify Headers Using...",
66
+ name: "specifyHeadersUsing",
67
+ type: "options",
68
+ noDataExpression: true,
69
+ displayOptions: {
70
+ show: {
71
+ sendAdditionalHeaders: [true],
72
+ },
73
+ },
74
+ options: [
75
+ {
76
+ name: "Fields",
77
+ value: "keypair",
78
+ },
79
+ {
80
+ name: "JSON",
81
+ value: "json",
82
+ },
83
+ ],
84
+ default: "keypair",
85
+ },
86
+ {
87
+ displayName: "Header Fields",
88
+ name: "headerFields",
89
+ type: "fixedCollection",
90
+ displayOptions: {
91
+ show: {
92
+ sendAdditionalHeaders: [true],
93
+ specifyHeadersUsing: ["keypair"],
94
+ },
95
+ },
96
+ typeOptions: {
97
+ multipleValues: true,
98
+ },
99
+ placeholder: "Add Header Field",
100
+ routing: {
101
+ send: { preSend: [populateHeaderFields] },
102
+ },
103
+ default: {
104
+ parameters: [
105
+ {
106
+ name: "",
107
+ value: "",
108
+ },
109
+ ],
110
+ },
111
+ options: [
112
+ {
113
+ name: "parameters",
114
+ displayName: "Parameter",
115
+ values: [
116
+ {
117
+ displayName: "Name",
118
+ name: "name",
119
+ type: "string",
120
+ default: "",
121
+ placeholder: "e.g. X-Title",
122
+ },
123
+ {
124
+ displayName: "Value",
125
+ name: "value",
126
+ type: "string",
127
+ default: "",
128
+ placeholder: "e.g. This is a title",
129
+ },
130
+ ],
131
+ },
132
+ ],
133
+ },
134
+ {
135
+ displayName: "JSON Headers",
136
+ name: "jsonHeaders",
137
+ type: "json",
138
+ displayOptions: {
139
+ show: {
140
+ sendAdditionalHeaders: [true],
141
+ specifyHeadersUsing: ["json"],
142
+ },
143
+ },
144
+ routing: {
145
+ send: { preSend: [populateJsonHeaders] },
146
+ },
147
+ default: '{ "X-Title": "This is a title" }',
148
+ },
149
+ ],
150
+ };
151
+ }
152
+ }
153
+ exports.Ntfy = Ntfy;
154
+ async function populateMessage(opts) {
155
+ opts.body = this.getNodeParameter("message");
156
+ return opts;
157
+ }
158
+ async function populateHeaderFields(opts) {
159
+ var _a;
160
+ (_a = opts.headers) !== null && _a !== void 0 ? _a : (opts.headers = {});
161
+ const { parameters } = this.getNodeParameter("headerFields");
162
+ for (const p of parameters) {
163
+ opts.headers[p.name] = p.value;
164
+ }
165
+ return opts;
166
+ }
167
+ async function populateJsonHeaders(opts) {
168
+ opts.headers = JSON.parse(this.getNodeParameter("jsonHeaders"));
169
+ return opts;
170
+ }
@@ -0,0 +1,132 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NtfyApi = void 0;
4
+ const n8n_workflow_1 = require("n8n-workflow");
5
+ class NtfyApi {
6
+ constructor() {
7
+ this.name = "ntfyApi";
8
+ this.displayName = "ntfy API";
9
+ this.icon = { light: "file:ntfy.light.svg", dark: "file:ntfy.dark.svg" };
10
+ this.properties = [
11
+ {
12
+ displayName: "Base URL",
13
+ name: "baseUrl",
14
+ type: "string",
15
+ default: "https://ntfy.sh",
16
+ description: "Base URL of the ntfy instance",
17
+ required: true,
18
+ },
19
+ {
20
+ displayName: "Auth Type",
21
+ name: "authType",
22
+ type: "options",
23
+ description: '<a href="https://docs.ntfy.sh/publish/#authentication">Auth type</a> to use',
24
+ required: true,
25
+ options: [
26
+ {
27
+ name: "No Auth",
28
+ value: "noAuth",
29
+ },
30
+ {
31
+ name: "Basic Auth",
32
+ value: "basicAuth",
33
+ },
34
+ {
35
+ name: "Bearer Auth",
36
+ value: "bearerAuth",
37
+ },
38
+ {
39
+ name: "Query Auth",
40
+ value: "queryAuth",
41
+ },
42
+ ],
43
+ default: "noAuth",
44
+ },
45
+ {
46
+ displayName: "Username",
47
+ name: "username",
48
+ type: "string",
49
+ description: '<a href="https://docs.ntfy.sh/publish/#username-password">Username</a> for basic auth',
50
+ default: "",
51
+ required: true,
52
+ displayOptions: {
53
+ show: {
54
+ authType: ["basicAuth"],
55
+ },
56
+ },
57
+ },
58
+ {
59
+ displayName: "Password",
60
+ name: "password",
61
+ type: "string",
62
+ description: '<a href="https://docs.ntfy.sh/publish/#username-password">Password</a> for basic auth',
63
+ typeOptions: {
64
+ password: true,
65
+ },
66
+ default: "",
67
+ placeholder: "e.g. mypassword123",
68
+ required: true,
69
+ displayOptions: {
70
+ show: {
71
+ authType: ["basicAuth"],
72
+ },
73
+ },
74
+ },
75
+ {
76
+ displayName: "Bearer Token",
77
+ name: "bearerToken",
78
+ required: true,
79
+ description: '<a href="https://docs.ntfy.sh/publish/#access-tokens">Bearer token</a> for bearer auth',
80
+ type: "string",
81
+ typeOptions: { password: true },
82
+ default: "",
83
+ placeholder: "e.g. tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2",
84
+ displayOptions: {
85
+ show: {
86
+ authType: ["bearerAuth"],
87
+ },
88
+ },
89
+ },
90
+ {
91
+ displayName: "Query Parameter",
92
+ name: "queryParameter",
93
+ type: "string",
94
+ required: true,
95
+ description: '<a href="https://docs.ntfy.sh/publish/#query-param">Query parameter</a> for auth',
96
+ default: "",
97
+ displayOptions: {
98
+ show: {
99
+ authType: ["queryAuth"],
100
+ },
101
+ },
102
+ },
103
+ ];
104
+ this.test = {
105
+ request: {
106
+ baseURL: '={{ $credentials.baseUrl }}',
107
+ url: '/v1/health',
108
+ },
109
+ };
110
+ }
111
+ async authenticate(credentials, opts) {
112
+ const c = credentials;
113
+ if (c.authType === "noAuth")
114
+ return opts;
115
+ if (c.authType === "basicAuth") {
116
+ opts.auth = { username: c.username, password: c.password };
117
+ return opts;
118
+ }
119
+ if (c.authType === "bearerAuth") {
120
+ opts.headers = {
121
+ Authorization: `Bearer ${c.bearerToken}`,
122
+ };
123
+ return opts;
124
+ }
125
+ if (c.authType === "queryAuth") {
126
+ opts.url = `${opts.url}?auth=${c.queryParameter}`;
127
+ return opts;
128
+ }
129
+ throw new n8n_workflow_1.ApplicationError("Invalid credentials type");
130
+ }
131
+ }
132
+ exports.NtfyApi = NtfyApi;
@@ -0,0 +1,7 @@
1
+ <svg width="800" height="800" viewBox="0 0 50.8 50.8" xmlns="http://www.w3.org/2000/svg">
2
+ <g style="stroke:#fff;stroke-opacity:1">
3
+ <path d="M44.98 39.952V10.848H7.407v27.814l-1.587 4.2 8.393-2.91Z" style="fill:none;fill-opacity:1;stroke:#fff;stroke-width:3.175;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"/>
4
+ <path d="M27.781 31.485h8.202" style="fill:none;fill-opacity:1;stroke:#fff;stroke-width:3.175;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill"/>
5
+ <path d="m65.979 100.011 9.511 5.492-9.511 5.491" style="display:inline;fill:none;fill-opacity:1;stroke:#fff;stroke-width:3.175;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" transform="translate(-51.81 -80.758)"/>
6
+ </g>
7
+ </svg>
@@ -0,0 +1,7 @@
1
+ <svg width="800" height="800" viewBox="0 0 50.8 50.8" xmlns="http://www.w3.org/2000/svg">
2
+ <g style="stroke:#000;stroke-opacity:1">
3
+ <path d="M44.98 39.952V10.848H7.407v27.814l-1.587 4.2 8.393-2.91Z" style="fill:none;fill-opacity:1;stroke:#000;stroke-width:3.175;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"/>
4
+ <path d="M27.781 31.485h8.202" style="fill:none;fill-opacity:1;stroke:#000;stroke-width:3.175;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill"/>
5
+ <path d="m65.979 100.011 9.511 5.492-9.511 5.491" style="display:inline;fill:none;fill-opacity:1;stroke:#000;stroke-width:3.175;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" transform="translate(-51.81 -80.758)"/>
6
+ </g>
7
+ </svg>
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "n8n-nodes-ntfy-next",
3
+ "version": "1.0.0",
4
+ "description": "n8n community package to push messages via ntfy.sh",
5
+ "keywords": [
6
+ "n8n-community-node-package",
7
+ "ntfy"
8
+ ],
9
+ "license": "MIT",
10
+ "author": {
11
+ "name": "Iván Ovejero"
12
+ },
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "https://github.com/ivov/n8n-nodes-ntfy.git"
16
+ },
17
+ "engines": {
18
+ "node": ">=20.15",
19
+ "pnpm": ">=9.15"
20
+ },
21
+ "packageManager": "pnpm@9.15.1",
22
+ "main": "index.js",
23
+ "files": [
24
+ "dist"
25
+ ],
26
+ "scripts": {
27
+ "build": "tsc && cp src/*.svg dist/"
28
+ },
29
+ "n8n": {
30
+ "n8nNodesApiVersion": 1,
31
+ "credentials": [
32
+ "dist/NtfyApi.credentials.js"
33
+ ],
34
+ "nodes": [
35
+ "dist/Ntfy.node.js"
36
+ ]
37
+ },
38
+ "peerDependencies": {
39
+ "n8n-workflow": "*"
40
+ },
41
+ "devDependencies": {
42
+ "typescript": "^5.7.3"
43
+ }
44
+ }