n8n-nodes-bun 0.1.2

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,315 @@
1
+ # n8n-nodes-bun
2
+
3
+ An [n8n](https://n8n.io) community node that lets you execute **TypeScript and JavaScript code using the [Bun](https://bun.sh) runtime** — with full system access, native TypeScript support, and all Bun APIs available.
4
+
5
+ Unlike the built-in Code node (which runs in a sandboxed VM), this node spawns a real Bun process. Your code can use the filesystem, network, Bun-specific APIs, npm packages, and anything else Bun supports.
6
+
7
+ ![n8n Bun Code Node](https://img.shields.io/badge/n8n-community%20node-ff6d5a) ![License: MIT](https://img.shields.io/badge/license-MIT-blue)
8
+
9
+ ## Features
10
+
11
+ - **Native TypeScript** — Bun runs `.ts` files directly, no compilation step
12
+ - **Full Bun runtime** — access `Bun.file()`, `Bun.serve()`, `Bun.sleep()`, `fetch()`, and all Bun APIs
13
+ - **No sandbox** — code executes with full system access (read/write files, spawn processes, network calls)
14
+ - **Two execution modes** — "Run Once for All Items" and "Run Once for Each Item", matching the standard Code node
15
+ - **n8n-compatible helpers** — familiar `$input`, `$json`, `items` variables
16
+ - **Error handling** — supports n8n's "Continue on Fail" setting
17
+ - **60-second timeout** — prevents runaway scripts
18
+
19
+ ## Prerequisites
20
+
21
+ - **n8n** — self-hosted instance (v1.0+)
22
+ - **Bun** — installed on the same machine running n8n
23
+
24
+ Install Bun:
25
+ ```bash
26
+ curl -fsSL https://bun.sh/install | bash
27
+ ```
28
+
29
+ Verify it's available:
30
+ ```bash
31
+ bun --version
32
+ ```
33
+
34
+ ## Installation
35
+
36
+ ### In n8n (Community Nodes)
37
+
38
+ 1. Go to **Settings > Community Nodes**
39
+ 2. Enter `n8n-nodes-bun`
40
+ 3. Click **Install**
41
+ 4. Restart n8n
42
+
43
+ ### Manual / Docker
44
+
45
+ ```bash
46
+ # From your n8n installation directory
47
+ npm install n8n-nodes-bun
48
+
49
+ # Restart n8n
50
+ ```
51
+
52
+ For Docker, add to your Dockerfile:
53
+ ```dockerfile
54
+ RUN npm install n8n-nodes-bun
55
+ ```
56
+
57
+ > Make sure Bun is also installed in your Docker image. See [Bun Docker docs](https://bun.sh/guides/ecosystem/docker).
58
+
59
+ ### From source
60
+
61
+ ```bash
62
+ git clone https://github.com/borgius/n8n-nodes-bun.git
63
+ cd n8n-nodes-bun
64
+ npm install
65
+ npm run build
66
+
67
+ # Link into your n8n installation
68
+ npm link
69
+ cd /path/to/n8n
70
+ npm link n8n-nodes-bun
71
+ ```
72
+
73
+ ## Usage
74
+
75
+ After installation, search for **"Bun Code"** in the n8n node panel.
76
+
77
+ ### Execution Modes
78
+
79
+ #### Run Once for All Items
80
+
81
+ Your code runs a single time and receives all input items at once. Return an array of items.
82
+
83
+ ```typescript
84
+ // Access all input items
85
+ const items = $input.all();
86
+
87
+ // Transform each item
88
+ return items.map(item => ({
89
+ json: {
90
+ ...item.json,
91
+ processed: true,
92
+ timestamp: Date.now(),
93
+ }
94
+ }));
95
+ ```
96
+
97
+ #### Run Once for Each Item
98
+
99
+ Your code runs separately for each input item. Return a single item.
100
+
101
+ ```typescript
102
+ // Access the current item
103
+ const item = $input.item;
104
+
105
+ // Transform it
106
+ return {
107
+ json: {
108
+ ...item.json,
109
+ uppercased: item.json.name.toUpperCase(),
110
+ }
111
+ };
112
+ ```
113
+
114
+ ### Available Variables
115
+
116
+ | Variable | Mode | Description |
117
+ |----------|------|-------------|
118
+ | `$input.all()` | Both | Returns all input items as an array |
119
+ | `$input.first()` | Both | Returns the first input item |
120
+ | `$input.last()` | Both | Returns the last input item |
121
+ | `$input.item` | Each Item | The current item being processed |
122
+ | `items` | All Items | Alias for `$input.all()` — all input items |
123
+ | `item` | Each Item | Alias for `$input.item` — current item |
124
+ | `$json` | Both | Shortcut to the `.json` property of the first/current item |
125
+
126
+ ### Item Format
127
+
128
+ Each item follows the n8n data structure:
129
+
130
+ ```typescript
131
+ {
132
+ json: {
133
+ // your data here
134
+ key: "value",
135
+ count: 42,
136
+ }
137
+ }
138
+ ```
139
+
140
+ When returning data, you can return either:
141
+ - **Proper n8n items** — objects with a `json` property: `{ json: { ... } }`
142
+ - **Plain objects** — automatically wrapped in `{ json: ... }` for you
143
+ - **Primitives** — wrapped as `{ json: { data: value } }`
144
+
145
+ ## Examples
146
+
147
+ ### Use TypeScript features
148
+
149
+ ```typescript
150
+ interface User {
151
+ name: string;
152
+ email: string;
153
+ age: number;
154
+ }
155
+
156
+ const users: User[] = $input.all().map(item => item.json as User);
157
+
158
+ const adults = users.filter(u => u.age >= 18);
159
+
160
+ return adults.map(u => ({
161
+ json: { name: u.name, email: u.email, isAdult: true }
162
+ }));
163
+ ```
164
+
165
+ ### Read a file from disk
166
+
167
+ ```typescript
168
+ import { readFileSync } from 'fs';
169
+
170
+ const config = JSON.parse(readFileSync('/etc/myapp/config.json', 'utf-8'));
171
+
172
+ return [{ json: config }];
173
+ ```
174
+
175
+ ### Use Bun APIs
176
+
177
+ ```typescript
178
+ // Read a file with Bun's fast API
179
+ const file = Bun.file('/tmp/data.csv');
180
+ const text = await file.text();
181
+
182
+ const rows = text.split('\n').map(line => {
183
+ const [name, value] = line.split(',');
184
+ return { json: { name, value } };
185
+ });
186
+
187
+ return rows;
188
+ ```
189
+
190
+ ### Make HTTP requests
191
+
192
+ ```typescript
193
+ const response = await fetch('https://api.example.com/data', {
194
+ headers: { 'Authorization': 'Bearer my-token' },
195
+ });
196
+
197
+ const data = await response.json();
198
+
199
+ return Array.isArray(data)
200
+ ? data.map(item => ({ json: item }))
201
+ : [{ json: data }];
202
+ ```
203
+
204
+ ### Hash passwords with Bun
205
+
206
+ ```typescript
207
+ const items = $input.all();
208
+
209
+ return items.map(item => ({
210
+ json: {
211
+ ...item.json,
212
+ passwordHash: Bun.hash(item.json.password as string).toString(),
213
+ }
214
+ }));
215
+ ```
216
+
217
+ ### Run a shell command
218
+
219
+ ```typescript
220
+ const proc = Bun.spawn(['ls', '-la', '/tmp']);
221
+ const output = await new Response(proc.stdout).text();
222
+
223
+ return [{
224
+ json: {
225
+ files: output.split('\n').filter(Boolean),
226
+ }
227
+ }];
228
+ ```
229
+
230
+ ### Process items with async operations
231
+
232
+ ```typescript
233
+ const items = $input.all();
234
+
235
+ const results = await Promise.all(
236
+ items.map(async (item) => {
237
+ const resp = await fetch(`https://api.example.com/enrich/${item.json.id}`);
238
+ const extra = await resp.json();
239
+ return {
240
+ json: { ...item.json, ...extra },
241
+ };
242
+ })
243
+ );
244
+
245
+ return results;
246
+ ```
247
+
248
+ ## How It Works
249
+
250
+ 1. Your code is wrapped in a template that provides the `$input`, `$json`, `items` helpers
251
+ 2. The template + your code are written to a temporary `.ts` file
252
+ 3. Input items are serialized to a temporary JSON file
253
+ 4. `bun run script.ts` is spawned as a child process
254
+ 5. Your code reads input, executes, and writes output to another temp JSON file
255
+ 6. The node reads the output and passes it downstream in n8n
256
+ 7. All temp files are cleaned up
257
+
258
+ ```
259
+ n8n node Bun child process
260
+ ┌─────────────┐ ┌─────────────────┐
261
+ │ Serialize │──input.json───> │ Read input │
262
+ │ input items │ │ Provide helpers │
263
+ │ │ │ Execute user code│
264
+ │ Parse output │<─output.json── │ Write result │
265
+ │ items │ │ │
266
+ └─────────────┘ └─────────────────┘
267
+ ```
268
+
269
+ ## Security Considerations
270
+
271
+ This node executes code **without any sandbox**. The Bun process has full access to:
272
+
273
+ - The filesystem (read/write any file the n8n process user can access)
274
+ - The network (make any outbound connections)
275
+ - Environment variables
276
+ - Child process spawning
277
+ - All Bun and Node.js APIs
278
+
279
+ **Only install this node on n8n instances where you trust all workflow editors.** It is not suitable for multi-tenant environments where untrusted users can create workflows.
280
+
281
+ ## Limitations
282
+
283
+ - **Binary data** — n8n binary attachments are not passed through to the Bun process. Work with `json` data or read files directly.
284
+ - **n8n context** — advanced n8n helpers like `$getWorkflowStaticData`, `helpers.httpRequestWithAuthentication`, and credential access are not available inside the Bun process. Use `fetch()` or Bun APIs directly.
285
+ - **Console output** — `console.log()` output from your code goes to the Bun process stderr/stdout and is not displayed in the n8n UI.
286
+ - **Execution timeout** — scripts are killed after 60 seconds.
287
+ - **Requires Bun installed** — the `bun` binary must be in the system PATH on the machine running n8n.
288
+
289
+ ## Development
290
+
291
+ ```bash
292
+ git clone https://github.com/borgius/n8n-nodes-bun.git
293
+ cd n8n-nodes-bun
294
+ npm install
295
+ npm run build # compile TypeScript + copy assets
296
+ npm run dev # watch mode (tsc --watch)
297
+ ```
298
+
299
+ ### Project structure
300
+
301
+ ```
302
+ n8n-nodes-bun/
303
+ ├── package.json # n8n community node registration
304
+ ├── tsconfig.json
305
+ ├── nodes/
306
+ │ └── BunCode/
307
+ │ ├── BunCode.node.ts # Node class (UI config + execute)
308
+ │ ├── runBunCode.ts # Bun execution engine
309
+ │ └── bunCode.svg # Node icon
310
+ └── dist/ # Build output (published to npm)
311
+ ```
312
+
313
+ ## License
314
+
315
+ [MIT](LICENSE)
@@ -0,0 +1,5 @@
1
+ import { type IExecuteFunctions, type INodeExecutionData, type INodeType, type INodeTypeDescription } from 'n8n-workflow';
2
+ export declare class BunCode implements INodeType {
3
+ description: INodeTypeDescription;
4
+ execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
5
+ }
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BunCode = void 0;
4
+ const n8n_workflow_1 = require("n8n-workflow");
5
+ const runBunCode_1 = require("./runBunCode");
6
+ class BunCode {
7
+ description = {
8
+ displayName: 'Bun Code',
9
+ name: 'bunCode',
10
+ icon: 'file:bunCode.svg',
11
+ group: ['transform'],
12
+ version: 1,
13
+ description: 'Run TypeScript/JavaScript code using Bun runtime',
14
+ defaults: {
15
+ name: 'Bun Code',
16
+ },
17
+ inputs: [n8n_workflow_1.NodeConnectionTypes.Main],
18
+ outputs: [n8n_workflow_1.NodeConnectionTypes.Main],
19
+ parameterPane: 'wide',
20
+ properties: [
21
+ {
22
+ displayName: 'Mode',
23
+ name: 'mode',
24
+ type: 'options',
25
+ noDataExpression: true,
26
+ options: [
27
+ {
28
+ name: 'Run Once for All Items',
29
+ value: 'runOnceForAllItems',
30
+ description: 'Run this code only once, no matter how many input items there are',
31
+ },
32
+ {
33
+ name: 'Run Once for Each Item',
34
+ value: 'runOnceForEachItem',
35
+ description: 'Run this code as many times as there are input items',
36
+ },
37
+ ],
38
+ default: 'runOnceForAllItems',
39
+ },
40
+ {
41
+ displayName: 'TypeScript/JavaScript Code',
42
+ name: 'code',
43
+ type: 'string',
44
+ typeOptions: {
45
+ editor: 'codeNodeEditor',
46
+ editorLanguage: 'javaScript',
47
+ },
48
+ default: '// Access input items with $input.all()\nconst items = $input.all();\n\nreturn items;',
49
+ noDataExpression: true,
50
+ description: 'TypeScript or JavaScript code to execute with Bun. Full Bun API available.',
51
+ displayOptions: {
52
+ show: {
53
+ mode: ['runOnceForAllItems'],
54
+ },
55
+ },
56
+ },
57
+ {
58
+ displayName: 'TypeScript/JavaScript Code',
59
+ name: 'code',
60
+ type: 'string',
61
+ typeOptions: {
62
+ editor: 'codeNodeEditor',
63
+ editorLanguage: 'javaScript',
64
+ },
65
+ default: '// Access current item with $input.item\nconst item = $input.item;\n\nreturn item;',
66
+ noDataExpression: true,
67
+ description: 'TypeScript or JavaScript code to execute with Bun. Full Bun API available.',
68
+ displayOptions: {
69
+ show: {
70
+ mode: ['runOnceForEachItem'],
71
+ },
72
+ },
73
+ },
74
+ {
75
+ displayName: 'Bun natively supports TypeScript, top-level await, and fast built-in APIs. No sandbox — code runs with full system access. <a href="https://bun.sh/docs" target="_blank">Bun docs</a>',
76
+ name: 'notice',
77
+ type: 'notice',
78
+ default: '',
79
+ },
80
+ ],
81
+ };
82
+ async execute() {
83
+ const mode = this.getNodeParameter('mode', 0);
84
+ const code = this.getNodeParameter('code', 0);
85
+ const inputItems = this.getInputData();
86
+ try {
87
+ const result = await (0, runBunCode_1.runBunCode)(code, inputItems, mode);
88
+ return [result];
89
+ }
90
+ catch (error) {
91
+ if (this.continueOnFail()) {
92
+ return [[{ json: { error: error.message } }]];
93
+ }
94
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), error);
95
+ }
96
+ }
97
+ }
98
+ exports.BunCode = BunCode;
99
+ //# sourceMappingURL=BunCode.node.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BunCode.node.js","sourceRoot":"","sources":["../../../nodes/BunCode/BunCode.node.ts"],"names":[],"mappings":";;;AAAA,+CAOsB;AAEtB,6CAA0C;AAE1C,MAAa,OAAO;IACnB,WAAW,GAAyB;QACnC,WAAW,EAAE,UAAU;QACvB,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,kBAAkB;QACxB,KAAK,EAAE,CAAC,WAAW,CAAC;QACpB,OAAO,EAAE,CAAC;QACV,WAAW,EAAE,kDAAkD;QAC/D,QAAQ,EAAE;YACT,IAAI,EAAE,UAAU;SAChB;QACD,MAAM,EAAE,CAAC,kCAAmB,CAAC,IAAI,CAAC;QAClC,OAAO,EAAE,CAAC,kCAAmB,CAAC,IAAI,CAAC;QACnC,aAAa,EAAE,MAAM;QACrB,UAAU,EAAE;YACX;gBACC,WAAW,EAAE,MAAM;gBACnB,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,SAAS;gBACf,gBAAgB,EAAE,IAAI;gBACtB,OAAO,EAAE;oBACR;wBACC,IAAI,EAAE,wBAAwB;wBAC9B,KAAK,EAAE,oBAAoB;wBAC3B,WAAW,EACV,mEAAmE;qBACpE;oBACD;wBACC,IAAI,EAAE,wBAAwB;wBAC9B,KAAK,EAAE,oBAAoB;wBAC3B,WAAW,EACV,sDAAsD;qBACvD;iBACD;gBACD,OAAO,EAAE,oBAAoB;aAC7B;YACD;gBACC,WAAW,EAAE,4BAA4B;gBACzC,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE;oBACZ,MAAM,EAAE,gBAAgB;oBACxB,cAAc,EAAE,YAAY;iBAC5B;gBACD,OAAO,EACN,uFAAuF;gBACxF,gBAAgB,EAAE,IAAI;gBACtB,WAAW,EACV,4EAA4E;gBAC7E,cAAc,EAAE;oBACf,IAAI,EAAE;wBACL,IAAI,EAAE,CAAC,oBAAoB,CAAC;qBAC5B;iBACD;aACD;YACD;gBACC,WAAW,EAAE,4BAA4B;gBACzC,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE;oBACZ,MAAM,EAAE,gBAAgB;oBACxB,cAAc,EAAE,YAAY;iBAC5B;gBACD,OAAO,EACN,oFAAoF;gBACrF,gBAAgB,EAAE,IAAI;gBACtB,WAAW,EACV,4EAA4E;gBAC7E,cAAc,EAAE;oBACf,IAAI,EAAE;wBACL,IAAI,EAAE,CAAC,oBAAoB,CAAC;qBAC5B;iBACD;aACD;YACD;gBACC,WAAW,EACV,uLAAuL;gBACxL,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,EAAE;aACX;SACD;KACD,CAAC;IAEF,KAAK,CAAC,OAAO;QACZ,MAAM,IAAI,GAAG,IAAI,CAAC,gBAAgB,CAAC,MAAM,EAAE,CAAC,CAAW,CAAC;QACxD,MAAM,IAAI,GAAG,IAAI,CAAC,gBAAgB,CAAC,MAAM,EAAE,CAAC,CAAW,CAAC;QACxD,MAAM,UAAU,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;QAEvC,IAAI,CAAC;YACJ,MAAM,MAAM,GAAG,MAAM,IAAA,uBAAU,EAAC,IAAI,EAAE,UAAU,EAAE,IAAI,CAAC,CAAC;YACxD,OAAO,CAAC,MAAM,CAAC,CAAC;QACjB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,IAAI,IAAI,CAAC,cAAc,EAAE,EAAE,CAAC;gBAC3B,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,KAAK,EAAG,KAAe,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;YAC1D,CAAC;YACD,MAAM,IAAI,iCAAkB,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,KAAc,CAAC,CAAC;QAC9D,CAAC;IACF,CAAC;CACD;AAnGD,0BAmGC"}
@@ -0,0 +1,22 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 80 80" fill="none">
2
+ <rect width="80" height="80" rx="16" fill="#fbf0df"/>
3
+ <g transform="translate(40,44)">
4
+ <!-- bun body -->
5
+ <ellipse cx="0" cy="2" rx="22" ry="18" fill="#fbbd6a"/>
6
+ <!-- bun top lines -->
7
+ <path d="M-8,-14 Q-6,-22 -2,-14" stroke="#c48a3f" stroke-width="2" fill="none" stroke-linecap="round"/>
8
+ <path d="M0,-16 Q2,-24 4,-16" stroke="#c48a3f" stroke-width="2" fill="none" stroke-linecap="round"/>
9
+ <path d="M6,-14 Q8,-22 12,-14" stroke="#c48a3f" stroke-width="2" fill="none" stroke-linecap="round"/>
10
+ <!-- face -->
11
+ <circle cx="-8" cy="2" r="2.5" fill="#3d2b1f"/>
12
+ <circle cx="8" cy="2" r="2.5" fill="#3d2b1f"/>
13
+ <!-- rosy cheeks -->
14
+ <ellipse cx="-14" cy="6" rx="3" ry="2" fill="#f4a0a0" opacity="0.5"/>
15
+ <ellipse cx="14" cy="6" rx="3" ry="2" fill="#f4a0a0" opacity="0.5"/>
16
+ <!-- smile -->
17
+ <path d="M-4,7 Q0,12 4,7" stroke="#3d2b1f" stroke-width="1.5" fill="none" stroke-linecap="round"/>
18
+ </g>
19
+ <!-- TS badge -->
20
+ <rect x="52" y="4" width="24" height="16" rx="4" fill="#3178c6"/>
21
+ <text x="64" y="15.5" text-anchor="middle" font-family="Arial,sans-serif" font-weight="bold" font-size="10" fill="white">TS</text>
22
+ </svg>
@@ -0,0 +1,2 @@
1
+ import type { INodeExecutionData } from 'n8n-workflow';
2
+ export declare function runBunCode(userCode: string, inputItems: INodeExecutionData[], mode: string): Promise<INodeExecutionData[]>;
@@ -0,0 +1,143 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runBunCode = runBunCode;
4
+ const child_process_1 = require("child_process");
5
+ const promises_1 = require("fs/promises");
6
+ const path_1 = require("path");
7
+ const os_1 = require("os");
8
+ function buildAllItemsTemplate(userCode, inputPath, outputPath) {
9
+ return `
10
+ import { readFileSync, writeFileSync } from 'fs';
11
+
12
+ const __inputData: any[] = JSON.parse(readFileSync(${JSON.stringify(inputPath)}, 'utf-8'));
13
+
14
+ const $input = {
15
+ all: () => __inputData,
16
+ first: () => __inputData[0] ?? null,
17
+ last: () => __inputData[__inputData.length - 1] ?? null,
18
+ item: __inputData[0] ?? null,
19
+ };
20
+
21
+ const items = __inputData;
22
+ const $json = __inputData[0]?.json ?? {};
23
+
24
+ async function __userCode() {
25
+ ${userCode}
26
+ }
27
+
28
+ const __result = await __userCode();
29
+
30
+ let __output: any[];
31
+ if (Array.isArray(__result)) {
32
+ __output = __result.map((item: any) => {
33
+ if (item && typeof item === 'object' && 'json' in item) return item;
34
+ return { json: typeof item === 'object' && item !== null ? item : { data: item } };
35
+ });
36
+ } else if (__result && typeof __result === 'object' && 'json' in __result) {
37
+ __output = [__result];
38
+ } else if (__result !== null && __result !== undefined) {
39
+ __output = [{ json: typeof __result === 'object' ? __result : { data: __result } }];
40
+ } else {
41
+ __output = [];
42
+ }
43
+
44
+ writeFileSync(${JSON.stringify(outputPath)}, JSON.stringify(__output));
45
+ `;
46
+ }
47
+ function buildEachItemTemplate(userCode, inputPath, outputPath) {
48
+ return `
49
+ import { readFileSync, writeFileSync } from 'fs';
50
+
51
+ const __inputData: any[] = JSON.parse(readFileSync(${JSON.stringify(inputPath)}, 'utf-8'));
52
+ const __results: any[] = [];
53
+
54
+ for (let __idx = 0; __idx < __inputData.length; __idx++) {
55
+ const $input = {
56
+ item: __inputData[__idx],
57
+ all: () => __inputData,
58
+ first: () => __inputData[0] ?? null,
59
+ last: () => __inputData[__inputData.length - 1] ?? null,
60
+ };
61
+
62
+ const item = __inputData[__idx];
63
+ const $json = __inputData[__idx].json ?? {};
64
+
65
+ const __runUserCode = async () => {
66
+ ${userCode}
67
+ };
68
+
69
+ const __itemResult = await __runUserCode();
70
+
71
+ if (__itemResult !== null && __itemResult !== undefined) {
72
+ let __normalized: any;
73
+ if (typeof __itemResult === 'object' && 'json' in __itemResult) {
74
+ __normalized = __itemResult;
75
+ } else if (typeof __itemResult === 'object' && __itemResult !== null) {
76
+ __normalized = { json: __itemResult };
77
+ } else {
78
+ __normalized = { json: { data: __itemResult } };
79
+ }
80
+ __normalized.pairedItem = { item: __idx };
81
+ __results.push(__normalized);
82
+ }
83
+ }
84
+
85
+ writeFileSync(${JSON.stringify(outputPath)}, JSON.stringify(__results));
86
+ `;
87
+ }
88
+ function executeBun(scriptPath) {
89
+ return new Promise((resolve, reject) => {
90
+ const proc = (0, child_process_1.spawn)('bun', ['run', scriptPath], {
91
+ stdio: ['ignore', 'pipe', 'pipe'],
92
+ timeout: 60_000,
93
+ });
94
+ let stdout = '';
95
+ let stderr = '';
96
+ proc.stdout.on('data', (data) => {
97
+ stdout += data.toString();
98
+ });
99
+ proc.stderr.on('data', (data) => {
100
+ stderr += data.toString();
101
+ });
102
+ proc.on('error', (err) => {
103
+ if (err.code === 'ENOENT') {
104
+ reject(new Error('Bun runtime not found. Please install Bun: https://bun.sh'));
105
+ }
106
+ else {
107
+ reject(err);
108
+ }
109
+ });
110
+ proc.on('close', (exitCode) => {
111
+ resolve({ stdout, stderr, exitCode: exitCode ?? 1 });
112
+ });
113
+ });
114
+ }
115
+ async function runBunCode(userCode, inputItems, mode) {
116
+ const tempDir = await (0, promises_1.mkdtemp)((0, path_1.join)((0, os_1.tmpdir)(), 'n8n-bun-'));
117
+ const inputPath = (0, path_1.join)(tempDir, 'input.json');
118
+ const outputPath = (0, path_1.join)(tempDir, 'output.json');
119
+ const scriptPath = (0, path_1.join)(tempDir, 'script.ts');
120
+ try {
121
+ await (0, promises_1.writeFile)(inputPath, JSON.stringify(inputItems));
122
+ const template = mode === 'runOnceForAllItems'
123
+ ? buildAllItemsTemplate(userCode, inputPath, outputPath)
124
+ : buildEachItemTemplate(userCode, inputPath, outputPath);
125
+ await (0, promises_1.writeFile)(scriptPath, template);
126
+ const { stderr, exitCode } = await executeBun(scriptPath);
127
+ if (exitCode !== 0) {
128
+ throw new Error(`Bun execution failed (exit code ${exitCode}):\n${stderr}`);
129
+ }
130
+ let outputRaw;
131
+ try {
132
+ outputRaw = await (0, promises_1.readFile)(outputPath, 'utf-8');
133
+ }
134
+ catch {
135
+ throw new Error(`Code did not produce output. Make sure your code returns data.\n${stderr}`);
136
+ }
137
+ return JSON.parse(outputRaw);
138
+ }
139
+ finally {
140
+ await (0, promises_1.rm)(tempDir, { recursive: true, force: true }).catch(() => { });
141
+ }
142
+ }
143
+ //# sourceMappingURL=runBunCode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runBunCode.js","sourceRoot":"","sources":["../../../nodes/BunCode/runBunCode.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "n8n-nodes-bun",
3
+ "version": "0.1.2",
4
+ "description": "n8n community node that executes TypeScript/JavaScript code using Bun runtime",
5
+ "keywords": [
6
+ "n8n-community-node-package",
7
+ "n8n",
8
+ "bun",
9
+ "typescript",
10
+ "code"
11
+ ],
12
+ "license": "MIT",
13
+ "main": "dist/nodes/BunCode/BunCode.node.js",
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "scripts": {
18
+ "build": "tsc && copyfiles \"nodes/**/*.svg\" dist/",
19
+ "dev": "tsc --watch",
20
+ "prepublishOnly": "npm run build",
21
+ "release": "npm version patch && npm run build && npm publish",
22
+ "release:minor": "npm version minor && npm run build && npm publish",
23
+ "release:major": "npm version major && npm run build && npm publish"
24
+ },
25
+ "n8n": {
26
+ "n8nNodesApiVersion": 1,
27
+ "nodes": [
28
+ "dist/nodes/BunCode/BunCode.node.js"
29
+ ]
30
+ },
31
+ "peerDependencies": {
32
+ "n8n-workflow": "*"
33
+ },
34
+ "devDependencies": {
35
+ "@types/node": "^25.3.0",
36
+ "copyfiles": "^2.4.1",
37
+ "n8n-workflow": "*",
38
+ "typescript": "~5.7.0"
39
+ }
40
+ }