n8n-nodes-cala 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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Cala AI
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,122 @@
1
+ # n8n-nodes-cala
2
+
3
+ This is an n8n community node for [Cala AI](https://cala.ai) - a platform that transforms internet information into structured, trustworthy context for AI agents.
4
+
5
+ ## Installation
6
+
7
+ ### n8n Cloud (Verified Nodes)
8
+
9
+ 1. Go to **Settings** → **Community Nodes**
10
+ 2. Click **Install**
11
+ 3. Enter `n8n-nodes-cala`
12
+ 4. Click **Install**
13
+
14
+ ### Self-hosted n8n
15
+
16
+ ```bash
17
+ npm install n8n-nodes-cala
18
+ ```
19
+
20
+ ## Credentials
21
+
22
+ You need a Cala API key to use this node:
23
+
24
+ 1. Sign up at [console.cala.ai](https://console.cala.ai)
25
+ 2. Create an API key
26
+ 3. In n8n, create new credentials of type **Cala API**
27
+ 4. Enter your API key
28
+
29
+ ## Operations
30
+
31
+ ### Knowledge
32
+
33
+ | Operation | Description |
34
+ |-----------|-------------|
35
+ | **Search** | Search verified knowledge using natural language queries |
36
+
37
+ ### Example
38
+
39
+ **Input:** "How many students were enrolled at MIT in 2024?"
40
+
41
+ **Output:**
42
+ ```json
43
+ {
44
+ "content": "In 2024, MIT had approximately 11,800 students enrolled, including 4,600 undergraduate and 7,200 graduate students.",
45
+ "explainability": [
46
+ {
47
+ "content": "MIT enrollment data shows total student population across undergraduate and graduate programs",
48
+ "references": ["a1b2c3d4-5678-90ab-cdef-123456789abc"]
49
+ }
50
+ ],
51
+ "context": [
52
+ {
53
+ "id": "a1b2c3d4-5678-90ab-cdef-123456789abc",
54
+ "content": "In 2024, the Massachusetts Institute of Technology enrolled approximately 11,800 students: 4,600 undergraduates and 7,200 graduate students.",
55
+ "origins": [
56
+ {
57
+ "source": { "name": "MIT", "url": "https://mit.edu" },
58
+ "document": { "name": "MIT Facts", "url": "https://mit.edu/about" }
59
+ }
60
+ ]
61
+ }
62
+ ],
63
+ "entities": [
64
+ { "id": 1, "name": "MIT", "entity_type": "ORGANIZATION" },
65
+ { "id": 2, "name": "Massachusetts Institute of Technology", "entity_type": "ORGANIZATION" }
66
+ ]
67
+ }
68
+ ```
69
+
70
+ ## Resources
71
+
72
+ - [Cala Documentation](https://docs.cala.ai)
73
+ - [Cala Console](https://console.cala.ai)
74
+ - [n8n Community Nodes Documentation](https://docs.n8n.io/integrations/community-nodes/)
75
+
76
+ ## Development
77
+
78
+ ### Requirements
79
+
80
+ - Node.js >= 22
81
+ - pnpm >= 10
82
+
83
+ ### Project Structure
84
+
85
+ ```text
86
+ cala-n8n/
87
+ ├── credentials/
88
+ │ └── CalaApi.credentials.ts # API credentials definition
89
+ ├── nodes/
90
+ │ └── Cala/
91
+ │ ├── Cala.node.ts # Main node logic
92
+ │ └── cala.svg # Node icon
93
+ ├── dist/ # Compiled output
94
+ ├── Makefile # Development commands
95
+ ├── package.json
96
+ ├── tsconfig.json
97
+ └── gulpfile.js
98
+ ```
99
+
100
+ ### Quick Start
101
+
102
+ ```bash
103
+ make start # Build + start n8n at http://localhost:5678
104
+ make stop # Stop n8n
105
+ ```
106
+
107
+ ### Commands
108
+
109
+ | Command | Description |
110
+ | ------- | ----------- |
111
+ | `make install` | Install dependencies |
112
+ | `make build` | Build the project |
113
+ | `make dev` | Development mode (watch) |
114
+ | `make start` | Start n8n locally |
115
+ | `make stop` | Stop n8n |
116
+ | `make publish` | Publish to npm |
117
+ | `make verify` | Run n8n linter |
118
+ | `make clean` | Remove build artifacts |
119
+
120
+ ## License
121
+
122
+ MIT
@@ -0,0 +1,7 @@
1
+ import { ICredentialType, INodeProperties } from 'n8n-workflow';
2
+ export declare class CalaApi implements ICredentialType {
3
+ name: string;
4
+ displayName: string;
5
+ documentationUrl: string;
6
+ properties: INodeProperties[];
7
+ }
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CalaApi = void 0;
4
+ class CalaApi {
5
+ constructor() {
6
+ this.name = 'calaApi';
7
+ this.displayName = 'Cala API';
8
+ this.documentationUrl = 'https://docs.cala.ai';
9
+ this.properties = [
10
+ {
11
+ displayName: 'API Key',
12
+ name: 'apiKey',
13
+ type: 'string',
14
+ typeOptions: {
15
+ password: true,
16
+ },
17
+ default: '',
18
+ required: true,
19
+ description: 'Your Cala API key',
20
+ },
21
+ {
22
+ displayName: 'Base URL',
23
+ name: 'baseUrl',
24
+ type: 'string',
25
+ default: 'https://api.cala.ai',
26
+ required: true,
27
+ description: 'The base URL of the Cala API',
28
+ },
29
+ ];
30
+ }
31
+ }
32
+ exports.CalaApi = CalaApi;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const CalaApi_credentials_1 = require("./CalaApi.credentials");
4
+ describe('CalaApi Credentials', () => {
5
+ let credentials;
6
+ beforeEach(() => {
7
+ credentials = new CalaApi_credentials_1.CalaApi();
8
+ });
9
+ it('should have correct name', () => {
10
+ expect(credentials.name).toBe('calaApi');
11
+ });
12
+ it('should have correct display name', () => {
13
+ expect(credentials.displayName).toBe('Cala API');
14
+ });
15
+ it('should have documentation URL', () => {
16
+ expect(credentials.documentationUrl).toBe('https://docs.cala.ai');
17
+ });
18
+ it('should have API key property', () => {
19
+ var _a;
20
+ const apiKeyProp = credentials.properties.find(p => p.name === 'apiKey');
21
+ expect(apiKeyProp).toBeDefined();
22
+ expect(apiKeyProp === null || apiKeyProp === void 0 ? void 0 : apiKeyProp.type).toBe('string');
23
+ expect(apiKeyProp === null || apiKeyProp === void 0 ? void 0 : apiKeyProp.required).toBe(true);
24
+ expect((_a = apiKeyProp === null || apiKeyProp === void 0 ? void 0 : apiKeyProp.typeOptions) === null || _a === void 0 ? void 0 : _a.password).toBe(true);
25
+ });
26
+ it('should have base URL property with default value', () => {
27
+ const baseUrlProp = credentials.properties.find(p => p.name === 'baseUrl');
28
+ expect(baseUrlProp).toBeDefined();
29
+ expect(baseUrlProp === null || baseUrlProp === void 0 ? void 0 : baseUrlProp.type).toBe('string');
30
+ expect(baseUrlProp === null || baseUrlProp === void 0 ? void 0 : baseUrlProp.default).toBe('https://api.cala.ai');
31
+ });
32
+ });
@@ -0,0 +1,5 @@
1
+ import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
2
+ export declare class Cala implements INodeType {
3
+ description: INodeTypeDescription;
4
+ execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
5
+ }
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Cala = void 0;
4
+ class Cala {
5
+ constructor() {
6
+ this.description = {
7
+ displayName: 'Cala',
8
+ name: 'cala',
9
+ icon: 'file:cala.svg',
10
+ group: ['transform'],
11
+ version: 1,
12
+ subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
13
+ description: 'Search verified knowledge with Cala AI',
14
+ defaults: {
15
+ name: 'Cala',
16
+ },
17
+ inputs: ['main'],
18
+ outputs: ['main'],
19
+ credentials: [
20
+ {
21
+ name: 'calaApi',
22
+ required: true,
23
+ },
24
+ ],
25
+ properties: [
26
+ {
27
+ displayName: 'Resource',
28
+ name: 'resource',
29
+ type: 'options',
30
+ noDataExpression: true,
31
+ options: [
32
+ {
33
+ name: 'Knowledge',
34
+ value: 'knowledge',
35
+ },
36
+ ],
37
+ default: 'knowledge',
38
+ },
39
+ {
40
+ displayName: 'Operation',
41
+ name: 'operation',
42
+ type: 'options',
43
+ noDataExpression: true,
44
+ displayOptions: {
45
+ show: {
46
+ resource: ['knowledge'],
47
+ },
48
+ },
49
+ options: [
50
+ {
51
+ name: 'Search',
52
+ value: 'search',
53
+ description: 'Search verified knowledge',
54
+ action: 'Search verified knowledge',
55
+ },
56
+ ],
57
+ default: 'search',
58
+ },
59
+ {
60
+ displayName: 'Query',
61
+ name: 'query',
62
+ type: 'string',
63
+ required: true,
64
+ displayOptions: {
65
+ show: {
66
+ resource: ['knowledge'],
67
+ operation: ['search'],
68
+ },
69
+ },
70
+ default: '',
71
+ placeholder: 'What is the refund policy?',
72
+ description: 'The search query to find verified knowledge',
73
+ },
74
+ ],
75
+ };
76
+ }
77
+ async execute() {
78
+ const items = this.getInputData();
79
+ const returnData = [];
80
+ const credentials = await this.getCredentials('calaApi');
81
+ const baseUrl = credentials.baseUrl.replace(/\/$/, '');
82
+ const apiKey = credentials.apiKey;
83
+ for (let i = 0; i < items.length; i++) {
84
+ const resource = this.getNodeParameter('resource', i);
85
+ const operation = this.getNodeParameter('operation', i);
86
+ if (resource === 'knowledge' && operation === 'search') {
87
+ const query = this.getNodeParameter('query', i);
88
+ const headers = {
89
+ 'Content-Type': 'application/json',
90
+ };
91
+ if (apiKey) {
92
+ headers['X-API-KEY'] = apiKey;
93
+ }
94
+ const response = await this.helpers.httpRequest({
95
+ method: 'POST',
96
+ url: `${baseUrl}/v1/knowledge/search`,
97
+ headers,
98
+ body: {
99
+ input: query,
100
+ },
101
+ json: true,
102
+ });
103
+ returnData.push({
104
+ json: response,
105
+ pairedItem: { item: i },
106
+ });
107
+ }
108
+ }
109
+ return [returnData];
110
+ }
111
+ }
112
+ exports.Cala = Cala;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,128 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const Cala_node_1 = require("./Cala.node");
4
+ describe('Cala Node', () => {
5
+ let node;
6
+ beforeEach(() => {
7
+ node = new Cala_node_1.Cala();
8
+ });
9
+ describe('execute', () => {
10
+ const createExecutionContext = ({ baseUrl = 'https://api.cala.ai/', apiKey = 'test-key', resource = 'knowledge', operation = 'search', query = 'What is Cala?', response = { content: 'ok' }, } = {}) => {
11
+ const httpRequest = jest.fn(async () => response);
12
+ return {
13
+ getInputData: jest.fn(() => [{ json: { input: 'one' } }]),
14
+ getNodeParameter: jest.fn((name, _index) => {
15
+ if (name === 'resource') {
16
+ return resource;
17
+ }
18
+ if (name === 'operation') {
19
+ return operation;
20
+ }
21
+ if (name === 'query') {
22
+ return query;
23
+ }
24
+ throw new Error(`Unexpected parameter name: ${name}`);
25
+ }),
26
+ getCredentials: jest.fn(async () => ({ baseUrl, apiKey })),
27
+ helpers: {
28
+ httpRequest,
29
+ },
30
+ };
31
+ };
32
+ it('should call Cala API with normalized base URL', async () => {
33
+ const context = createExecutionContext();
34
+ const result = await node.execute.call(context);
35
+ expect(context.helpers.httpRequest).toHaveBeenCalledWith({
36
+ method: 'POST',
37
+ url: 'https://api.cala.ai/v1/knowledge/search',
38
+ headers: {
39
+ 'Content-Type': 'application/json',
40
+ 'X-API-KEY': 'test-key',
41
+ },
42
+ body: {
43
+ input: 'What is Cala?',
44
+ },
45
+ json: true,
46
+ });
47
+ expect(result).toEqual([[{ json: { content: 'ok' }, pairedItem: { item: 0 } }]]);
48
+ });
49
+ it('should omit API key header when missing', async () => {
50
+ const context = createExecutionContext({ apiKey: '' });
51
+ await node.execute.call(context);
52
+ expect(context.helpers.httpRequest).toHaveBeenCalledWith({
53
+ method: 'POST',
54
+ url: 'https://api.cala.ai/v1/knowledge/search',
55
+ headers: {
56
+ 'Content-Type': 'application/json',
57
+ },
58
+ body: {
59
+ input: 'What is Cala?',
60
+ },
61
+ json: true,
62
+ });
63
+ });
64
+ it('should process multiple items', async () => {
65
+ const queries = ['Query 1', 'Query 2', 'Query 3'];
66
+ const httpRequest = jest.fn()
67
+ .mockResolvedValueOnce({ answer: 'Answer 1' })
68
+ .mockResolvedValueOnce({ answer: 'Answer 2' })
69
+ .mockResolvedValueOnce({ answer: 'Answer 3' });
70
+ const context = {
71
+ getInputData: jest.fn(() => queries.map(q => ({ json: { query: q } }))),
72
+ getNodeParameter: jest.fn((name, index) => {
73
+ if (name === 'resource')
74
+ return 'knowledge';
75
+ if (name === 'operation')
76
+ return 'search';
77
+ if (name === 'query')
78
+ return queries[index];
79
+ throw new Error(`Unexpected parameter: ${name}`);
80
+ }),
81
+ getCredentials: jest.fn(async () => ({ baseUrl: 'https://api.cala.ai', apiKey: 'test-key' })),
82
+ helpers: { httpRequest },
83
+ };
84
+ const result = await node.execute.call(context);
85
+ expect(httpRequest).toHaveBeenCalledTimes(3);
86
+ expect(result[0]).toHaveLength(3);
87
+ expect(result[0][0].json).toEqual({ answer: 'Answer 1' });
88
+ expect(result[0][1].json).toEqual({ answer: 'Answer 2' });
89
+ expect(result[0][2].json).toEqual({ answer: 'Answer 3' });
90
+ });
91
+ it('should propagate HTTP errors', async () => {
92
+ const httpRequest = jest.fn().mockRejectedValue(new Error('API Error: 500 Internal Server Error'));
93
+ const context = {
94
+ getInputData: jest.fn(() => [{ json: {} }]),
95
+ getNodeParameter: jest.fn((name) => {
96
+ if (name === 'resource')
97
+ return 'knowledge';
98
+ if (name === 'operation')
99
+ return 'search';
100
+ if (name === 'query')
101
+ return 'test query';
102
+ throw new Error(`Unexpected parameter: ${name}`);
103
+ }),
104
+ getCredentials: jest.fn(async () => ({ baseUrl: 'https://api.cala.ai', apiKey: 'test-key' })),
105
+ helpers: { httpRequest },
106
+ };
107
+ await expect(node.execute.call(context)).rejects.toThrow('API Error: 500 Internal Server Error');
108
+ });
109
+ it('should return empty array for unsupported resource/operation', async () => {
110
+ const httpRequest = jest.fn();
111
+ const context = {
112
+ getInputData: jest.fn(() => [{ json: {} }]),
113
+ getNodeParameter: jest.fn((name) => {
114
+ if (name === 'resource')
115
+ return 'unsupported';
116
+ if (name === 'operation')
117
+ return 'unknown';
118
+ throw new Error(`Unexpected parameter: ${name}`);
119
+ }),
120
+ getCredentials: jest.fn(async () => ({ baseUrl: 'https://api.cala.ai', apiKey: 'test-key' })),
121
+ helpers: { httpRequest },
122
+ };
123
+ const result = await node.execute.call(context);
124
+ expect(httpRequest).not.toHaveBeenCalled();
125
+ expect(result).toEqual([[]]);
126
+ });
127
+ });
128
+ });
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3
+ <svg width="100%" height="100%" viewBox="0 0 440 158" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
4
+ <use xlink:href="#_Image1" x="0" y="0.811" width="440px" height="157px"/>
5
+ <defs>
6
+ <image id="_Image1" width="440px" height="157px" xlink:href="data:image/png;base64,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"/>
7
+ </defs>
8
+ </svg>
package/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "n8n-nodes-cala",
3
+ "version": "0.2.0",
4
+ "description": "n8n nodes for Cala AI knowledge search",
5
+ "keywords": [
6
+ "n8n-community-node-package",
7
+ "n8n",
8
+ "cala",
9
+ "knowledge",
10
+ "search"
11
+ ],
12
+ "license": "MIT",
13
+ "author": {
14
+ "name": "Cala AI",
15
+ "email": "support@cala.ai",
16
+ "url": "https://cala.ai"
17
+ },
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "https://gitlab.com/cala-ai/cala-n8n.git"
21
+ },
22
+ "homepage": "https://gitlab.com/cala-ai/cala-n8n",
23
+ "bugs": {
24
+ "url": "https://gitlab.com/cala-ai/cala-n8n/-/issues"
25
+ },
26
+ "files": [
27
+ "dist",
28
+ "LICENSE",
29
+ "README.md"
30
+ ],
31
+ "n8n": {
32
+ "n8nNodesApiVersion": 1,
33
+ "credentials": [
34
+ "dist/credentials/CalaApi.credentials.js"
35
+ ],
36
+ "nodes": [
37
+ "dist/nodes/Cala/Cala.node.js"
38
+ ]
39
+ },
40
+ "devDependencies": {
41
+ "@eslint/js": "^9.39.2",
42
+ "@types/jest": "^30.0.0",
43
+ "@types/node": "^20.10.0",
44
+ "eslint": "^9.39.2",
45
+ "gulp": "^5.0.0",
46
+ "jest": "^30.2.0",
47
+ "n8n-workflow": "^1.0.0",
48
+ "ts-jest": "^29.4.6",
49
+ "typescript": "^5.3.0",
50
+ "typescript-eslint": "^8.53.1"
51
+ },
52
+ "peerDependencies": {
53
+ "n8n-workflow": "*"
54
+ },
55
+ "engines": {
56
+ "node": ">=22",
57
+ "pnpm": ">=10"
58
+ },
59
+ "volta": {
60
+ "node": "22.13.1"
61
+ },
62
+ "scripts": {
63
+ "build": "tsc && gulp build:icons",
64
+ "dev": "tsc --watch",
65
+ "test": "jest",
66
+ "lint": "eslint nodes credentials"
67
+ }
68
+ }