n8n-nodes-tunova 0.1.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,39 @@
1
+ # n8n-nodes-tunova
2
+
3
+ An [n8n](https://n8n.io) community node for the **[Tunova](https://tunova.ai) Suno music API** — generate
4
+ full songs from your workflows over a simple REST API. Generation is async and **billed only on a
5
+ successful render** (a failed generation auto-refunds).
6
+
7
+ This is a community node. [Installing community nodes.](https://docs.n8n.io/integrations/community-nodes/installation/)
8
+
9
+ ## Installation
10
+
11
+ In n8n: **Settings → Community Nodes → Install**, then enter `n8n-nodes-tunova`.
12
+
13
+ ## Credentials
14
+
15
+ Create a **Tunova API** credential with your API key (`sk_live_…`). Get one free — 50 tokens, no card —
16
+ at <https://tunova.ai>. The key is sent as the `X-API-Key` header; the credential's **Test** button
17
+ calls `GET /api/me`.
18
+
19
+ ## Operations
20
+
21
+ - **Generate Song** — submit a job from a text prompt (`prompt`, `model` default `v5.5`, optional
22
+ instrumental). Async: returns `202` + a `job_id`.
23
+ - **Get Job** — poll a `job_id`; once `status` is `complete`, `clips[].audio_url` is set.
24
+ - **Generate Lyrics** — generate song lyrics (synchronous).
25
+
26
+ ### Typical flow
27
+
28
+ `Generate Song` → **Wait** (a few seconds) → `Get Job` → **IF** `status` is `complete`/`failed`
29
+ (loop back to Wait otherwise) → use `clips[0].audio_url`. Or pass a `callback_url` to `POST /api/generate`
30
+ with a raw HTTP node and take an HMAC-signed webhook instead of polling.
31
+
32
+ ## Resources
33
+
34
+ - Tunova docs: <https://api.tunova.ai/docs>
35
+ - Live status: <https://tunova.ai/status>
36
+
37
+ ## License
38
+
39
+ MIT. Tunova is an independent service, not affiliated with or endorsed by Suno.
@@ -0,0 +1,9 @@
1
+ import { IAuthenticateGeneric, ICredentialTestRequest, ICredentialType, INodeProperties } from 'n8n-workflow';
2
+ export declare class TunovaApi implements ICredentialType {
3
+ name: string;
4
+ displayName: string;
5
+ documentationUrl: string;
6
+ properties: INodeProperties[];
7
+ authenticate: IAuthenticateGeneric;
8
+ test: ICredentialTestRequest;
9
+ }
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TunovaApi = void 0;
4
+ class TunovaApi {
5
+ constructor() {
6
+ this.name = 'tunovaApi';
7
+ this.displayName = 'Tunova API';
8
+ this.documentationUrl = 'https://api.tunova.ai/docs';
9
+ this.properties = [
10
+ {
11
+ displayName: 'API Key',
12
+ name: 'apiKey',
13
+ type: 'string',
14
+ typeOptions: { password: true },
15
+ default: '',
16
+ required: true,
17
+ description: 'Your Tunova API key (sk_live_…). Get one free (50 tokens, no card) at https://tunova.ai',
18
+ },
19
+ ];
20
+ // Sent as X-API-Key on every request.
21
+ this.authenticate = {
22
+ type: 'generic',
23
+ properties: {
24
+ headers: {
25
+ 'X-API-Key': '={{$credentials.apiKey}}',
26
+ },
27
+ },
28
+ };
29
+ // "Test" button in the n8n credential UI — hits GET /api/me.
30
+ this.test = {
31
+ request: {
32
+ baseURL: 'https://api.tunova.ai',
33
+ url: '/api/me',
34
+ },
35
+ };
36
+ }
37
+ }
38
+ exports.TunovaApi = TunovaApi;
@@ -0,0 +1,4 @@
1
+ import { INodeType, INodeTypeDescription } from 'n8n-workflow';
2
+ export declare class Tunova implements INodeType {
3
+ description: INodeTypeDescription;
4
+ }
@@ -0,0 +1,155 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Tunova = void 0;
4
+ // n8n-workflow exports NodeConnectionType as a type (not a runtime enum) — its underlying value
5
+ // for a standard data connection is the string 'main'. Cast keeps us compatible across versions.
6
+ const MAIN = 'main';
7
+ class Tunova {
8
+ constructor() {
9
+ this.description = {
10
+ displayName: 'Tunova',
11
+ name: 'tunova',
12
+ icon: 'file:tunova.svg',
13
+ group: ['transform'],
14
+ version: 1,
15
+ subtitle: '={{$parameter["operation"]}}',
16
+ description: 'Generate music with the Tunova Suno API (billed only on successful renders)',
17
+ defaults: {
18
+ name: 'Tunova',
19
+ },
20
+ inputs: [MAIN],
21
+ outputs: [MAIN],
22
+ credentials: [
23
+ {
24
+ name: 'tunovaApi',
25
+ required: true,
26
+ },
27
+ ],
28
+ requestDefaults: {
29
+ baseURL: 'https://api.tunova.ai',
30
+ headers: {
31
+ 'Content-Type': 'application/json',
32
+ },
33
+ },
34
+ properties: [
35
+ {
36
+ displayName: 'Operation',
37
+ name: 'operation',
38
+ type: 'options',
39
+ noDataExpression: true,
40
+ default: 'generate',
41
+ options: [
42
+ {
43
+ name: 'Generate Song',
44
+ value: 'generate',
45
+ action: 'Generate a song',
46
+ description: 'Submit a song generation job — returns 202 + a job_id (settled on success)',
47
+ routing: {
48
+ request: {
49
+ method: 'POST',
50
+ url: '/api/generate',
51
+ },
52
+ },
53
+ },
54
+ {
55
+ name: 'Generate Lyrics',
56
+ value: 'lyrics',
57
+ action: 'Generate lyrics',
58
+ description: 'Generate song lyrics (synchronous)',
59
+ routing: {
60
+ request: {
61
+ method: 'POST',
62
+ url: '/api/lyrics',
63
+ },
64
+ },
65
+ },
66
+ {
67
+ name: 'Get Job',
68
+ value: 'getJob',
69
+ action: 'Get a job',
70
+ description: 'Poll a job for its status and finished clips',
71
+ routing: {
72
+ request: {
73
+ method: 'GET',
74
+ url: '=/api/jobs/{{$parameter.jobId}}',
75
+ },
76
+ },
77
+ },
78
+ ],
79
+ },
80
+ {
81
+ displayName: 'Prompt',
82
+ name: 'prompt',
83
+ type: 'string',
84
+ typeOptions: {
85
+ rows: 2,
86
+ },
87
+ default: '',
88
+ required: true,
89
+ description: 'For Generate Song: a text description (e.g. "calm rainy-night lofi"). For Generate Lyrics: the theme/brief.',
90
+ displayOptions: {
91
+ show: {
92
+ operation: ['generate', 'lyrics'],
93
+ },
94
+ },
95
+ routing: {
96
+ send: {
97
+ type: 'body',
98
+ property: 'prompt',
99
+ },
100
+ },
101
+ },
102
+ {
103
+ displayName: 'Model',
104
+ name: 'model',
105
+ type: 'string',
106
+ default: 'v5.5',
107
+ description: 'Suno model to use (per request)',
108
+ displayOptions: {
109
+ show: {
110
+ operation: ['generate'],
111
+ },
112
+ },
113
+ routing: {
114
+ send: {
115
+ type: 'body',
116
+ property: 'model',
117
+ },
118
+ },
119
+ },
120
+ {
121
+ displayName: 'Instrumental',
122
+ name: 'makeInstrumental',
123
+ type: 'boolean',
124
+ default: false,
125
+ description: 'Whether to generate an instrumental (no vocals)',
126
+ displayOptions: {
127
+ show: {
128
+ operation: ['generate'],
129
+ },
130
+ },
131
+ routing: {
132
+ send: {
133
+ type: 'body',
134
+ property: 'make_instrumental',
135
+ },
136
+ },
137
+ },
138
+ {
139
+ displayName: 'Job ID',
140
+ name: 'jobId',
141
+ type: 'string',
142
+ default: '',
143
+ required: true,
144
+ description: 'The job_id returned by Generate Song',
145
+ displayOptions: {
146
+ show: {
147
+ operation: ['getJob'],
148
+ },
149
+ },
150
+ },
151
+ ],
152
+ };
153
+ }
154
+ }
155
+ exports.Tunova = Tunova;
@@ -0,0 +1,8 @@
1
+ <svg width="60" height="60" viewBox="0 0 60 60" xmlns="http://www.w3.org/2000/svg">
2
+ <rect width="60" height="60" rx="14" fill="#0d0d0d"/>
3
+ <path d="M17 21h26" stroke="#ffffff" stroke-width="5" stroke-linecap="round"/>
4
+ <path d="M30 21v18" stroke="#ffffff" stroke-width="5" stroke-linecap="round"/>
5
+ <circle cx="25.5" cy="40.5" r="4.5" fill="#ffffff"/>
6
+ <path d="M30 39V28l9-2v9" stroke="#ffffff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
7
+ <circle cx="35.5" cy="35.5" r="4" fill="#ffffff"/>
8
+ </svg>
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "n8n-nodes-tunova",
3
+ "version": "0.1.0",
4
+ "description": "n8n community node for the Tunova Suno music API — generate full songs over REST, billed only on successful renders.",
5
+ "keywords": [
6
+ "n8n-community-node-package",
7
+ "n8n",
8
+ "tunova",
9
+ "suno",
10
+ "music",
11
+ "ai",
12
+ "music-generation"
13
+ ],
14
+ "license": "MIT",
15
+ "homepage": "https://tunova.ai",
16
+ "author": "Tunova",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/erliona/n8n-nodes-tunova.git"
20
+ },
21
+ "engines": {
22
+ "node": ">=18.10"
23
+ },
24
+ "scripts": {
25
+ "build": "tsc && npm run icons",
26
+ "icons": "mkdir -p dist/nodes/Tunova && cp nodes/Tunova/tunova.svg dist/nodes/Tunova/tunova.svg",
27
+ "dev": "tsc --watch",
28
+ "prepack": "npm run build"
29
+ },
30
+ "files": [
31
+ "dist"
32
+ ],
33
+ "n8n": {
34
+ "n8nNodesApiVersion": 1,
35
+ "credentials": [
36
+ "dist/credentials/TunovaApi.credentials.js"
37
+ ],
38
+ "nodes": [
39
+ "dist/nodes/Tunova/Tunova.node.js"
40
+ ]
41
+ },
42
+ "peerDependencies": {
43
+ "n8n-workflow": "*"
44
+ },
45
+ "devDependencies": {
46
+ "n8n-workflow": "^1.60.0",
47
+ "typescript": "^5.5.3"
48
+ }
49
+ }