n8n-nodes-db-anub 0.0.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/LICENSE.md +21 -0
- package/README.md +323 -0
- package/credentials/D1ManagerApi.credentials.ts +52 -0
- package/nodes/D1Manager/D1Manager.node.ts +594 -0
- package/nodes/D1Manager/d1manager-dark.svg +9 -0
- package/nodes/D1Manager/d1manager-light.svg +9 -0
- package/package.json +43 -0
- package/tsconfig.json +25 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
# n8n-nodes-db-anub
|
|
2
|
+
|
|
3
|
+
[](https://badge.fury.io/js/n8n-nodes-db-anub)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
An n8n community node for interacting with **Cloudflare D1 databases** via the [D1 Manager Worker API](https://github.com/your-username/n8n-d1-anub).
|
|
7
|
+
|
|
8
|
+
## 🚀 Features
|
|
9
|
+
|
|
10
|
+
- **Full CRUD Operations**: Select, Insert, Update, Delete records
|
|
11
|
+
- **Advanced Queries**: JOINs, WHERE conditions, ORDER BY, GROUP BY, LIMIT/OFFSET
|
|
12
|
+
- **Aggregate Functions**: Count and Exists operations
|
|
13
|
+
- **Raw SQL**: Execute custom SQL queries
|
|
14
|
+
- **Batch Operations**: Execute multiple statements atomically
|
|
15
|
+
- **Database Discovery**: List all configured D1 database bindings
|
|
16
|
+
- **Secure Authentication**: API key-based authentication
|
|
17
|
+
- **AI-Ready**: Usable as a tool in n8n AI workflows
|
|
18
|
+
|
|
19
|
+
## 📦 Installation
|
|
20
|
+
|
|
21
|
+
### Via n8n Community Nodes (Recommended)
|
|
22
|
+
|
|
23
|
+
1. Go to **Settings** > **Community Nodes**
|
|
24
|
+
2. Select **Install**
|
|
25
|
+
3. Enter `n8n-nodes-db-anub`
|
|
26
|
+
4. Select **Install**
|
|
27
|
+
|
|
28
|
+
### Via npm
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm install n8n-nodes-db-anub
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Manual Installation
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
# Clone or download this repository
|
|
38
|
+
cd n8n-nodes-db-anub
|
|
39
|
+
npm install
|
|
40
|
+
npm run build
|
|
41
|
+
npm link
|
|
42
|
+
|
|
43
|
+
# In your n8n custom directory
|
|
44
|
+
mkdir -p ~/.n8n/custom
|
|
45
|
+
cd ~/.n8n/custom
|
|
46
|
+
npm init -y
|
|
47
|
+
npm link n8n-nodes-db-anub
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## 🔧 Prerequisites
|
|
51
|
+
|
|
52
|
+
1. **D1 Manager Worker** deployed to Cloudflare Workers
|
|
53
|
+
2. **API Key** configured in your worker
|
|
54
|
+
3. **D1 Database bindings** configured in your worker
|
|
55
|
+
|
|
56
|
+
See the [D1 Manager Worker API documentation](https://github.com/your-username/n8n-d1-anub) for setup instructions.
|
|
57
|
+
|
|
58
|
+
## 🔐 Credentials Setup
|
|
59
|
+
|
|
60
|
+
1. In n8n, go to **Credentials** > **Add Credential**
|
|
61
|
+
2. Search for **D1 Manager API**
|
|
62
|
+
3. Enter:
|
|
63
|
+
- **Base URL**: Your worker URL (e.g., `https://your-worker.your-subdomain.workers.dev`)
|
|
64
|
+
- **API Key**: Your API key for authentication
|
|
65
|
+
4. Click **Save**
|
|
66
|
+
|
|
67
|
+
## 📖 Operations
|
|
68
|
+
|
|
69
|
+
### Resource: Record
|
|
70
|
+
|
|
71
|
+
Perform CRUD operations on database tables.
|
|
72
|
+
|
|
73
|
+
#### Select
|
|
74
|
+
|
|
75
|
+
Retrieve records from a table with optional filtering, ordering, and pagination.
|
|
76
|
+
|
|
77
|
+
| Field | Type | Description |
|
|
78
|
+
|-------|------|-------------|
|
|
79
|
+
| Database | String | D1 database binding name |
|
|
80
|
+
| Table | String | Target table name |
|
|
81
|
+
| Columns | String | Comma-separated columns (default: `*`) |
|
|
82
|
+
| Distinct | Boolean | Return distinct rows only |
|
|
83
|
+
| Where Conditions | JSON | WHERE condition tree |
|
|
84
|
+
| Joins | JSON | Array of JOIN clauses |
|
|
85
|
+
| Order By | JSON | Array of order clauses |
|
|
86
|
+
| Group By | JSON | Array of columns to group by |
|
|
87
|
+
| Limit | Number | Maximum rows to return |
|
|
88
|
+
| Offset | Number | Rows to skip |
|
|
89
|
+
|
|
90
|
+
**Example Where Conditions:**
|
|
91
|
+
```json
|
|
92
|
+
{
|
|
93
|
+
"column": "status",
|
|
94
|
+
"op": "=",
|
|
95
|
+
"value": "active"
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**Nested conditions:**
|
|
100
|
+
```json
|
|
101
|
+
{
|
|
102
|
+
"and": [
|
|
103
|
+
{ "column": "status", "op": "=", "value": "active" },
|
|
104
|
+
{
|
|
105
|
+
"or": [
|
|
106
|
+
{ "column": "score", "op": ">", "value": 100 },
|
|
107
|
+
{ "column": "score", "op": "is null" }
|
|
108
|
+
]
|
|
109
|
+
}
|
|
110
|
+
]
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**Example Joins:**
|
|
115
|
+
```json
|
|
116
|
+
[
|
|
117
|
+
{ "type": "inner", "table": "orders", "on": "users.id = orders.user_id" }
|
|
118
|
+
]
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**Example Order By:**
|
|
122
|
+
```json
|
|
123
|
+
[
|
|
124
|
+
{ "column": "created_at", "dir": "desc" },
|
|
125
|
+
{ "column": "name", "dir": "asc" }
|
|
126
|
+
]
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
#### Insert
|
|
130
|
+
|
|
131
|
+
Insert one or multiple records into a table.
|
|
132
|
+
|
|
133
|
+
| Field | Type | Description |
|
|
134
|
+
|-------|------|-------------|
|
|
135
|
+
| Database | String | D1 database binding name |
|
|
136
|
+
| Table | String | Target table name |
|
|
137
|
+
| Data | JSON | Column values (object or array) |
|
|
138
|
+
|
|
139
|
+
**Single row:**
|
|
140
|
+
```json
|
|
141
|
+
{
|
|
142
|
+
"name": "Alice",
|
|
143
|
+
"email": "alice@example.com",
|
|
144
|
+
"active": true
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**Multiple rows:**
|
|
149
|
+
```json
|
|
150
|
+
[
|
|
151
|
+
{ "name": "Bob", "email": "bob@example.com" },
|
|
152
|
+
{ "name": "Carol", "email": "carol@example.com" }
|
|
153
|
+
]
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
#### Update
|
|
157
|
+
|
|
158
|
+
Update records in a table.
|
|
159
|
+
|
|
160
|
+
| Field | Type | Description |
|
|
161
|
+
|-------|------|-------------|
|
|
162
|
+
| Database | String | D1 database binding name |
|
|
163
|
+
| Table | String | Target table name |
|
|
164
|
+
| Data | JSON | Column values to update |
|
|
165
|
+
| Where Conditions | JSON | WHERE condition tree |
|
|
166
|
+
|
|
167
|
+
#### Delete
|
|
168
|
+
|
|
169
|
+
Delete records from a table.
|
|
170
|
+
|
|
171
|
+
| Field | Type | Description |
|
|
172
|
+
|-------|------|-------------|
|
|
173
|
+
| Database | String | D1 database binding name |
|
|
174
|
+
| Table | String | Target table name |
|
|
175
|
+
| Where Conditions | JSON | WHERE condition tree |
|
|
176
|
+
|
|
177
|
+
#### Count
|
|
178
|
+
|
|
179
|
+
Count records in a table.
|
|
180
|
+
|
|
181
|
+
| Field | Type | Description |
|
|
182
|
+
|-------|------|-------------|
|
|
183
|
+
| Database | String | D1 database binding name |
|
|
184
|
+
| Table | String | Target table name |
|
|
185
|
+
| Where Conditions | JSON | WHERE condition tree (optional) |
|
|
186
|
+
|
|
187
|
+
#### Exists
|
|
188
|
+
|
|
189
|
+
Check if records exist in a table.
|
|
190
|
+
|
|
191
|
+
| Field | Type | Description |
|
|
192
|
+
|-------|------|-------------|
|
|
193
|
+
| Database | String | D1 database binding name |
|
|
194
|
+
| Table | String | Target table name |
|
|
195
|
+
| Where Conditions | JSON | WHERE condition tree |
|
|
196
|
+
|
|
197
|
+
### Resource: Raw SQL
|
|
198
|
+
|
|
199
|
+
Execute custom SQL queries.
|
|
200
|
+
|
|
201
|
+
| Field | Type | Description |
|
|
202
|
+
|-------|------|-------------|
|
|
203
|
+
| Database | String | D1 database binding name |
|
|
204
|
+
| SQL Query | String | Raw SQL to execute |
|
|
205
|
+
|
|
206
|
+
**Example:**
|
|
207
|
+
```sql
|
|
208
|
+
CREATE TABLE IF NOT EXISTS users (
|
|
209
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
210
|
+
name TEXT NOT NULL,
|
|
211
|
+
email TEXT UNIQUE,
|
|
212
|
+
created_at TEXT DEFAULT CURRENT_TIMESTAMP
|
|
213
|
+
)
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### Resource: Batch
|
|
217
|
+
|
|
218
|
+
Execute multiple statements atomically in a single transaction.
|
|
219
|
+
|
|
220
|
+
| Field | Type | Description |
|
|
221
|
+
|-------|------|-------------|
|
|
222
|
+
| Database | String | D1 database binding name |
|
|
223
|
+
| Statements | JSON | Array of action objects |
|
|
224
|
+
|
|
225
|
+
**Example:**
|
|
226
|
+
```json
|
|
227
|
+
[
|
|
228
|
+
{
|
|
229
|
+
"action": "insert",
|
|
230
|
+
"table": "orders",
|
|
231
|
+
"data": { "user_id": 1, "total": 99.99, "status": "pending" }
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
"action": "update",
|
|
235
|
+
"table": "users",
|
|
236
|
+
"data": { "order_count": 5 },
|
|
237
|
+
"where": { "column": "id", "op": "=", "value": 1 }
|
|
238
|
+
}
|
|
239
|
+
]
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Resource: Database
|
|
243
|
+
|
|
244
|
+
List all configured D1 database bindings.
|
|
245
|
+
|
|
246
|
+
## 📤 Response Format
|
|
247
|
+
|
|
248
|
+
All responses follow this structure:
|
|
249
|
+
|
|
250
|
+
**Success:**
|
|
251
|
+
```json
|
|
252
|
+
{
|
|
253
|
+
"success": true,
|
|
254
|
+
"data": { ... },
|
|
255
|
+
"meta": {
|
|
256
|
+
"rows_read": 5,
|
|
257
|
+
"rows_written": 0,
|
|
258
|
+
"duration_ms": 12
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
**Error:**
|
|
264
|
+
```json
|
|
265
|
+
{
|
|
266
|
+
"success": false,
|
|
267
|
+
"error": {
|
|
268
|
+
"message": "Human-readable description",
|
|
269
|
+
"code": "MACHINE_READABLE_CODE"
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
## 🔒 Supported WHERE Operators
|
|
275
|
+
|
|
276
|
+
| Operator | Description |
|
|
277
|
+
|----------|-------------|
|
|
278
|
+
| `=`, `!=`, `<>` | Equality |
|
|
279
|
+
| `<`, `<=`, `>`, `>=` | Comparison |
|
|
280
|
+
| `like`, `not like` | Pattern matching |
|
|
281
|
+
| `glob` | SQLite GLOB |
|
|
282
|
+
| `in`, `not in` | Set membership |
|
|
283
|
+
| `between` | Range |
|
|
284
|
+
| `is null`, `is not null` | Null checks |
|
|
285
|
+
|
|
286
|
+
## 🛠️ Development
|
|
287
|
+
|
|
288
|
+
```bash
|
|
289
|
+
# Install dependencies
|
|
290
|
+
npm install
|
|
291
|
+
|
|
292
|
+
# Build the node
|
|
293
|
+
npm run build
|
|
294
|
+
|
|
295
|
+
# Development mode with watch
|
|
296
|
+
npm run dev
|
|
297
|
+
|
|
298
|
+
# Lint code
|
|
299
|
+
npm run lint
|
|
300
|
+
npm run lint:fix
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
## 📝 License
|
|
304
|
+
|
|
305
|
+
[MIT](LICENSE.md)
|
|
306
|
+
|
|
307
|
+
## 🤝 Contributing
|
|
308
|
+
|
|
309
|
+
1. Fork the repository
|
|
310
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
311
|
+
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
|
312
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
313
|
+
5. Open a Pull Request
|
|
314
|
+
|
|
315
|
+
## 📚 Related
|
|
316
|
+
|
|
317
|
+
- [D1 Manager Worker API](https://github.com/your-username/n8n-d1-anub) - The backend API this node connects to
|
|
318
|
+
- [n8n](https://n8n.io) - Workflow automation tool
|
|
319
|
+
- [Cloudflare D1](https://developers.cloudflare.com/d1/) - SQLite at the Edge
|
|
320
|
+
|
|
321
|
+
## ❓ Support
|
|
322
|
+
|
|
323
|
+
If you encounter any issues or have questions, please [open an issue](https://github.com/your-username/n8n-nodes-db-anub/issues) on GitHub.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import {
|
|
2
|
+
IAuthenticateGeneric,
|
|
3
|
+
ICredentialTestRequest,
|
|
4
|
+
ICredentialType,
|
|
5
|
+
INodeProperties,
|
|
6
|
+
Icon,
|
|
7
|
+
} from 'n8n-workflow';
|
|
8
|
+
|
|
9
|
+
export class D1ManagerApi implements ICredentialType {
|
|
10
|
+
name = 'd1ManagerApi';
|
|
11
|
+
displayName = 'D1 Manager API';
|
|
12
|
+
documentationUrl = 'https://github.com/your-username/n8n-nodes-db-anub#readme';
|
|
13
|
+
icon: Icon = { light: 'file:d1manager-dark.svg', dark: 'file:d1manager-light.svg' };
|
|
14
|
+
|
|
15
|
+
properties: INodeProperties[] = [
|
|
16
|
+
{
|
|
17
|
+
displayName: 'Base URL',
|
|
18
|
+
name: 'baseUrl',
|
|
19
|
+
type: 'string',
|
|
20
|
+
default: 'https://your-worker.your-subdomain.workers.dev',
|
|
21
|
+
required: true,
|
|
22
|
+
description: 'The URL of your D1 Manager Worker',
|
|
23
|
+
placeholder: 'https://your-worker.your-subdomain.workers.dev',
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
displayName: 'API Key',
|
|
27
|
+
name: 'apiKey',
|
|
28
|
+
type: 'string',
|
|
29
|
+
typeOptions: { password: true },
|
|
30
|
+
default: '',
|
|
31
|
+
required: true,
|
|
32
|
+
description: 'The API key for authentication (x-api-key header)',
|
|
33
|
+
},
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
authenticate: IAuthenticateGeneric = {
|
|
37
|
+
type: 'generic',
|
|
38
|
+
properties: {
|
|
39
|
+
headers: {
|
|
40
|
+
'x-api-key': '={{$credentials.apiKey}}',
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
test: ICredentialTestRequest = {
|
|
46
|
+
request: {
|
|
47
|
+
baseURL: '={{$credentials.baseUrl}}',
|
|
48
|
+
url: '/databases',
|
|
49
|
+
method: 'GET',
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
@@ -0,0 +1,594 @@
|
|
|
1
|
+
import {
|
|
2
|
+
IExecuteFunctions,
|
|
3
|
+
INodeExecutionData,
|
|
4
|
+
INodeType,
|
|
5
|
+
INodeTypeDescription,
|
|
6
|
+
INodeProperties,
|
|
7
|
+
NodeApiError,
|
|
8
|
+
NodeOperationError,
|
|
9
|
+
ILoadOptionsFunctions,
|
|
10
|
+
INodeListSearchResult,
|
|
11
|
+
} from 'n8n-workflow';
|
|
12
|
+
|
|
13
|
+
// ============================================
|
|
14
|
+
// Resource & Operation Definitions
|
|
15
|
+
// ============================================
|
|
16
|
+
|
|
17
|
+
const databaseField: INodeProperties = {
|
|
18
|
+
displayName: 'Database',
|
|
19
|
+
name: 'database',
|
|
20
|
+
type: 'string',
|
|
21
|
+
default: '',
|
|
22
|
+
required: true,
|
|
23
|
+
description: 'Name of the D1 database binding (e.g., MY_DB, MATCHES_DB)',
|
|
24
|
+
placeholder: 'MY_DB',
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const tableField: INodeProperties = {
|
|
28
|
+
displayName: 'Table',
|
|
29
|
+
name: 'table',
|
|
30
|
+
type: 'string',
|
|
31
|
+
default: '',
|
|
32
|
+
required: true,
|
|
33
|
+
description: 'Name of the table to operate on',
|
|
34
|
+
placeholder: 'users',
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// ============================================
|
|
38
|
+
// WHERE Condition Fields
|
|
39
|
+
// ============================================
|
|
40
|
+
|
|
41
|
+
const whereField: INodeProperties = {
|
|
42
|
+
displayName: 'Where Conditions',
|
|
43
|
+
name: 'whereJson',
|
|
44
|
+
type: 'json',
|
|
45
|
+
default: '{}',
|
|
46
|
+
description: 'WHERE condition tree (JSON). Example: {"column": "id", "op": "=", "value": 1}',
|
|
47
|
+
displayOptions: {
|
|
48
|
+
show: {
|
|
49
|
+
resource: ['record'],
|
|
50
|
+
operation: ['select', 'update', 'delete', 'count', 'exists'],
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const columnsField: INodeProperties = {
|
|
56
|
+
displayName: 'Columns',
|
|
57
|
+
name: 'columns',
|
|
58
|
+
type: 'string',
|
|
59
|
+
default: '*',
|
|
60
|
+
description: 'Comma-separated list of columns to select, or * for all',
|
|
61
|
+
displayOptions: {
|
|
62
|
+
show: {
|
|
63
|
+
resource: ['record'],
|
|
64
|
+
operation: ['select'],
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const distinctField: INodeProperties = {
|
|
70
|
+
displayName: 'Distinct',
|
|
71
|
+
name: 'distinct',
|
|
72
|
+
type: 'boolean',
|
|
73
|
+
default: false,
|
|
74
|
+
description: 'Whether to return distinct rows only',
|
|
75
|
+
displayOptions: {
|
|
76
|
+
show: {
|
|
77
|
+
resource: ['record'],
|
|
78
|
+
operation: ['select'],
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const dataField: INodeProperties = {
|
|
84
|
+
displayName: 'Data',
|
|
85
|
+
name: 'dataJson',
|
|
86
|
+
type: 'json',
|
|
87
|
+
default: '{}',
|
|
88
|
+
description: 'Column values as JSON object (for single row) or array (for multiple rows)',
|
|
89
|
+
displayOptions: {
|
|
90
|
+
show: {
|
|
91
|
+
resource: ['record'],
|
|
92
|
+
operation: ['insert', 'update'],
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const orderField: INodeProperties = {
|
|
98
|
+
displayName: 'Order By',
|
|
99
|
+
name: 'orderJson',
|
|
100
|
+
type: 'json',
|
|
101
|
+
default: '[]',
|
|
102
|
+
description: 'Array of order clauses. Example: [{"column": "name", "dir": "asc"}]',
|
|
103
|
+
displayOptions: {
|
|
104
|
+
show: {
|
|
105
|
+
resource: ['record'],
|
|
106
|
+
operation: ['select'],
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
const limitField: INodeProperties = {
|
|
112
|
+
displayName: 'Limit',
|
|
113
|
+
name: 'limit',
|
|
114
|
+
type: 'number',
|
|
115
|
+
default: 100,
|
|
116
|
+
description: 'Maximum number of rows to return',
|
|
117
|
+
displayOptions: {
|
|
118
|
+
show: {
|
|
119
|
+
resource: ['record'],
|
|
120
|
+
operation: ['select'],
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
const offsetField: INodeProperties = {
|
|
126
|
+
displayName: 'Offset',
|
|
127
|
+
name: 'offset',
|
|
128
|
+
type: 'number',
|
|
129
|
+
default: 0,
|
|
130
|
+
description: 'Number of rows to skip',
|
|
131
|
+
displayOptions: {
|
|
132
|
+
show: {
|
|
133
|
+
resource: ['record'],
|
|
134
|
+
operation: ['select'],
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
const joinsField: INodeProperties = {
|
|
140
|
+
displayName: 'Joins',
|
|
141
|
+
name: 'joinsJson',
|
|
142
|
+
type: 'json',
|
|
143
|
+
default: '[]',
|
|
144
|
+
description: 'Array of JOIN clauses. Example: [{"type": "inner", "table": "orders", "on": "users.id = orders.user_id"}]',
|
|
145
|
+
displayOptions: {
|
|
146
|
+
show: {
|
|
147
|
+
resource: ['record'],
|
|
148
|
+
operation: ['select'],
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
const groupField: INodeProperties = {
|
|
154
|
+
displayName: 'Group By',
|
|
155
|
+
name: 'groupJson',
|
|
156
|
+
type: 'json',
|
|
157
|
+
default: '[]',
|
|
158
|
+
description: 'Array of column names to GROUP BY',
|
|
159
|
+
displayOptions: {
|
|
160
|
+
show: {
|
|
161
|
+
resource: ['record'],
|
|
162
|
+
operation: ['select'],
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
// ============================================
|
|
168
|
+
// Raw SQL Fields
|
|
169
|
+
// ============================================
|
|
170
|
+
|
|
171
|
+
const sqlField: INodeProperties = {
|
|
172
|
+
displayName: 'SQL Query',
|
|
173
|
+
name: 'sql',
|
|
174
|
+
type: 'string',
|
|
175
|
+
typeOptions: {
|
|
176
|
+
rows: 5,
|
|
177
|
+
},
|
|
178
|
+
default: '',
|
|
179
|
+
required: true,
|
|
180
|
+
description: 'Raw SQL query to execute',
|
|
181
|
+
displayOptions: {
|
|
182
|
+
show: {
|
|
183
|
+
resource: ['raw'],
|
|
184
|
+
operation: ['execute'],
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
// ============================================
|
|
190
|
+
// Batch Fields
|
|
191
|
+
// ============================================
|
|
192
|
+
|
|
193
|
+
const statementsField: INodeProperties = {
|
|
194
|
+
displayName: 'Statements',
|
|
195
|
+
name: 'statementsJson',
|
|
196
|
+
type: 'json',
|
|
197
|
+
default: '[]',
|
|
198
|
+
required: true,
|
|
199
|
+
description: 'Array of action objects to execute atomically. Example: [{"action": "insert", "table": "users", "data": {"name": "John"}}]',
|
|
200
|
+
displayOptions: {
|
|
201
|
+
show: {
|
|
202
|
+
resource: ['batch'],
|
|
203
|
+
operation: ['execute'],
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
// ============================================
|
|
209
|
+
// Main Node Class
|
|
210
|
+
// ============================================
|
|
211
|
+
|
|
212
|
+
export class D1Manager implements INodeType {
|
|
213
|
+
description: INodeTypeDescription = {
|
|
214
|
+
displayName: 'D1 Manager',
|
|
215
|
+
name: 'd1Manager',
|
|
216
|
+
icon: { light: 'file:d1manager-dark.svg', dark: 'file:d1manager-light.svg' },
|
|
217
|
+
group: ['transform'],
|
|
218
|
+
version: 1,
|
|
219
|
+
description: 'Interact with Cloudflare D1 databases via D1 Manager Worker API',
|
|
220
|
+
defaults: { name: 'D1 Manager' },
|
|
221
|
+
inputs: ['main'],
|
|
222
|
+
outputs: ['main'],
|
|
223
|
+
usableAsTool: true,
|
|
224
|
+
credentials: [
|
|
225
|
+
{ name: 'd1ManagerApi', required: true },
|
|
226
|
+
],
|
|
227
|
+
requestDefaults: {
|
|
228
|
+
headers: {
|
|
229
|
+
Accept: 'application/json',
|
|
230
|
+
'Content-Type': 'application/json',
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
properties: [
|
|
234
|
+
// Resource Selection
|
|
235
|
+
{
|
|
236
|
+
displayName: 'Resource',
|
|
237
|
+
name: 'resource',
|
|
238
|
+
type: 'options',
|
|
239
|
+
noDataExpression: true,
|
|
240
|
+
options: [
|
|
241
|
+
{ name: 'Record', value: 'record', description: 'Perform CRUD operations on a table' },
|
|
242
|
+
{ name: 'Raw SQL', value: 'raw', description: 'Execute raw SQL queries' },
|
|
243
|
+
{ name: 'Batch', value: 'batch', description: 'Execute multiple statements atomically' },
|
|
244
|
+
{ name: 'Database', value: 'database', description: 'List available databases' },
|
|
245
|
+
],
|
|
246
|
+
default: 'record',
|
|
247
|
+
},
|
|
248
|
+
|
|
249
|
+
// Operation Selection for Record
|
|
250
|
+
{
|
|
251
|
+
displayName: 'Operation',
|
|
252
|
+
name: 'operation',
|
|
253
|
+
type: 'options',
|
|
254
|
+
noDataExpression: true,
|
|
255
|
+
displayOptions: {
|
|
256
|
+
show: {
|
|
257
|
+
resource: ['record'],
|
|
258
|
+
},
|
|
259
|
+
},
|
|
260
|
+
options: [
|
|
261
|
+
{ name: 'Select', value: 'select', description: 'Retrieve records from a table', action: 'Select records' },
|
|
262
|
+
{ name: 'Insert', value: 'insert', description: 'Insert records into a table', action: 'Insert records' },
|
|
263
|
+
{ name: 'Update', value: 'update', description: 'Update records in a table', action: 'Update records' },
|
|
264
|
+
{ name: 'Delete', value: 'delete', description: 'Delete records from a table', action: 'Delete records' },
|
|
265
|
+
{ name: 'Count', value: 'count', description: 'Count records in a table', action: 'Count records' },
|
|
266
|
+
{ name: 'Exists', value: 'exists', description: 'Check if records exist', action: 'Check existence' },
|
|
267
|
+
],
|
|
268
|
+
default: 'select',
|
|
269
|
+
},
|
|
270
|
+
|
|
271
|
+
// Operation Selection for Raw SQL
|
|
272
|
+
{
|
|
273
|
+
displayName: 'Operation',
|
|
274
|
+
name: 'operation',
|
|
275
|
+
type: 'options',
|
|
276
|
+
noDataExpression: true,
|
|
277
|
+
displayOptions: {
|
|
278
|
+
show: {
|
|
279
|
+
resource: ['raw'],
|
|
280
|
+
},
|
|
281
|
+
},
|
|
282
|
+
options: [
|
|
283
|
+
{ name: 'Execute', value: 'execute', description: 'Execute a raw SQL query', action: 'Execute SQL' },
|
|
284
|
+
],
|
|
285
|
+
default: 'execute',
|
|
286
|
+
},
|
|
287
|
+
|
|
288
|
+
// Operation Selection for Batch
|
|
289
|
+
{
|
|
290
|
+
displayName: 'Operation',
|
|
291
|
+
name: 'operation',
|
|
292
|
+
type: 'options',
|
|
293
|
+
noDataExpression: true,
|
|
294
|
+
displayOptions: {
|
|
295
|
+
show: {
|
|
296
|
+
resource: ['batch'],
|
|
297
|
+
},
|
|
298
|
+
},
|
|
299
|
+
options: [
|
|
300
|
+
{ name: 'Execute', value: 'execute', description: 'Execute multiple statements atomically', action: 'Execute batch' },
|
|
301
|
+
],
|
|
302
|
+
default: 'execute',
|
|
303
|
+
},
|
|
304
|
+
|
|
305
|
+
// Operation Selection for Database
|
|
306
|
+
{
|
|
307
|
+
displayName: 'Operation',
|
|
308
|
+
name: 'operation',
|
|
309
|
+
type: 'options',
|
|
310
|
+
noDataExpression: true,
|
|
311
|
+
displayOptions: {
|
|
312
|
+
show: {
|
|
313
|
+
resource: ['database'],
|
|
314
|
+
},
|
|
315
|
+
},
|
|
316
|
+
options: [
|
|
317
|
+
{ name: 'List', value: 'list', description: 'List all configured D1 database bindings', action: 'List databases' },
|
|
318
|
+
],
|
|
319
|
+
default: 'list',
|
|
320
|
+
},
|
|
321
|
+
|
|
322
|
+
// Database & Table fields
|
|
323
|
+
{
|
|
324
|
+
...databaseField,
|
|
325
|
+
displayOptions: {
|
|
326
|
+
show: {
|
|
327
|
+
resource: ['record', 'raw', 'batch'],
|
|
328
|
+
},
|
|
329
|
+
},
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
...tableField,
|
|
333
|
+
displayOptions: {
|
|
334
|
+
show: {
|
|
335
|
+
resource: ['record'],
|
|
336
|
+
},
|
|
337
|
+
},
|
|
338
|
+
},
|
|
339
|
+
|
|
340
|
+
// Record operation fields
|
|
341
|
+
columnsField,
|
|
342
|
+
distinctField,
|
|
343
|
+
whereField,
|
|
344
|
+
dataField,
|
|
345
|
+
orderField,
|
|
346
|
+
limitField,
|
|
347
|
+
offsetField,
|
|
348
|
+
joinsField,
|
|
349
|
+
groupField,
|
|
350
|
+
|
|
351
|
+
// Raw SQL fields
|
|
352
|
+
sqlField,
|
|
353
|
+
|
|
354
|
+
// Batch fields
|
|
355
|
+
statementsField,
|
|
356
|
+
],
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
// ============================================
|
|
360
|
+
// List Search Methods
|
|
361
|
+
// ============================================
|
|
362
|
+
|
|
363
|
+
methods = {
|
|
364
|
+
listSearch: {
|
|
365
|
+
async getDatabases(this: ILoadOptionsFunctions, filter?: string): Promise<INodeListSearchResult> {
|
|
366
|
+
const credentials = await this.getCredentials('d1ManagerApi');
|
|
367
|
+
const baseUrl = credentials.baseUrl as string;
|
|
368
|
+
const apiKey = credentials.apiKey as string;
|
|
369
|
+
|
|
370
|
+
try {
|
|
371
|
+
const response = await this.helpers.httpRequest({
|
|
372
|
+
method: 'GET',
|
|
373
|
+
url: `${baseUrl}/databases`,
|
|
374
|
+
headers: {
|
|
375
|
+
'x-api-key': apiKey,
|
|
376
|
+
},
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
const databases = (response as any).data?.databases || [];
|
|
380
|
+
return {
|
|
381
|
+
results: databases
|
|
382
|
+
.filter((db: string) => !filter || db.toLowerCase().includes(filter.toLowerCase()))
|
|
383
|
+
.map((db: string) => ({ name: db, value: db })),
|
|
384
|
+
};
|
|
385
|
+
} catch (error) {
|
|
386
|
+
return { results: [] };
|
|
387
|
+
}
|
|
388
|
+
},
|
|
389
|
+
},
|
|
390
|
+
};
|
|
391
|
+
|
|
392
|
+
// ============================================
|
|
393
|
+
// Execute Method
|
|
394
|
+
// ============================================
|
|
395
|
+
|
|
396
|
+
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
|
397
|
+
const items = this.getInputData();
|
|
398
|
+
const returnData: INodeExecutionData[] = [];
|
|
399
|
+
const credentials = await this.getCredentials('d1ManagerApi');
|
|
400
|
+
const baseUrl = credentials.baseUrl as string;
|
|
401
|
+
const apiKey = credentials.apiKey as string;
|
|
402
|
+
|
|
403
|
+
for (let i = 0; i < items.length; i++) {
|
|
404
|
+
try {
|
|
405
|
+
const resource = this.getNodeParameter('resource', i) as string;
|
|
406
|
+
const operation = this.getNodeParameter('operation', i) as string;
|
|
407
|
+
|
|
408
|
+
let response: any;
|
|
409
|
+
|
|
410
|
+
// ============================================
|
|
411
|
+
// Database Operations
|
|
412
|
+
// ============================================
|
|
413
|
+
if (resource === 'database' && operation === 'list') {
|
|
414
|
+
response = await this.helpers.httpRequest({
|
|
415
|
+
method: 'GET',
|
|
416
|
+
url: `${baseUrl}/databases`,
|
|
417
|
+
headers: {
|
|
418
|
+
'x-api-key': apiKey,
|
|
419
|
+
},
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// ============================================
|
|
424
|
+
// Record Operations
|
|
425
|
+
// ============================================
|
|
426
|
+
else if (resource === 'record') {
|
|
427
|
+
const database = this.getNodeParameter('database', i) as string;
|
|
428
|
+
const table = this.getNodeParameter('table', i) as string;
|
|
429
|
+
|
|
430
|
+
const body: any = {
|
|
431
|
+
database,
|
|
432
|
+
action: operation,
|
|
433
|
+
table,
|
|
434
|
+
};
|
|
435
|
+
|
|
436
|
+
// Add operation-specific parameters
|
|
437
|
+
if (operation === 'select') {
|
|
438
|
+
const columns = this.getNodeParameter('columns', i) as string;
|
|
439
|
+
const distinct = this.getNodeParameter('distinct', i) as boolean;
|
|
440
|
+
const whereJson = this.getNodeParameter('whereJson', i) as string;
|
|
441
|
+
const orderJson = this.getNodeParameter('orderJson', i) as string;
|
|
442
|
+
const limit = this.getNodeParameter('limit', i) as number;
|
|
443
|
+
const offset = this.getNodeParameter('offset', i) as number;
|
|
444
|
+
const joinsJson = this.getNodeParameter('joinsJson', i) as string;
|
|
445
|
+
const groupJson = this.getNodeParameter('groupJson', i) as string;
|
|
446
|
+
|
|
447
|
+
if (columns && columns !== '*') {
|
|
448
|
+
body.columns = columns.split(',').map((c) => c.trim());
|
|
449
|
+
}
|
|
450
|
+
if (distinct) {
|
|
451
|
+
body.distinct = true;
|
|
452
|
+
}
|
|
453
|
+
if (whereJson && whereJson !== '{}') {
|
|
454
|
+
body.where = JSON.parse(whereJson);
|
|
455
|
+
}
|
|
456
|
+
if (orderJson && orderJson !== '[]') {
|
|
457
|
+
body.order = JSON.parse(orderJson);
|
|
458
|
+
}
|
|
459
|
+
if (limit) {
|
|
460
|
+
body.limit = limit;
|
|
461
|
+
}
|
|
462
|
+
if (offset) {
|
|
463
|
+
body.offset = offset;
|
|
464
|
+
}
|
|
465
|
+
if (joinsJson && joinsJson !== '[]') {
|
|
466
|
+
body.joins = JSON.parse(joinsJson);
|
|
467
|
+
}
|
|
468
|
+
if (groupJson && groupJson !== '[]') {
|
|
469
|
+
body.group = JSON.parse(groupJson);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
if (operation === 'insert' || operation === 'update') {
|
|
474
|
+
const dataJson = this.getNodeParameter('dataJson', i) as string;
|
|
475
|
+
if (dataJson && dataJson !== '{}') {
|
|
476
|
+
body.data = JSON.parse(dataJson);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
if (['update', 'delete', 'count', 'exists'].includes(operation)) {
|
|
481
|
+
const whereJson = this.getNodeParameter('whereJson', i) as string;
|
|
482
|
+
if (whereJson && whereJson !== '{}') {
|
|
483
|
+
body.where = JSON.parse(whereJson);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
response = await this.helpers.httpRequest({
|
|
488
|
+
method: 'POST',
|
|
489
|
+
url: `${baseUrl}/query`,
|
|
490
|
+
headers: {
|
|
491
|
+
'Content-Type': 'application/json',
|
|
492
|
+
'x-api-key': apiKey,
|
|
493
|
+
},
|
|
494
|
+
body,
|
|
495
|
+
json: true,
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// ============================================
|
|
500
|
+
// Raw SQL Operations
|
|
501
|
+
// ============================================
|
|
502
|
+
else if (resource === 'raw' && operation === 'execute') {
|
|
503
|
+
const database = this.getNodeParameter('database', i) as string;
|
|
504
|
+
const sql = this.getNodeParameter('sql', i) as string;
|
|
505
|
+
|
|
506
|
+
response = await this.helpers.httpRequest({
|
|
507
|
+
method: 'POST',
|
|
508
|
+
url: `${baseUrl}/raw`,
|
|
509
|
+
headers: {
|
|
510
|
+
'Content-Type': 'application/json',
|
|
511
|
+
'x-api-key': apiKey,
|
|
512
|
+
},
|
|
513
|
+
body: {
|
|
514
|
+
database,
|
|
515
|
+
sql,
|
|
516
|
+
},
|
|
517
|
+
json: true,
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// ============================================
|
|
522
|
+
// Batch Operations
|
|
523
|
+
// ============================================
|
|
524
|
+
else if (resource === 'batch' && operation === 'execute') {
|
|
525
|
+
const database = this.getNodeParameter('database', i) as string;
|
|
526
|
+
const statementsJson = this.getNodeParameter('statementsJson', i) as string;
|
|
527
|
+
|
|
528
|
+
response = await this.helpers.httpRequest({
|
|
529
|
+
method: 'POST',
|
|
530
|
+
url: `${baseUrl}/query`,
|
|
531
|
+
headers: {
|
|
532
|
+
'Content-Type': 'application/json',
|
|
533
|
+
'x-api-key': apiKey,
|
|
534
|
+
},
|
|
535
|
+
body: {
|
|
536
|
+
database,
|
|
537
|
+
action: 'batch',
|
|
538
|
+
statements: JSON.parse(statementsJson),
|
|
539
|
+
},
|
|
540
|
+
json: true,
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// ============================================
|
|
545
|
+
// Process Response
|
|
546
|
+
// ============================================
|
|
547
|
+
if (response) {
|
|
548
|
+
returnData.push({
|
|
549
|
+
json: response,
|
|
550
|
+
pairedItem: { item: i },
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
} catch (error: any) {
|
|
554
|
+
if (this.continueOnFail()) {
|
|
555
|
+
returnData.push({
|
|
556
|
+
json: {
|
|
557
|
+
success: false,
|
|
558
|
+
error: {
|
|
559
|
+
message: error.message,
|
|
560
|
+
code: error.code || 'UNKNOWN_ERROR',
|
|
561
|
+
},
|
|
562
|
+
},
|
|
563
|
+
pairedItem: { item: i },
|
|
564
|
+
});
|
|
565
|
+
continue;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
// Handle specific error codes
|
|
569
|
+
if (error.statusCode === 401) {
|
|
570
|
+
throw new NodeApiError(this.getNode(), error, {
|
|
571
|
+
message: 'Unauthorized - Missing or invalid API key',
|
|
572
|
+
description: 'Please check your x-api-key header in the credentials',
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
if (error.statusCode === 403) {
|
|
576
|
+
throw new NodeApiError(this.getNode(), error, {
|
|
577
|
+
message: 'Forbidden - Invalid API key',
|
|
578
|
+
description: 'The provided API key is not valid',
|
|
579
|
+
});
|
|
580
|
+
}
|
|
581
|
+
if (error.statusCode === 422) {
|
|
582
|
+
throw new NodeApiError(this.getNode(), error, {
|
|
583
|
+
message: 'Validation Error',
|
|
584
|
+
description: error.message || 'Invalid payload structure',
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
throw new NodeOperationError(this.getNode(), error.message, { itemIndex: i });
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
return [returnData];
|
|
593
|
+
}
|
|
594
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#333333" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
2
|
+
<!-- Database cylinder -->
|
|
3
|
+
<ellipse cx="12" cy="5" rx="9" ry="3"/>
|
|
4
|
+
<path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3"/>
|
|
5
|
+
<path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5"/>
|
|
6
|
+
<!-- Cloudflare D1 indicator -->
|
|
7
|
+
<circle cx="18" cy="18" r="4" fill="#F6821F" stroke="none"/>
|
|
8
|
+
<text x="18" y="20" text-anchor="middle" font-size="5" font-weight="bold" fill="white" font-family="Arial, sans-serif">D1</text>
|
|
9
|
+
</svg>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#FFFFFF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
2
|
+
<!-- Database cylinder -->
|
|
3
|
+
<ellipse cx="12" cy="5" rx="9" ry="3"/>
|
|
4
|
+
<path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3"/>
|
|
5
|
+
<path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5"/>
|
|
6
|
+
<!-- Cloudflare D1 indicator -->
|
|
7
|
+
<circle cx="18" cy="18" r="4" fill="#F6821F" stroke="none"/>
|
|
8
|
+
<text x="18" y="20" text-anchor="middle" font-size="5" font-weight="bold" fill="white" font-family="Arial, sans-serif">D1</text>
|
|
9
|
+
</svg>
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "n8n-nodes-db-anub",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "n8n node for Cloudflare D1 Manager Worker API - Manage D1 databases with select, insert, update, delete, and more",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"main": "index.js",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "n8n-node build",
|
|
9
|
+
"dev": "n8n-node dev",
|
|
10
|
+
"lint": "n8n-node lint",
|
|
11
|
+
"lint:fix": "n8n-node lint --fix"
|
|
12
|
+
},
|
|
13
|
+
"n8n": {
|
|
14
|
+
"n8nNodesApiVersion": 1,
|
|
15
|
+
"credentials": [
|
|
16
|
+
"dist/credentials/D1ManagerApi.credentials.js"
|
|
17
|
+
],
|
|
18
|
+
"nodes": [
|
|
19
|
+
"dist/nodes/D1Manager/D1Manager.node.js"
|
|
20
|
+
]
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@n8n/node-cli": "*"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"n8n-community-node-package",
|
|
27
|
+
"n8n",
|
|
28
|
+
"cloudflare",
|
|
29
|
+
"d1",
|
|
30
|
+
"database",
|
|
31
|
+
"sqlite",
|
|
32
|
+
"worker"
|
|
33
|
+
],
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "https://github.com/your-username/n8n-nodes-db-anub.git"
|
|
37
|
+
},
|
|
38
|
+
"bugs": {
|
|
39
|
+
"url": "https://github.com/your-username/n8n-nodes-db-anub/issues"
|
|
40
|
+
},
|
|
41
|
+
"homepage": "https://github.com/your-username/n8n-nodes-db-anub#readme",
|
|
42
|
+
"author": "Your Name <your-email@example.com>"
|
|
43
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"module": "commonjs",
|
|
4
|
+
"target": "ES2019",
|
|
5
|
+
"outDir": "dist",
|
|
6
|
+
"rootDir": ".",
|
|
7
|
+
"strict": true,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"forceConsistentCasingInFileNames": true,
|
|
11
|
+
"declaration": true,
|
|
12
|
+
"declarationMap": true,
|
|
13
|
+
"sourceMap": true,
|
|
14
|
+
"resolveJsonModule": true,
|
|
15
|
+
"moduleResolution": "bundler"
|
|
16
|
+
},
|
|
17
|
+
"include": [
|
|
18
|
+
"credentials/**/*",
|
|
19
|
+
"nodes/**/*"
|
|
20
|
+
],
|
|
21
|
+
"exclude": [
|
|
22
|
+
"node_modules",
|
|
23
|
+
"dist"
|
|
24
|
+
]
|
|
25
|
+
}
|