first commit
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
# AGENTS.md
|
||||
|
||||
Guidance for node development in the nodes-base package.
|
||||
|
||||
## Node Structure
|
||||
|
||||
Every node implements the `INodeType` interface with:
|
||||
- `description: INodeTypeDescription` - Node metadata and UI configuration
|
||||
- `execute?()` - For programmatic nodes
|
||||
- `poll?()` - For polling triggers (set `polling: true` in description)
|
||||
- `trigger?()` - For generic triggers
|
||||
- `webhook?()` - For webhook triggers
|
||||
- `webhookMethods?` - Webhook lifecycle (checkExists, create, delete)
|
||||
- `methods?` - loadOptions, listSearch, credentialTest, resourceMapping
|
||||
|
||||
## Node Types
|
||||
|
||||
### Programmatic Nodes
|
||||
Use `execute` function for custom logic. Example: `nodes/Discord/v2/DiscordV2.node.ts`
|
||||
|
||||
### Declarative Nodes
|
||||
Use `requestDefaults` and routing configuration instead of `execute`. Example: `nodes/Okta/Okta.node.ts`
|
||||
|
||||
### Trigger Nodes
|
||||
- **Webhook triggers**: Implement `webhook` and `webhookMethods` (checkExists, create, delete). Example: `nodes/Microsoft/Teams/MicrosoftTeamsTrigger.node.ts`
|
||||
- **Polling triggers**: Set `polling: true` and implement `poll`. Use `getWorkflowStaticData('node')` to persist state. Example: `nodes/Google/Gmail/GmailTrigger.node.ts`
|
||||
- **Generic triggers**: Implement `trigger` function. Example: `nodes/MQTT/MqttTrigger.node.ts`
|
||||
|
||||
## Node Parameters
|
||||
|
||||
Common parameter types:
|
||||
- `string` - Text input
|
||||
- `options` - Dropdown (static or dynamic via `loadOptionsMethod`)
|
||||
- `resourceLocator` - Select by list, ID, or URL
|
||||
- `collection` - Key-value pairs
|
||||
- `fixedCollection` - Structured collections
|
||||
|
||||
Use `displayOptions` to show/hide fields based on other parameters. Use `noDataExpression: true` for resource/operation selectors.
|
||||
|
||||
## Versioning
|
||||
|
||||
- **Light versioning**: Use version arrays in description: `version: [3, 3.1, 3.2]`
|
||||
- **Full versioning**: Use `VersionedNodeType` class with separate version implementations. Example: `nodes/Set/Set.node.ts`
|
||||
|
||||
## Credentials
|
||||
|
||||
Credentials are defined in `credentials/` directory and implement `ICredentialType`:
|
||||
- `name` - Internal identifier
|
||||
- `displayName` - Human-readable name
|
||||
- `properties` - Credential fields
|
||||
- `authenticate` - Authentication configuration (generic or custom function)
|
||||
- `test` - Credential test request
|
||||
|
||||
Nodes can test credentials via `methods.credentialTest`.
|
||||
|
||||
## Testing
|
||||
|
||||
### Unit Tests
|
||||
- Use `jest-mock-extended` for mocking interfaces
|
||||
- Use `nock` for HTTP mocking
|
||||
- Mock all external dependencies
|
||||
- Test happy paths, error handling, edge cases, and binary data
|
||||
|
||||
### Workflow Tests
|
||||
- Use `NodeTestHarness` with JSON workflow definitions
|
||||
- Mock external APIs with nock
|
||||
- Use `pnpm test` for running tests. Example: `cd packages/nodes-base/ && pnpm test TestFileName`
|
||||
|
||||
## Common Development Tasks
|
||||
|
||||
### Creating a New Node
|
||||
1. Create directory: `nodes/YourService/`
|
||||
2. Create `YourService.node.ts` implementing `INodeType`
|
||||
3. Add icon SVG files in node directory
|
||||
4. Define credentials in `credentials/` if needed
|
||||
5. Write tests following testing guidelines
|
||||
6. Register in `package.json` nodes array if needed
|
||||
|
||||
### Adding Dynamic Options
|
||||
Add `loadOptionsMethod` to parameter's `typeOptions` and implement method in `methods.loadOptions`.
|
||||
|
||||
### Adding Resource Locator
|
||||
Change parameter type to `'resourceLocator'`, define modes (list, id, url), add `searchListMethod` for list mode, add `extractValue` regex for URL mode.
|
||||
|
||||
## Best Practices
|
||||
|
||||
### TypeScript
|
||||
- Never use `any` type - use proper types or `unknown`
|
||||
- Avoid type casting with `as` - use type guards instead
|
||||
- Define interfaces for API responses
|
||||
|
||||
### Error Handling
|
||||
- Use `NodeOperationError` for user-facing errors
|
||||
- Use `NodeApiError` for API-related errors
|
||||
- Support `continueOnFail` option when appropriate
|
||||
|
||||
### Code Organization
|
||||
- Separate operation/field descriptions into separate files
|
||||
- Create reusable API request helpers in GenericFunctions
|
||||
- Use kebab-case for files, PascalCase for classes
|
||||
|
||||
### UI/UX
|
||||
- Use clear `displayName` and `description` fields
|
||||
- Set sensible default values
|
||||
- Use `displayOptions` to show/hide fields conditionally
|
||||
|
||||
## Example Nodes
|
||||
|
||||
- Declarative: `nodes/Okta/Okta.node.ts`
|
||||
- Programmatic: `nodes/Discord/v2/DiscordV2.node.ts`
|
||||
- Webhook Trigger: `nodes/Microsoft/Teams/MicrosoftTeamsTrigger.node.ts`
|
||||
- Polling Trigger: `nodes/Google/Gmail/GmailTrigger.node.ts`
|
||||
- Generic Trigger: `nodes/MQTT/MqttTrigger.node.ts`
|
||||
- Versioned: `nodes/Set/Set.node.ts`
|
||||
@@ -0,0 +1 @@
|
||||
@AGENTS.md
|
||||
@@ -0,0 +1,13 @@
|
||||

|
||||
|
||||
# n8n-nodes-base
|
||||
|
||||
The nodes which are included by default in n8n
|
||||
|
||||
```
|
||||
npm install n8n-nodes-base -g
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
You can find the license information [here](https://github.com/n8n-io/n8n/blob/master/README.md#license)
|
||||
@@ -0,0 +1,36 @@
|
||||
To write unit tests it is suggested to use AI for
|
||||
help.
|
||||
|
||||
## Approach for standard unit tests
|
||||
|
||||
1. **Create the test file**: Decide which node you want to test and create a test file with the corresponding name in the test folder. For example, for a node in `nodeA/v2/NodeAV2.node.ts`, create a test file in `nodeA/v2/test/NodeAV2.test.ts`.
|
||||
|
||||
2. **Use AI assistance**: Send this prompt to your AI tool (Cursor, Copilot, Claude, etc.):
|
||||
```
|
||||
Using guidelines in @TESTING_PROMPT.md, write tests for @NodeAV2.node.ts in @NodeAV2.node.test.ts
|
||||
```
|
||||
Make sure file names after `@` are detected and referenced by your tool.
|
||||
You can improve the prompt by asking to cover specific test cases.
|
||||
|
||||
3. **Review and refine**: Thoroughly review the generated tests, make necessary fixes, and remove redundant tests. __Even if generated by AI, it's still your responsibility to ensure tests are working and reasonable.__
|
||||
|
||||
## Approach for workflow unit tests
|
||||
Workflow unit tests are tests that use user predefined workflows in json format and NodeTestHarness helper that runs the workflow. This is closer to integration tests.
|
||||
|
||||
For these tests you can follow the guidelines defined above, but with some modifications:
|
||||
- Use `TESTING_PROMPT_WORKFLOW.md` instead
|
||||
- Use a different prompt. It's also important to specify a credentials schema if any credentials are being used, because AI struggles with identifying the schema. You can use the following prompt:
|
||||
```
|
||||
I need you to write workflow unit tests for @NodeAV2.node.ts in @NodeAV2.node.test.ts
|
||||
using guidelines in @TESTING_PROMPT_WORKFLOW.md
|
||||
You should test each resource and operation in the node
|
||||
After writing a first test make sure it passes, then write other tests.
|
||||
|
||||
To mock credentials use this schema
|
||||
oauth2: {
|
||||
scope: '',
|
||||
oauthTokenData: {
|
||||
access_token: 'ACCESSTOKEN',
|
||||
},
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,473 @@
|
||||
# AI Agent Prompt: Writing Reliable Unit Tests for n8n Nodes
|
||||
|
||||
You are an expert AI agent specialized in writing comprehensive, reliable unit tests for n8n nodes in the `@packages/nodes-base` folder. Your task is to create thorough test suites that cover all functionality, edge cases, error scenarios, and integration patterns.
|
||||
|
||||
## Core Testing Principles
|
||||
|
||||
### 1. Test Structure and Organization
|
||||
- **File Naming**: Use `.test.ts` extension, place in `test/` or `__tests__/` directories
|
||||
- **Test Organization**: Group tests by functionality using `describe()` blocks. Test concrete operations and resources.
|
||||
- **Test Naming**: Use descriptive test names that explain the expected behavior
|
||||
- **Setup/Teardown**: Use `beforeEach()` and `afterEach()` for consistent test isolation
|
||||
|
||||
### 3. Testing guidelines
|
||||
|
||||
- **Don't add useless comments** such as "Arrange, Assert, Act" or "Mock something".
|
||||
- **Always work from within the package directory** when running tests. E.g. for a node in nodes-base enter `packages/nodes-base` or for langchain node enter `packages/@n8n/nodes-langchain`
|
||||
- **Use `pnpm test <file_name>`** for running tests
|
||||
- **Mock all external dependencies** in unit tests
|
||||
|
||||
|
||||
### 4. Essential Test Categories
|
||||
Always include tests for:
|
||||
- **Happy Path**: Normal operation with valid inputs
|
||||
- **Error Handling**: Invalid inputs, API failures
|
||||
- **Edge Cases**: Empty data, null values, boundary conditions
|
||||
- **Binary Data**: File uploads, downloads, data streams
|
||||
- **Authentication**: Credential handling, token refresh
|
||||
- **Rate Limiting**: API throttling, retry logic
|
||||
- **Data Transformation**: Input/output data processing
|
||||
- **Node Versioning**: Different node type versions
|
||||
|
||||
## Mocking Strategies
|
||||
|
||||
### 1. Core n8n Interfaces Mocking
|
||||
```typescript
|
||||
import { mock, mockDeep } from 'jest-mock-extended';
|
||||
import type { IExecuteFunctions, IWebhookFunctions, INode } from 'n8n-workflow';
|
||||
|
||||
// Standard execute functions mock
|
||||
const mockExecuteFunctions = mockDeep<IExecuteFunctions>();
|
||||
|
||||
// Webhook functions mock
|
||||
const mockWebhookFunctions = mock<IWebhookFunctions>();
|
||||
|
||||
// Node mock
|
||||
const mockNode = mock<INode>({
|
||||
id: 'test-node',
|
||||
name: 'Test Node',
|
||||
type: 'n8n-nodes-base.test',
|
||||
typeVersion: 1,
|
||||
position: [0, 0],
|
||||
parameters: {},
|
||||
});
|
||||
```
|
||||
|
||||
### 2. Common Mock Patterns
|
||||
```typescript
|
||||
// Input data mocking
|
||||
mockExecuteFunctions.getInputData.mockReturnValue([
|
||||
{ json: { test: 'data' } },
|
||||
{ json: { another: 'item' } }
|
||||
]);
|
||||
|
||||
// Node parameter mocking
|
||||
mockExecuteFunctions.getNodeParameter.mockImplementation((paramName: string) => {
|
||||
const mockParams = {
|
||||
'operation': 'create',
|
||||
'resource': 'user',
|
||||
'name': 'Test User',
|
||||
'email': 'test@example.com'
|
||||
};
|
||||
return mockParams[paramName];
|
||||
});
|
||||
|
||||
// Credentials mocking
|
||||
mockExecuteFunctions.getCredentials.mockResolvedValue({
|
||||
accessToken: 'test-token',
|
||||
baseUrl: 'https://api.example.com'
|
||||
});
|
||||
|
||||
// Binary data mocking
|
||||
mockExecuteFunctions.helpers.prepareBinaryData.mockResolvedValue({
|
||||
data: 'base64data',
|
||||
mimeType: 'text/plain',
|
||||
fileName: 'test.txt'
|
||||
});
|
||||
```
|
||||
|
||||
### 3. External API Mocking
|
||||
```typescript
|
||||
// Using jest.spyOn for API functions
|
||||
const apiRequestSpy = jest.spyOn(GenericFunctions, 'apiRequest');
|
||||
apiRequestSpy.mockResolvedValue({
|
||||
id: '123',
|
||||
name: 'Test Item',
|
||||
status: 'active'
|
||||
});
|
||||
|
||||
// Using nock for HTTP mocking
|
||||
import nock from 'nock';
|
||||
|
||||
beforeEach(() => {
|
||||
nock('https://api.example.com')
|
||||
.get('/users')
|
||||
.reply(200, { users: [{ id: 1, name: 'John' }] });
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
nock.cleanAll();
|
||||
});
|
||||
```
|
||||
|
||||
### 4. Database and External Service Mocking
|
||||
```typescript
|
||||
// Database mocking
|
||||
const mockDataTable = mock<IDataStoreProjectService>({
|
||||
getColumns: jest.fn(),
|
||||
addColumn: jest.fn(),
|
||||
updateRow: jest.fn(),
|
||||
});
|
||||
|
||||
// Redis client mocking
|
||||
const mockClient = mock<RedisClient>();
|
||||
const createClient = jest.fn().mockReturnValue(mockClient);
|
||||
jest.mock('redis', () => ({ createClient }));
|
||||
```
|
||||
|
||||
## Test Implementation Patterns
|
||||
|
||||
### 1. Basic Node Execution Test
|
||||
```typescript
|
||||
describe('Node Execution', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
mockExecuteFunctions.getInputData.mockReturnValue([{ json: {} }]);
|
||||
mockExecuteFunctions.getNode.mockReturnValue(mockNode);
|
||||
});
|
||||
|
||||
it('should execute successfully with valid parameters', async () => {
|
||||
// Setup mocks
|
||||
mockExecuteFunctions.getNodeParameter.mockImplementation((param) => {
|
||||
const params = { operation: 'create', name: 'Test' };
|
||||
return params[param];
|
||||
});
|
||||
|
||||
apiRequestSpy.mockResolvedValue({ id: '123', name: 'Test' });
|
||||
|
||||
// Execute
|
||||
const result = await node.execute.call(mockExecuteFunctions);
|
||||
|
||||
// Assertions
|
||||
expect(result).toEqual([[
|
||||
{ json: { id: '123', name: 'Test' }, pairedItem: { item: 0 } }
|
||||
]]);
|
||||
expect(apiRequestSpy).toHaveBeenCalledWith('POST', '/items', { name: 'Test' });
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### 2. Error Handling Tests
|
||||
```typescript
|
||||
describe('Error Handling', () => {
|
||||
it('should throw error for invalid credentials', async () => {
|
||||
mockExecuteFunctions.getCredentials.mockRejectedValue(
|
||||
new Error('Invalid credentials')
|
||||
);
|
||||
|
||||
await expect(node.execute.call(mockExecuteFunctions))
|
||||
.rejects.toThrow('Invalid credentials');
|
||||
});
|
||||
|
||||
it('should handle API errors gracefully', async () => {
|
||||
apiRequestSpy.mockRejectedValue(new Error('API Error'));
|
||||
mockExecuteFunctions.continueOnFail.mockReturnValue(true);
|
||||
|
||||
const result = await node.execute.call(mockExecuteFunctions);
|
||||
|
||||
expect(result[0][0].json).toHaveProperty('error');
|
||||
});
|
||||
|
||||
it('should validate required parameters', async () => {
|
||||
mockExecuteFunctions.getNodeParameter.mockReturnValue(undefined);
|
||||
|
||||
await expect(node.execute.call(mockExecuteFunctions))
|
||||
.rejects.toThrow(NodeOperationError);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### 3. Binary Data Testing
|
||||
```typescript
|
||||
describe('Binary Data Handling', () => {
|
||||
it('should process binary files correctly', async () => {
|
||||
const mockBinaryData = {
|
||||
data: 'base64data',
|
||||
mimeType: 'image/png',
|
||||
fileName: 'test.png'
|
||||
};
|
||||
|
||||
mockExecuteFunctions.helpers.assertBinaryData.mockReturnValue(mockBinaryData);
|
||||
mockExecuteFunctions.helpers.prepareBinaryData.mockResolvedValue(mockBinaryData);
|
||||
|
||||
const result = await node.execute.call(mockExecuteFunctions);
|
||||
|
||||
expect(result[0][0].binary).toBeDefined();
|
||||
expect(mockExecuteFunctions.helpers.prepareBinaryData).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should handle file upload operations', async () => {
|
||||
const fileBuffer = Buffer.from('test file content');
|
||||
mockExecuteFunctions.helpers.getBinaryStream.mockResolvedValue(fileBuffer);
|
||||
|
||||
// Test file upload logic
|
||||
const result = await node.execute.call(mockExecuteFunctions);
|
||||
|
||||
expect(result[0][0].json).toHaveProperty('fileId');
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### 4. Webhook Testing
|
||||
```typescript
|
||||
describe('Webhook Operations', () => {
|
||||
it('should handle GET requests', async () => {
|
||||
const mockRequest = { method: 'GET', query: { id: '123' } };
|
||||
const mockResponse = { render: jest.fn(), send: jest.fn() };
|
||||
|
||||
mockWebhookFunctions.getRequestObject.mockReturnValue(mockRequest);
|
||||
mockWebhookFunctions.getResponseObject.mockReturnValue(mockResponse);
|
||||
|
||||
await node.webhook(mockWebhookFunctions);
|
||||
|
||||
expect(mockResponse.render).toHaveBeenCalledWith('template', expect.any(Object));
|
||||
});
|
||||
|
||||
it('should process POST data', async () => {
|
||||
const mockRequest = {
|
||||
method: 'POST',
|
||||
body: { name: 'Test', email: 'test@example.com' }
|
||||
};
|
||||
|
||||
mockWebhookFunctions.getRequestObject.mockReturnValue(mockRequest);
|
||||
mockWebhookFunctions.getBodyData.mockReturnValue(mockRequest.body);
|
||||
|
||||
const result = await node.webhook(mockWebhookFunctions);
|
||||
|
||||
expect(result.workflowData).toBeDefined();
|
||||
expect(result.workflowData[0][0].json).toEqual(mockRequest.body);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### 5. Data Transformation Testing
|
||||
```typescript
|
||||
describe('Data Processing', () => {
|
||||
it('should transform input data correctly', async () => {
|
||||
const inputData = [
|
||||
{ json: { firstName: 'John', lastName: 'Doe' } },
|
||||
{ json: { firstName: 'Jane', lastName: 'Smith' } }
|
||||
];
|
||||
|
||||
mockExecuteFunctions.getInputData.mockReturnValue(inputData);
|
||||
|
||||
const result = await node.execute.call(mockExecuteFunctions);
|
||||
|
||||
expect(result[0]).toHaveLength(2);
|
||||
expect(result[0][0].json).toHaveProperty('fullName', 'John Doe');
|
||||
});
|
||||
|
||||
it('should handle empty input gracefully', async () => {
|
||||
mockExecuteFunctions.getInputData.mockReturnValue([]);
|
||||
|
||||
const result = await node.execute.call(mockExecuteFunctions);
|
||||
|
||||
expect(result).toEqual([[]]);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## Advanced Testing Patterns
|
||||
|
||||
### 1. Using NodeTestHarness for Integration Tests
|
||||
```typescript
|
||||
import { NodeTestHarness } from '@nodes-testing/node-test-harness';
|
||||
|
||||
describe('Integration Tests', () => {
|
||||
new NodeTestHarness().setupTests({
|
||||
credentials: {
|
||||
'testApi': { accessToken: 'test-token' }
|
||||
},
|
||||
nock: {
|
||||
baseUrl: 'https://api.example.com',
|
||||
mocks: [{
|
||||
method: 'get',
|
||||
path: '/users',
|
||||
statusCode: 200,
|
||||
responseBody: { users: [] }
|
||||
}]
|
||||
}
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### 2. Testing Node Methods and Properties
|
||||
```typescript
|
||||
describe('Node Methods', () => {
|
||||
it('should have required methods defined', () => {
|
||||
expect(node.methods.credentialTest).toBeDefined();
|
||||
expect(node.methods.loadOptions).toBeDefined();
|
||||
expect(node.methods.listSearch).toBeDefined();
|
||||
});
|
||||
|
||||
it('should validate credential test method', async () => {
|
||||
const mockCredentialTestFunctions = mock<ICredentialTestFunctions>();
|
||||
mockCredentialTestFunctions.getCredentials.mockResolvedValue({
|
||||
accessToken: 'test-token'
|
||||
});
|
||||
|
||||
const result = await node.methods.credentialTest.testApiCredentialTest.call(
|
||||
mockCredentialTestFunctions
|
||||
);
|
||||
|
||||
expect(result).toEqual({ status: 'OK' });
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### 3. Testing Load Options
|
||||
```typescript
|
||||
describe('Load Options', () => {
|
||||
it('should load resource options', async () => {
|
||||
const mockLoadOptionsFunctions = mock<ILoadOptionsFunctions>();
|
||||
mockLoadOptionsFunctions.getCredentials.mockResolvedValue({
|
||||
accessToken: 'test-token'
|
||||
});
|
||||
|
||||
apiRequestSpy.mockResolvedValue([
|
||||
{ id: '1', name: 'Option 1' },
|
||||
{ id: '2', name: 'Option 2' }
|
||||
]);
|
||||
|
||||
const result = await node.methods.loadOptions.resourceOptions.call(
|
||||
mockLoadOptionsFunctions
|
||||
);
|
||||
|
||||
expect(result).toEqual([
|
||||
{ name: 'Option 1', value: '1' },
|
||||
{ name: 'Option 2', value: '2' }
|
||||
]);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## Testing Guidelines
|
||||
|
||||
### 1. Test Coverage Requirements
|
||||
- **Minimum 80% code coverage** for all node files
|
||||
- **100% coverage** for critical error handling paths
|
||||
- **Test all public methods** and exported functions
|
||||
- **Cover all conditional branches** and edge cases
|
||||
|
||||
### 2. Test Data Management
|
||||
- Use **realistic test data** that mirrors production scenarios
|
||||
- Create **reusable test fixtures** for common data patterns
|
||||
- Use **factory functions** for generating test data
|
||||
- **Clean up test data** in afterEach hooks
|
||||
|
||||
### 3. Assertion Best Practices
|
||||
```typescript
|
||||
// Use specific assertions
|
||||
expect(result).toEqual(expectedData);
|
||||
expect(mockFunction).toHaveBeenCalledWith(expectedArgs);
|
||||
expect(mockFunction).toHaveBeenCalledTimes(1);
|
||||
|
||||
// Test error messages
|
||||
expect(() => functionCall()).toThrow('Expected error message');
|
||||
|
||||
// Test async operations
|
||||
await expect(asyncFunction()).resolves.toEqual(expectedResult);
|
||||
await expect(asyncFunction()).rejects.toThrow(Error);
|
||||
```
|
||||
|
||||
### 4. Performance and Reliability
|
||||
- **Mock external dependencies** to ensure test reliability
|
||||
- **Use deterministic test data** for consistent results
|
||||
- **Test timeout scenarios** for long-running operations
|
||||
- **Validate memory usage** for large data processing
|
||||
|
||||
### 5. Documentation and Maintenance
|
||||
- **Document complex test scenarios** with inline comments
|
||||
- **Use descriptive test names** that explain the test purpose
|
||||
- **Group related tests** logically in describe blocks
|
||||
- **Keep tests independent** - no test should depend on another
|
||||
|
||||
## Common Anti-Patterns to Avoid
|
||||
|
||||
1. **Don't test implementation details** - focus on behavior
|
||||
2. **Don't use real external APIs** in unit tests
|
||||
3. **Don't skip error handling tests** - they're critical
|
||||
4. **Don't use hardcoded values** - use constants or factories
|
||||
5. **Don't ignore async operations** - always await promises
|
||||
6. **Don't test multiple concerns** in a single test case
|
||||
|
||||
## Example Complete Test Suite
|
||||
|
||||
```typescript
|
||||
import { mock, mockDeep } from 'jest-mock-extended';
|
||||
import type { IExecuteFunctions, INode } from 'n8n-workflow';
|
||||
import { NodeOperationError } from 'n8n-workflow';
|
||||
import { TestNode } from '../TestNode';
|
||||
import * as GenericFunctions from '../GenericFunctions';
|
||||
|
||||
describe('TestNode', () => {
|
||||
let node: TestNode;
|
||||
let mockExecuteFunctions: jest.Mocked<IExecuteFunctions>;
|
||||
const apiRequestSpy = jest.spyOn(GenericFunctions, 'apiRequest');
|
||||
|
||||
beforeEach(() => {
|
||||
node = new TestNode();
|
||||
mockExecuteFunctions = mockDeep<IExecuteFunctions>();
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
describe('execute', () => {
|
||||
beforeEach(() => {
|
||||
mockExecuteFunctions.getInputData.mockReturnValue([{ json: {} }]);
|
||||
mockExecuteFunctions.getNode.mockReturnValue({
|
||||
id: 'test',
|
||||
name: 'Test Node',
|
||||
type: 'n8n-nodes-base.test',
|
||||
typeVersion: 1,
|
||||
position: [0, 0],
|
||||
parameters: {}
|
||||
});
|
||||
});
|
||||
|
||||
describe('successful execution', () => {
|
||||
it('should process data correctly', async () => {
|
||||
mockExecuteFunctions.getNodeParameter.mockImplementation((param) => {
|
||||
const params = { operation: 'create', name: 'Test Item' };
|
||||
return params[param];
|
||||
});
|
||||
|
||||
apiRequestSpy.mockResolvedValue({ id: '123', name: 'Test Item' });
|
||||
|
||||
const result = await node.execute.call(mockExecuteFunctions);
|
||||
|
||||
expect(result).toEqual([[
|
||||
{ json: { id: '123', name: 'Test Item' }, pairedItem: { item: 0 } }
|
||||
]]);
|
||||
expect(apiRequestSpy).toHaveBeenCalledWith('POST', '/items', { name: 'Test Item' });
|
||||
});
|
||||
});
|
||||
|
||||
describe('error handling', () => {
|
||||
it('should handle API errors with continueOnFail', async () => {
|
||||
mockExecuteFunctions.getNodeParameter.mockReturnValue('create');
|
||||
mockExecuteFunctions.continueOnFail.mockReturnValue(true);
|
||||
apiRequestSpy.mockRejectedValue(new Error('API Error'));
|
||||
|
||||
const result = await node.execute.call(mockExecuteFunctions);
|
||||
|
||||
expect(result[0][0].json).toHaveProperty('error', 'API Error');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
@@ -0,0 +1,562 @@
|
||||
# AI Agent Prompt: Writing Reliable Workflow Unit Tests for n8n Nodes
|
||||
|
||||
You are an expert AI agent specialized in writing comprehensive, reliable workflow unit tests for n8n nodes in the `@packages/nodes-base` folder. Your task is to create thorough test suites that use `.workflow.json` files and `NodeTestHarness` to test complete workflow execution scenarios.
|
||||
|
||||
## Core Guidelines
|
||||
- **Don't add useless comments** such as "Arrange, Assert, Act" or "Mock something"
|
||||
- **Always work from within the package directory** when running tests
|
||||
- **Use `pnpm test`** for running tests. Example: `cd packages/nodes-base/ && pnpm test TestFileName
|
||||
|
||||
## Essential Test Structure
|
||||
|
||||
### Basic Test Setup
|
||||
```typescript
|
||||
import { NodeTestHarness } from '@nodes-testing/node-test-harness';
|
||||
import nock from 'nock';
|
||||
|
||||
describe('NodeName', () => {
|
||||
describe('Run Test Workflow', () => {
|
||||
beforeAll(() => {
|
||||
const mock = nock('https://api.example.com');
|
||||
mock.post('/endpoint').reply(200, mockResponse);
|
||||
mock.get('/data').reply(200, mockData);
|
||||
});
|
||||
|
||||
new NodeTestHarness().setupTests();
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### Advanced Test with Credentials
|
||||
```typescript
|
||||
describe('NodeName', () => {
|
||||
const credentials = {
|
||||
nodeApi: {
|
||||
accessToken: 'test-token',
|
||||
baseUrl: 'https://api.example.com',
|
||||
},
|
||||
};
|
||||
|
||||
describe('Run Test Workflow', () => {
|
||||
beforeAll(() => {
|
||||
const mock = nock(credentials.nodeApi.baseUrl);
|
||||
mock.post('/users').reply(200, userCreateResponse);
|
||||
});
|
||||
|
||||
new NodeTestHarness().setupTests({
|
||||
credentials,
|
||||
workflowFiles: ['workflow.json'],
|
||||
assertBinaryData: true
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## Workflow JSON Structure
|
||||
|
||||
### Basic Workflow Template
|
||||
```json
|
||||
{
|
||||
"name": "NodeName Test Workflow",
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {},
|
||||
"type": "n8n-nodes-base.manualTrigger",
|
||||
"typeVersion": 1,
|
||||
"position": [0, 0],
|
||||
"id": "trigger-id",
|
||||
"name": "When clicking 'Execute Workflow'"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"operation": "create",
|
||||
"resource": "user",
|
||||
"name": "Test User",
|
||||
"email": "test@example.com"
|
||||
},
|
||||
"type": "n8n-nodes-base.nodeName",
|
||||
"typeVersion": 1,
|
||||
"position": [200, 0],
|
||||
"id": "node-id",
|
||||
"name": "Node Operation",
|
||||
"credentials": {
|
||||
"nodeApi": {
|
||||
"id": "credential-id",
|
||||
"name": "Test Credentials"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"pinData": {
|
||||
"Node Operation": [
|
||||
{
|
||||
"json": {
|
||||
"id": "123",
|
||||
"name": "Test User",
|
||||
"email": "test@example.com",
|
||||
"status": "active"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"connections": {
|
||||
"When clicking 'Execute Workflow'": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Node Operation",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"active": false,
|
||||
"settings": {
|
||||
"executionOrder": "v1"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Node Parameter Types
|
||||
|
||||
### Basic Parameters
|
||||
```json
|
||||
{
|
||||
"displayName": "Parameter Name",
|
||||
"name": "parameterName",
|
||||
"type": "string|number|boolean|options",
|
||||
"default": "defaultValue",
|
||||
"required": true
|
||||
}
|
||||
```
|
||||
|
||||
### Collection Parameters
|
||||
```json
|
||||
{
|
||||
"displayName": "Additional Fields",
|
||||
"name": "additionalFields",
|
||||
"type": "collection",
|
||||
"default": {},
|
||||
"options": [
|
||||
{
|
||||
"displayName": "Custom Field",
|
||||
"name": "customField",
|
||||
"type": "string",
|
||||
"default": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Fixed Collection Parameters
|
||||
```json
|
||||
{
|
||||
"displayName": "Fields to Set",
|
||||
"name": "fields",
|
||||
"type": "fixedCollection",
|
||||
"typeOptions": {
|
||||
"multipleValues": true
|
||||
},
|
||||
"options": [
|
||||
{
|
||||
"name": "values",
|
||||
"displayName": "Values",
|
||||
"values": [
|
||||
{
|
||||
"displayName": "Name",
|
||||
"name": "name",
|
||||
"type": "string",
|
||||
"default": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## HTTP Mocking with Nock
|
||||
|
||||
### Basic API Mocking
|
||||
```typescript
|
||||
beforeAll(() => {
|
||||
const mock = nock('https://api.example.com');
|
||||
|
||||
// Mock GET request
|
||||
mock.get('/users')
|
||||
.reply(200, {
|
||||
users: [
|
||||
{ id: 1, name: 'User 1' },
|
||||
{ id: 2, name: 'User 2' }
|
||||
]
|
||||
});
|
||||
|
||||
// Mock POST request
|
||||
mock.post('/users', {
|
||||
name: 'Test User',
|
||||
email: 'test@example.com'
|
||||
})
|
||||
.reply(201, {
|
||||
id: 123,
|
||||
name: 'Test User',
|
||||
email: 'test@example.com',
|
||||
status: 'active'
|
||||
});
|
||||
|
||||
// Mock error responses
|
||||
mock.get('/error-endpoint')
|
||||
.reply(500, { error: 'Internal Server Error' });
|
||||
});
|
||||
```
|
||||
|
||||
### Advanced Mocking
|
||||
```typescript
|
||||
beforeAll(() => {
|
||||
const mock = nock('https://api.example.com');
|
||||
|
||||
// Mock with headers
|
||||
mock.get('/protected-endpoint')
|
||||
.matchHeader('Authorization', 'Bearer test-token')
|
||||
.reply(200, { data: 'protected' });
|
||||
|
||||
// Mock with query parameters
|
||||
mock.get('/search')
|
||||
.query({ q: 'test', limit: 10 })
|
||||
.reply(200, { results: [] });
|
||||
|
||||
// Mock with request body validation
|
||||
mock.post('/validate', (body) => {
|
||||
return body.name && body.email;
|
||||
})
|
||||
.reply(200, { valid: true });
|
||||
});
|
||||
```
|
||||
|
||||
### Credentials Mocking
|
||||
Some workflows require credentials for NodeHarness. If the execution result of a test is null it means that workflow has invalid inputs. Very often it's misconfigured credentials.
|
||||
|
||||
```typescript
|
||||
const credentials = {
|
||||
googleAnalyticsOAuth2: {
|
||||
scope: '',
|
||||
oauthTokenData: {
|
||||
access_token: 'ACCESSTOKEN',
|
||||
},
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```typescript
|
||||
const credentials = {
|
||||
aws: {
|
||||
region: 'eu-central-1',
|
||||
accessKeyId: 'test',
|
||||
secretAccessKey: 'test',
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
```typescript
|
||||
wordpressApi: {
|
||||
url: 'https://myblog.com',
|
||||
allowUnauthorizedCerts: false,
|
||||
username: 'nodeqa',
|
||||
password: 'fake-password',
|
||||
},
|
||||
```
|
||||
|
||||
```typescript
|
||||
const credentials = {
|
||||
telegramApi: {
|
||||
accessToken: 'testToken',
|
||||
baseUrl: 'https://api.telegram.org',
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
## Binary Data Testing
|
||||
|
||||
### Binary Data Workflow
|
||||
```json
|
||||
{
|
||||
"pinData": {
|
||||
"Upload Node": [
|
||||
{
|
||||
"json": {
|
||||
"fileId": "123",
|
||||
"fileName": "test.txt",
|
||||
"fileSize": 1024,
|
||||
"mimeType": "text/plain"
|
||||
},
|
||||
"binary": {
|
||||
"data": {
|
||||
"data": "base64data",
|
||||
"mimeType": "text/plain",
|
||||
"fileName": "test.txt"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Binary Data Test Setup
|
||||
```typescript
|
||||
new NodeTestHarness().setupTests({
|
||||
credentials,
|
||||
workflowFiles: ['binary.workflow.json'],
|
||||
assertBinaryData: true
|
||||
});
|
||||
```
|
||||
|
||||
## Error Scenario Testing
|
||||
|
||||
### Error Workflow
|
||||
```json
|
||||
{
|
||||
"pinData": {
|
||||
"Error Node": [
|
||||
{
|
||||
"json": {
|
||||
"error": "User not found",
|
||||
"message": "Invalid request",
|
||||
"code": 404
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Error Mock Setup
|
||||
```typescript
|
||||
beforeAll(() => {
|
||||
const mock = nock('https://api.example.com');
|
||||
mock.get('/users/nonexistent')
|
||||
.reply(404, { error: 'User not found' });
|
||||
});
|
||||
```
|
||||
|
||||
## Advanced Workflow Patterns
|
||||
|
||||
### Switch Node Testing
|
||||
```json
|
||||
{
|
||||
"parameters": {
|
||||
"rules": {
|
||||
"values": [
|
||||
{
|
||||
"conditions": {
|
||||
"conditions": [
|
||||
{
|
||||
"leftValue": "={{ $json.status }}",
|
||||
"rightValue": "active",
|
||||
"operator": {
|
||||
"type": "string",
|
||||
"operation": "equals"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"outputKey": "Active Users"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Set Node Testing
|
||||
```json
|
||||
{
|
||||
"parameters": {
|
||||
"fields": {
|
||||
"values": [
|
||||
{
|
||||
"name": "processed",
|
||||
"stringValue": "true"
|
||||
},
|
||||
{
|
||||
"name": "timestamp",
|
||||
"stringValue": "={{ new Date().toISOString() }}"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Code Node Testing
|
||||
```json
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "return [\n { id: 1, name: 'Item 1' },\n { id: 2, name: 'Item 2' }\n]"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Credential Types
|
||||
|
||||
### API Key Credentials
|
||||
```json
|
||||
{
|
||||
"credentials": {
|
||||
"openAiApi": {
|
||||
"id": "openai-cred-id",
|
||||
"name": "OpenAI API Key"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### OAuth2 Credentials
|
||||
```json
|
||||
{
|
||||
"credentials": {
|
||||
"slackOAuth2Api": {
|
||||
"id": "slack-oauth-id",
|
||||
"name": "Slack OAuth2"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Database Credentials
|
||||
```json
|
||||
{
|
||||
"credentials": {
|
||||
"postgres": {
|
||||
"id": "postgres-cred-id",
|
||||
"name": "PostgreSQL Database"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Essential Test Categories
|
||||
|
||||
Always include tests for:
|
||||
- **Complete Workflow Execution**: End-to-end workflow scenarios
|
||||
- **API Integration**: External API calls with proper mocking
|
||||
- **Data Flow**: Input data transformation through multiple nodes
|
||||
- **Error Scenarios**: Workflow execution with API failures
|
||||
- **Binary Data Handling**: File uploads, downloads, and processing
|
||||
- **Authentication**: Credential handling across workflow execution
|
||||
- **Node Interactions**: Multiple nodes working together
|
||||
- **Conditional Logic**: Switch nodes, conditional execution paths
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Workflow JSON Design
|
||||
- **Trigger Node**: Always start with `n8n-nodes-base.manualTrigger`
|
||||
- **Node Parameters**: Include all required parameters with realistic values
|
||||
- **Node Connections**: Define clear data flow between nodes
|
||||
- **Pin Data**: Provide expected outputs for validation
|
||||
- **Credentials**: Reference appropriate credential types
|
||||
|
||||
### Mock Setup
|
||||
- **Mock all external API calls** to ensure test reliability
|
||||
- **Use realistic response data** that matches expected outputs
|
||||
- **Test both success and error scenarios**
|
||||
- **Include proper HTTP status codes**
|
||||
- **Clean up mocks** between test runs
|
||||
|
||||
### Test Organization
|
||||
- **Group related workflows** in the same test file
|
||||
- **Use descriptive test names** that explain the scenario
|
||||
- **Keep workflow JSON files** in the same directory as test files
|
||||
- **Use consistent naming conventions** for workflow files
|
||||
|
||||
## Common Anti-Patterns to Avoid
|
||||
|
||||
1. **Don't use real external APIs** in workflow tests
|
||||
2. **Don't skip pinData** - it's essential for output validation
|
||||
3. **Don't forget to mock all API calls** - missing mocks cause test failures
|
||||
4. **Don't use hardcoded credentials** - use test credentials
|
||||
5. **Don't ignore error scenarios** - test both success and failure cases
|
||||
6. **Don't create overly complex workflows** - keep them focused and testable
|
||||
7. **Don't forget to clean up nock mocks** between tests
|
||||
8. **Don't use production data** in test workflows
|
||||
9. **Don't skip credential testing** - test authentication flows
|
||||
10. **Don't ignore node version differences** - test multiple node versions
|
||||
|
||||
## Complete Example
|
||||
|
||||
```typescript
|
||||
import { NodeTestHarness } from '@nodes-testing/node-test-harness';
|
||||
import nock from 'nock';
|
||||
|
||||
describe('NodeName', () => {
|
||||
const credentials = {
|
||||
nodeApi: {
|
||||
accessToken: 'test-token',
|
||||
baseUrl: 'https://api.example.com',
|
||||
},
|
||||
};
|
||||
|
||||
describe('Basic Operations', () => {
|
||||
beforeAll(() => {
|
||||
const mock = nock(credentials.nodeApi.baseUrl);
|
||||
|
||||
mock.get('/users')
|
||||
.reply(200, {
|
||||
users: [
|
||||
{ id: 1, name: 'User 1', email: 'user1@example.com' },
|
||||
{ id: 2, name: 'User 2', email: 'user2@example.com' }
|
||||
]
|
||||
});
|
||||
|
||||
mock.post('/users', {
|
||||
name: 'Test User',
|
||||
email: 'test@example.com'
|
||||
})
|
||||
.reply(201, {
|
||||
id: 123,
|
||||
name: 'Test User',
|
||||
email: 'test@example.com',
|
||||
status: 'active'
|
||||
});
|
||||
});
|
||||
|
||||
new NodeTestHarness().setupTests({
|
||||
credentials,
|
||||
workflowFiles: ['basic.workflow.json']
|
||||
});
|
||||
});
|
||||
|
||||
describe('Error Handling', () => {
|
||||
beforeAll(() => {
|
||||
const mock = nock(credentials.nodeApi.baseUrl);
|
||||
mock.get('/users')
|
||||
.reply(500, { error: 'Internal Server Error' });
|
||||
});
|
||||
|
||||
new NodeTestHarness().setupTests({
|
||||
credentials,
|
||||
workflowFiles: ['error.workflow.json']
|
||||
});
|
||||
});
|
||||
|
||||
describe('Binary Data Operations', () => {
|
||||
beforeAll(() => {
|
||||
const mock = nock(credentials.nodeApi.baseUrl);
|
||||
mock.post('/upload')
|
||||
.reply(200, {
|
||||
fileId: '123',
|
||||
fileName: 'test.txt',
|
||||
fileSize: 1024,
|
||||
mimeType: 'text/plain'
|
||||
});
|
||||
});
|
||||
|
||||
new NodeTestHarness().setupTests({
|
||||
credentials,
|
||||
workflowFiles: ['binary.workflow.json'],
|
||||
assertBinaryData: true
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"$schema": "../../node_modules/@biomejs/biome/configuration_schema.json",
|
||||
"extends": ["../../biome.jsonc"],
|
||||
"formatter": {
|
||||
"ignore": ["nodes/**/test/*.json", "nodes/**/__schema__/**/*.json"]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import type {
|
||||
ICredentialDataDecryptedObject,
|
||||
ICredentialTestRequest,
|
||||
ICredentialType,
|
||||
IHttpRequestOptions,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class ActionNetworkApi implements ICredentialType {
|
||||
name = 'actionNetworkApi';
|
||||
|
||||
displayName = 'Action Network API';
|
||||
|
||||
documentationUrl = 'actionnetwork';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'apiKey',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: 'https://actionnetwork.org/api/v2',
|
||||
url: '/events?per_page=1',
|
||||
},
|
||||
};
|
||||
|
||||
async authenticate(
|
||||
credentials: ICredentialDataDecryptedObject,
|
||||
requestOptions: IHttpRequestOptions,
|
||||
): Promise<IHttpRequestOptions> {
|
||||
requestOptions.headers = { 'OSDI-API-Token': credentials.apiKey };
|
||||
return requestOptions;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
import type {
|
||||
IAuthenticateGeneric,
|
||||
ICredentialTestRequest,
|
||||
ICredentialType,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class ActiveCampaignApi implements ICredentialType {
|
||||
name = 'activeCampaignApi';
|
||||
|
||||
displayName = 'ActiveCampaign API';
|
||||
|
||||
documentationUrl = 'activecampaign';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'API URL',
|
||||
name: 'apiUrl',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'apiKey',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
|
||||
authenticate: IAuthenticateGeneric = {
|
||||
type: 'generic',
|
||||
properties: {
|
||||
headers: {
|
||||
'Api-Token': '={{$credentials.apiKey}}',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: '={{$credentials.apiUrl}}',
|
||||
url: '/api/3/fields',
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class AcuitySchedulingApi implements ICredentialType {
|
||||
name = 'acuitySchedulingApi';
|
||||
|
||||
displayName = 'Acuity Scheduling API';
|
||||
|
||||
documentationUrl = 'acuityscheduling';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'User ID',
|
||||
name: 'userId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'apiKey',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class AcuitySchedulingOAuth2Api implements ICredentialType {
|
||||
name = 'acuitySchedulingOAuth2Api';
|
||||
|
||||
extends = ['oAuth2Api'];
|
||||
|
||||
displayName = 'AcuityScheduling OAuth2 API';
|
||||
|
||||
documentationUrl = 'acuityscheduling';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Grant Type',
|
||||
name: 'grantType',
|
||||
type: 'hidden',
|
||||
default: 'authorizationCode',
|
||||
},
|
||||
{
|
||||
displayName: 'Authorization URL',
|
||||
name: 'authUrl',
|
||||
type: 'hidden',
|
||||
default: 'https://acuityscheduling.com/oauth2/authorize',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Access Token URL',
|
||||
name: 'accessTokenUrl',
|
||||
type: 'hidden',
|
||||
default: 'https://acuityscheduling.com/oauth2/token',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Scope',
|
||||
name: 'scope',
|
||||
type: 'hidden',
|
||||
default: 'api-v1',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Auth URI Query Parameters',
|
||||
name: 'authQueryParameters',
|
||||
type: 'hidden',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Authentication',
|
||||
name: 'authentication',
|
||||
type: 'hidden',
|
||||
default: 'body',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import type { IAuthenticateGeneric, ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class AdaloApi implements ICredentialType {
|
||||
name = 'adaloApi';
|
||||
|
||||
displayName = 'Adalo API';
|
||||
|
||||
documentationUrl = 'adalo';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'apiKey',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
description:
|
||||
'The Adalo API is available on paid Adalo plans, find more information <a href="https://help.adalo.com/integrations/the-adalo-api" target="_blank">here</a>',
|
||||
},
|
||||
{
|
||||
displayName: 'App ID',
|
||||
name: 'appId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description:
|
||||
'You can get App ID from the URL of your app. For example, if your app URL is <strong>https://app.adalo.com/apps/1234567890/screens</strong>, then your App ID is <strong>1234567890</strong>.',
|
||||
},
|
||||
];
|
||||
|
||||
authenticate: IAuthenticateGeneric = {
|
||||
type: 'generic',
|
||||
properties: {
|
||||
headers: {
|
||||
Authorization: '=Bearer {{$credentials.apiKey}}',
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class AffinityApi implements ICredentialType {
|
||||
name = 'affinityApi';
|
||||
|
||||
displayName = 'Affinity API';
|
||||
|
||||
documentationUrl = 'affinity';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'apiKey',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class AgileCrmApi implements ICredentialType {
|
||||
name = 'agileCrmApi';
|
||||
|
||||
displayName = 'AgileCRM API';
|
||||
|
||||
documentationUrl = 'agilecrm';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Email',
|
||||
name: 'email',
|
||||
type: 'string',
|
||||
placeholder: 'name@email.com',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'apiKey',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Subdomain',
|
||||
name: 'subdomain',
|
||||
type: 'string',
|
||||
default: '',
|
||||
placeholder: 'example',
|
||||
description:
|
||||
'If the domain is https://example.agilecrm.com "example" would have to be entered',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import type { IAuthenticateGeneric, ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class AirtableApi implements ICredentialType {
|
||||
name = 'airtableApi';
|
||||
|
||||
displayName = 'Airtable API';
|
||||
|
||||
documentationUrl = 'airtable';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName:
|
||||
"This type of connection (API Key) was deprecated and can't be used anymore. Please create a new credential of type 'Access Token' instead.",
|
||||
name: 'deprecated',
|
||||
type: 'notice',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'apiKey',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
|
||||
authenticate: IAuthenticateGeneric = {
|
||||
type: 'generic',
|
||||
properties: {
|
||||
qs: {
|
||||
api_key: '={{$credentials.apiKey}}',
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
const scopes = ['schema.bases:read', 'data.records:read', 'data.records:write'];
|
||||
|
||||
export class AirtableOAuth2Api implements ICredentialType {
|
||||
name = 'airtableOAuth2Api';
|
||||
|
||||
extends = ['oAuth2Api'];
|
||||
|
||||
displayName = 'Airtable OAuth2 API';
|
||||
|
||||
documentationUrl = 'airtable';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Grant Type',
|
||||
name: 'grantType',
|
||||
type: 'hidden',
|
||||
default: 'pkce',
|
||||
},
|
||||
{
|
||||
displayName: 'Authorization URL',
|
||||
name: 'authUrl',
|
||||
type: 'hidden',
|
||||
default: 'https://airtable.com/oauth2/v1/authorize',
|
||||
},
|
||||
{
|
||||
displayName: 'Access Token URL',
|
||||
name: 'accessTokenUrl',
|
||||
type: 'hidden',
|
||||
default: 'https://airtable.com/oauth2/v1/token',
|
||||
},
|
||||
{
|
||||
displayName: 'Scope',
|
||||
name: 'scope',
|
||||
type: 'hidden',
|
||||
default: `${scopes.join(' ')}`,
|
||||
},
|
||||
{
|
||||
displayName: 'Auth URI Query Parameters',
|
||||
name: 'authQueryParameters',
|
||||
type: 'hidden',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Authentication',
|
||||
name: 'authentication',
|
||||
type: 'hidden',
|
||||
default: 'header',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import type {
|
||||
IAuthenticateGeneric,
|
||||
ICredentialTestRequest,
|
||||
ICredentialType,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class AirtableTokenApi implements ICredentialType {
|
||||
name = 'airtableTokenApi';
|
||||
|
||||
displayName = 'Airtable Personal Access Token API';
|
||||
|
||||
documentationUrl = 'airtable';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Access Token',
|
||||
name: 'accessToken',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: `Make sure you enabled the following scopes for your token:<br>
|
||||
<code>data.records:read</code><br>
|
||||
<code>data.records:write</code><br>
|
||||
<code>schema.bases:read</code><br>
|
||||
`,
|
||||
name: 'notice',
|
||||
type: 'notice',
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
|
||||
authenticate: IAuthenticateGeneric = {
|
||||
type: 'generic',
|
||||
properties: {
|
||||
headers: {
|
||||
Authorization: '=Bearer {{$credentials.accessToken}}',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: 'https://api.airtable.com/v0/meta/whoami',
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import type {
|
||||
IAuthenticateGeneric,
|
||||
ICredentialType,
|
||||
ICredentialTestRequest,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import { BASE_URL } from '../nodes/Airtop/constants';
|
||||
|
||||
export class AirtopApi implements ICredentialType {
|
||||
name = 'airtopApi';
|
||||
|
||||
displayName = 'Airtop API';
|
||||
|
||||
documentationUrl = 'airtop';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'apiKey',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description:
|
||||
'The Airtop API key. You can create one at <a href="https://portal.airtop.ai/api-keys" target="_blank">Airtop</a> for free.',
|
||||
required: true,
|
||||
typeOptions: {
|
||||
password: true,
|
||||
},
|
||||
noDataExpression: true,
|
||||
},
|
||||
];
|
||||
|
||||
authenticate: IAuthenticateGeneric = {
|
||||
type: 'generic',
|
||||
properties: {
|
||||
headers: {
|
||||
Authorization: '=Bearer {{$credentials.apiKey}}',
|
||||
'api-key': '={{$credentials.apiKey}}',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
method: 'GET',
|
||||
baseURL: BASE_URL,
|
||||
url: '/sessions',
|
||||
qs: {
|
||||
limit: 10,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import type {
|
||||
IAuthenticateGeneric,
|
||||
ICredentialTestRequest,
|
||||
ICredentialType,
|
||||
INodeProperties,
|
||||
Icon,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class AlienVaultApi implements ICredentialType {
|
||||
name = 'alienVaultApi';
|
||||
|
||||
displayName = 'AlienVault API';
|
||||
|
||||
documentationUrl = 'alienvault';
|
||||
|
||||
icon: Icon = 'file:icons/AlienVault.png';
|
||||
|
||||
httpRequestNode = {
|
||||
name: 'AlienVault',
|
||||
docsUrl: 'https://otx.alienvault.com/api',
|
||||
apiBaseUrl: 'https://otx.alienvault.com/api/v1/',
|
||||
};
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'OTX Key',
|
||||
name: 'accessToken',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
required: true,
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
|
||||
authenticate: IAuthenticateGeneric = {
|
||||
type: 'generic',
|
||||
properties: {
|
||||
headers: {
|
||||
'X-OTX-API-KEY': '={{$credentials.accessToken}}',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: 'https://otx.alienvault.com',
|
||||
url: '/api/v1/user/me',
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class Amqp implements ICredentialType {
|
||||
name = 'amqp';
|
||||
|
||||
displayName = 'AMQP';
|
||||
|
||||
documentationUrl = 'amqp';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Hostname',
|
||||
name: 'hostname',
|
||||
type: 'string',
|
||||
placeholder: 'e.g. localhost',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Port',
|
||||
name: 'port',
|
||||
type: 'number',
|
||||
default: 5672,
|
||||
},
|
||||
{
|
||||
displayName: 'User',
|
||||
name: 'username',
|
||||
type: 'string',
|
||||
placeholder: 'e.g. guest',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Password',
|
||||
name: 'password',
|
||||
type: 'string',
|
||||
placeholder: 'e.g. guest',
|
||||
typeOptions: {
|
||||
password: true,
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Transport Type',
|
||||
name: 'transportType',
|
||||
type: 'string',
|
||||
placeholder: 'e.g. tcp',
|
||||
default: '',
|
||||
hint: 'Optional transport type to use, either tcp or tls',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import type {
|
||||
IAuthenticateGeneric,
|
||||
ICredentialTestRequest,
|
||||
ICredentialType,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class ApiTemplateIoApi implements ICredentialType {
|
||||
name = 'apiTemplateIoApi';
|
||||
|
||||
displayName = 'APITemplate.io API';
|
||||
|
||||
documentationUrl = 'apitemplateio';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'apiKey',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
|
||||
authenticate: IAuthenticateGeneric = {
|
||||
type: 'generic',
|
||||
properties: {
|
||||
headers: {
|
||||
'X-API-KEY': '={{$credentials.apiKey}}',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: 'https://api.apitemplate.io/v1',
|
||||
url: '/list-templates',
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import type { IAuthenticateGeneric, ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class AsanaApi implements ICredentialType {
|
||||
name = 'asanaApi';
|
||||
|
||||
displayName = 'Asana API';
|
||||
|
||||
documentationUrl = 'asana';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Access Token',
|
||||
name: 'accessToken',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
|
||||
authenticate: IAuthenticateGeneric = {
|
||||
type: 'generic',
|
||||
properties: {
|
||||
headers: {
|
||||
Authorization: '=Bearer {{$credentials.accessToken}}',
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class AsanaOAuth2Api implements ICredentialType {
|
||||
name = 'asanaOAuth2Api';
|
||||
|
||||
extends = ['oAuth2Api'];
|
||||
|
||||
displayName = 'Asana OAuth2 API';
|
||||
|
||||
documentationUrl = 'asana';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Grant Type',
|
||||
name: 'grantType',
|
||||
type: 'hidden',
|
||||
default: 'authorizationCode',
|
||||
},
|
||||
{
|
||||
displayName: 'Authorization URL',
|
||||
name: 'authUrl',
|
||||
type: 'hidden',
|
||||
default: 'https://app.asana.com/-/oauth_authorize',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Access Token URL',
|
||||
name: 'accessTokenUrl',
|
||||
type: 'hidden',
|
||||
default: 'https://app.asana.com/-/oauth_token',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Scope',
|
||||
name: 'scope',
|
||||
type: 'hidden',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Auth URI Query Parameters',
|
||||
name: 'authQueryParameters',
|
||||
type: 'hidden',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Authentication',
|
||||
name: 'authentication',
|
||||
type: 'hidden',
|
||||
default: 'body',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
import type {
|
||||
IAuthenticateGeneric,
|
||||
ICredentialDataDecryptedObject,
|
||||
ICredentialTestRequest,
|
||||
ICredentialType,
|
||||
IHttpRequestHelper,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class Auth0ManagementApi implements ICredentialType {
|
||||
name = 'auth0ManagementApi';
|
||||
|
||||
displayName = 'Auth0 Management API';
|
||||
|
||||
documentationUrl = 'auth0management';
|
||||
|
||||
icon = { light: 'file:icons/Auth0.svg', dark: 'file:icons/Auth0.dark.svg' } as const;
|
||||
|
||||
httpRequestNode = {
|
||||
name: 'Auth0',
|
||||
docsUrl: 'https://auth0.com/docs/api/management/v2',
|
||||
apiBaseUrlPlaceholder: 'https://your-tenant.auth0.com/api/v2/users/',
|
||||
};
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Session Token',
|
||||
name: 'sessionToken',
|
||||
type: 'hidden',
|
||||
typeOptions: {
|
||||
expirable: true,
|
||||
password: true,
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Auth0 Domain',
|
||||
name: 'domain',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: 'your-domain.eu.auth0.com',
|
||||
},
|
||||
{
|
||||
displayName: 'Client ID',
|
||||
name: 'clientId',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Client Secret',
|
||||
name: 'clientSecret',
|
||||
type: 'string',
|
||||
typeOptions: {
|
||||
password: true,
|
||||
},
|
||||
required: true,
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
|
||||
async preAuthentication(this: IHttpRequestHelper, credentials: ICredentialDataDecryptedObject) {
|
||||
const { access_token } = (await this.helpers.httpRequest({
|
||||
method: 'POST',
|
||||
url: `https://${credentials.domain}/oauth/token`,
|
||||
body: {
|
||||
client_id: credentials.clientId,
|
||||
client_secret: credentials.clientSecret,
|
||||
audience: `https://${credentials.domain}/api/v2/`,
|
||||
grant_type: 'client_credentials',
|
||||
},
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
})) as { access_token: string };
|
||||
return { sessionToken: access_token };
|
||||
}
|
||||
|
||||
authenticate: IAuthenticateGeneric = {
|
||||
type: 'generic',
|
||||
properties: {
|
||||
headers: {
|
||||
Authorization: '=Bearer {{$credentials.sessionToken}}',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: '=https://{{$credentials.domain}}',
|
||||
url: '/api/v2/clients',
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class AutopilotApi implements ICredentialType {
|
||||
name = 'autopilotApi';
|
||||
|
||||
displayName = 'Autopilot API';
|
||||
|
||||
documentationUrl = 'autopilot';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'apiKey',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
import type {
|
||||
ICredentialDataDecryptedObject,
|
||||
ICredentialType,
|
||||
IHttpRequestOptions,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import type { AwsIamCredentialsType, AWSRegion } from './common/aws/types';
|
||||
import {
|
||||
awsCredentialsTest,
|
||||
awsGetSignInOptionsAndUpdateRequest,
|
||||
signOptions,
|
||||
} from './common/aws/utils';
|
||||
import { awsCustomEndpoints, awsRegionProperty } from './common/aws/descriptions';
|
||||
|
||||
export class Aws implements ICredentialType {
|
||||
name = 'aws';
|
||||
|
||||
displayName = 'AWS (IAM)';
|
||||
|
||||
documentationUrl = 'aws';
|
||||
|
||||
icon = { light: 'file:icons/AWS.svg', dark: 'file:icons/AWS.dark.svg' } as const;
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
awsRegionProperty,
|
||||
{
|
||||
displayName: 'Access Key ID',
|
||||
name: 'accessKeyId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Secret Access Key',
|
||||
name: 'secretAccessKey',
|
||||
type: 'string',
|
||||
default: '',
|
||||
typeOptions: {
|
||||
password: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Temporary Security Credentials',
|
||||
name: 'temporaryCredentials',
|
||||
description: 'Support for temporary credentials from AWS STS',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
},
|
||||
{
|
||||
displayName: 'Session Token',
|
||||
name: 'sessionToken',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
temporaryCredentials: [true],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
typeOptions: {
|
||||
password: true,
|
||||
},
|
||||
},
|
||||
...awsCustomEndpoints,
|
||||
];
|
||||
|
||||
async authenticate(
|
||||
rawCredentials: ICredentialDataDecryptedObject,
|
||||
requestOptions: IHttpRequestOptions,
|
||||
): Promise<IHttpRequestOptions> {
|
||||
const credentials = rawCredentials as AwsIamCredentialsType;
|
||||
const service = requestOptions.qs?.service as string;
|
||||
const path = (requestOptions.qs?.path as string) ?? '';
|
||||
const method = requestOptions.method;
|
||||
|
||||
let region = credentials.region;
|
||||
if (requestOptions.qs?._region) {
|
||||
region = requestOptions.qs._region as AWSRegion;
|
||||
delete requestOptions.qs._region;
|
||||
}
|
||||
|
||||
const { signOpts, url } = awsGetSignInOptionsAndUpdateRequest(
|
||||
requestOptions,
|
||||
credentials,
|
||||
path,
|
||||
method,
|
||||
service,
|
||||
region,
|
||||
);
|
||||
|
||||
const securityHeaders = {
|
||||
accessKeyId: `${credentials.accessKeyId}`.trim(),
|
||||
secretAccessKey: `${credentials.secretAccessKey}`.trim(),
|
||||
sessionToken: credentials.temporaryCredentials
|
||||
? `${credentials.sessionToken}`.trim()
|
||||
: undefined,
|
||||
};
|
||||
|
||||
return signOptions(requestOptions, signOpts, securityHeaders, url, method);
|
||||
}
|
||||
|
||||
test = awsCredentialsTest;
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
import type {
|
||||
ICredentialDataDecryptedObject,
|
||||
ICredentialType,
|
||||
IHttpRequestOptions,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
import { ApplicationError } from 'n8n-workflow';
|
||||
|
||||
import { type AwsAssumeRoleCredentialsType, type AWSRegion } from './common/aws/types';
|
||||
import { awsCustomEndpoints, awsRegionProperty } from './common/aws/descriptions';
|
||||
import {
|
||||
assumeRole,
|
||||
awsCredentialsTest,
|
||||
awsGetSignInOptionsAndUpdateRequest,
|
||||
signOptions,
|
||||
} from './common/aws/utils';
|
||||
|
||||
export class AwsAssumeRole implements ICredentialType {
|
||||
name = 'awsAssumeRole';
|
||||
|
||||
displayName = 'AWS (Assume Role)';
|
||||
|
||||
documentationUrl = 'awsassumerole';
|
||||
|
||||
icon = { light: 'file:icons/AWS.svg', dark: 'file:icons/AWS.dark.svg' } as const;
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
awsRegionProperty,
|
||||
{
|
||||
displayName: 'Use System Credentials',
|
||||
name: 'useSystemCredentialsForRole',
|
||||
description:
|
||||
'Use system credentials (environment variables, container role, etc.) to call STS.AssumeRole. Access to AWS system credentials is disabled by default and must be explicitly enabled. See <a href="https://docs.n8n.io/integrations/credentials/awsassumerole/">documentation</a> for more information.',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
displayOptions: {
|
||||
hideOnCloud: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'STS Access Key ID',
|
||||
name: 'stsAccessKeyId',
|
||||
description: 'Access Key ID to use for the STS.AssumeRole call',
|
||||
// eslint-disable-next-line n8n-nodes-base/cred-class-field-type-options-password-missing
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
useSystemCredentialsForRole: [false],
|
||||
},
|
||||
},
|
||||
required: true,
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'STS Access Key Secret',
|
||||
name: 'stsSecretAccessKey',
|
||||
description: 'Secret Access Key to use for the STS.AssumeRole call',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
useSystemCredentialsForRole: [false],
|
||||
},
|
||||
},
|
||||
required: true,
|
||||
default: '',
|
||||
typeOptions: {
|
||||
password: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'STS Session Token (optional)',
|
||||
name: 'stsSessionToken',
|
||||
description: 'Session Token to use for the STS.AssumeRole call',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
useSystemCredentialsForRole: [false],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
typeOptions: {
|
||||
password: true,
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
displayName: 'Role ARN',
|
||||
name: 'roleArn',
|
||||
description: 'The ARN of the role to assume (e.g., arn:aws:iam::123456789012:role/MyRole)',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: '',
|
||||
placeholder: 'arn:aws:iam::123456789012:role/MyRole',
|
||||
},
|
||||
{
|
||||
displayName: 'External ID',
|
||||
name: 'externalId',
|
||||
description:
|
||||
"External ID for cross-account role assumption (should be required by your role's trust policy)",
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: '',
|
||||
typeOptions: {
|
||||
password: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Role Session Name',
|
||||
name: 'roleSessionName',
|
||||
description: 'Name for the role session',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: 'n8n-session',
|
||||
},
|
||||
...awsCustomEndpoints,
|
||||
];
|
||||
|
||||
async authenticate(
|
||||
decryptedCredentials: ICredentialDataDecryptedObject,
|
||||
requestOptions: IHttpRequestOptions,
|
||||
): Promise<IHttpRequestOptions> {
|
||||
const credentials = decryptedCredentials as AwsAssumeRoleCredentialsType;
|
||||
const service = requestOptions.qs?.service as string;
|
||||
const path = (requestOptions.qs?.path as string) ?? '';
|
||||
const method = requestOptions.method;
|
||||
|
||||
let region = credentials.region;
|
||||
if (requestOptions.qs?._region) {
|
||||
region = requestOptions.qs._region as AWSRegion;
|
||||
delete requestOptions.qs._region;
|
||||
}
|
||||
|
||||
let finalCredentials = credentials;
|
||||
let securityHeaders: {
|
||||
accessKeyId: string;
|
||||
secretAccessKey: string;
|
||||
sessionToken: string;
|
||||
};
|
||||
|
||||
if (!credentials.roleArn || credentials.roleArn.trim() === '') {
|
||||
throw new ApplicationError('Role ARN is required when assuming a role.');
|
||||
}
|
||||
if (!credentials.externalId || credentials.externalId.trim() === '') {
|
||||
throw new ApplicationError('External ID is required when assuming a role.');
|
||||
}
|
||||
if (!credentials.roleSessionName || credentials.roleSessionName.trim() === '') {
|
||||
throw new ApplicationError('Role Session Name is required when assuming a role.');
|
||||
}
|
||||
try {
|
||||
securityHeaders = await assumeRole(credentials, region);
|
||||
finalCredentials = { ...credentials, ...securityHeaders };
|
||||
} catch (error) {
|
||||
console.error('Failed to assume role:', error);
|
||||
throw new ApplicationError(
|
||||
`Failed to assume role: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
||||
);
|
||||
}
|
||||
|
||||
const { signOpts, url } = awsGetSignInOptionsAndUpdateRequest(
|
||||
requestOptions,
|
||||
finalCredentials,
|
||||
path,
|
||||
method,
|
||||
service,
|
||||
region,
|
||||
);
|
||||
|
||||
return signOptions(requestOptions, signOpts, securityHeaders, url, method);
|
||||
}
|
||||
|
||||
test = awsCredentialsTest;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class AzureStorageOAuth2Api implements ICredentialType {
|
||||
name = 'azureStorageOAuth2Api';
|
||||
|
||||
displayName = 'Azure Storage OAuth2 API';
|
||||
|
||||
extends = ['microsoftOAuth2Api'];
|
||||
|
||||
documentationUrl = 'azurestorage';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Account',
|
||||
name: 'account',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Base URL',
|
||||
name: 'baseUrl',
|
||||
type: 'hidden',
|
||||
default: '=https://{{ $self["account"] }}.blob.core.windows.net',
|
||||
},
|
||||
{
|
||||
displayName: 'Scope',
|
||||
name: 'scope',
|
||||
type: 'hidden',
|
||||
default: 'https://storage.azure.com/.default',
|
||||
},
|
||||
{
|
||||
displayName: 'Microsoft Graph API Base URL',
|
||||
name: 'graphApiBaseUrl',
|
||||
type: 'hidden',
|
||||
default: 'https://graph.microsoft.com',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
import type {
|
||||
ICredentialDataDecryptedObject,
|
||||
ICredentialTestRequest,
|
||||
ICredentialType,
|
||||
IHttpRequestOptions,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
import { createHmac } from 'node:crypto';
|
||||
|
||||
import {
|
||||
getCanonicalizedHeadersString,
|
||||
getCanonicalizedResourceString,
|
||||
HeaderConstants,
|
||||
XMsVersion,
|
||||
} from '../nodes/Microsoft/Storage/GenericFunctions';
|
||||
|
||||
export class AzureStorageSharedKeyApi implements ICredentialType {
|
||||
name = 'azureStorageSharedKeyApi';
|
||||
|
||||
displayName = 'Azure Storage Shared Key API';
|
||||
|
||||
documentationUrl = 'azurestorage';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Account',
|
||||
name: 'account',
|
||||
description: 'Account name',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Key',
|
||||
name: 'key',
|
||||
description: 'Account key',
|
||||
type: 'string',
|
||||
typeOptions: {
|
||||
password: true,
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Base URL',
|
||||
name: 'baseUrl',
|
||||
type: 'hidden',
|
||||
default: '=https://{{ $self["account"] }}.blob.core.windows.net',
|
||||
},
|
||||
];
|
||||
|
||||
async authenticate(
|
||||
credentials: ICredentialDataDecryptedObject,
|
||||
requestOptions: IHttpRequestOptions,
|
||||
): Promise<IHttpRequestOptions> {
|
||||
if (requestOptions.qs) {
|
||||
for (const [key, value] of Object.entries(requestOptions.qs)) {
|
||||
if (value === undefined) {
|
||||
delete requestOptions.qs[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (requestOptions.headers) {
|
||||
for (const [key, value] of Object.entries(requestOptions.headers)) {
|
||||
if (value === undefined) {
|
||||
delete requestOptions.headers[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
requestOptions.method ??= 'GET';
|
||||
requestOptions.headers ??= {};
|
||||
|
||||
requestOptions.headers[HeaderConstants.X_MS_VERSION] ??= XMsVersion;
|
||||
requestOptions.headers[HeaderConstants.X_MS_DATE] ??= new Date().toUTCString();
|
||||
|
||||
const stringToSign: string = [
|
||||
requestOptions.method.toUpperCase(),
|
||||
requestOptions.headers[HeaderConstants.CONTENT_LANGUAGE] ?? '',
|
||||
requestOptions.headers[HeaderConstants.CONTENT_ENCODING] ?? '',
|
||||
requestOptions.headers[HeaderConstants.CONTENT_LENGTH] ?? '',
|
||||
requestOptions.headers[HeaderConstants.CONTENT_MD5] ?? '',
|
||||
requestOptions.headers[HeaderConstants.CONTENT_TYPE] ?? '',
|
||||
requestOptions.headers[HeaderConstants.DATE] ?? '',
|
||||
requestOptions.headers[HeaderConstants.IF_MODIFIED_SINCE] ?? '',
|
||||
requestOptions.headers[HeaderConstants.IF_MATCH] ?? '',
|
||||
requestOptions.headers[HeaderConstants.IF_NONE_MATCH] ?? '',
|
||||
requestOptions.headers[HeaderConstants.IF_UNMODIFIED_SINCE] ?? '',
|
||||
requestOptions.headers[HeaderConstants.RANGE] ?? '',
|
||||
getCanonicalizedHeadersString(requestOptions) +
|
||||
getCanonicalizedResourceString(requestOptions, credentials),
|
||||
].join('\n');
|
||||
|
||||
const signature: string = createHmac('sha256', Buffer.from(credentials.key as string, 'base64'))
|
||||
.update(stringToSign, 'utf8')
|
||||
.digest('base64');
|
||||
|
||||
requestOptions.headers[HeaderConstants.AUTHORIZATION] =
|
||||
`SharedKey ${credentials.account as string}:${signature}`;
|
||||
|
||||
return requestOptions;
|
||||
}
|
||||
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: '={{$credentials.baseUrl}}',
|
||||
url: '/',
|
||||
headers: {
|
||||
'x-ms-date': '={{ new Date().toUTCString() }}',
|
||||
'x-ms-version': '2021-12-02',
|
||||
},
|
||||
qs: {
|
||||
comp: 'list',
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class BambooHrApi implements ICredentialType {
|
||||
name = 'bambooHrApi';
|
||||
|
||||
displayName = 'BambooHR API';
|
||||
|
||||
documentationUrl = 'bamboohr';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Subdomain',
|
||||
name: 'subdomain',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'apiKey',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class BannerbearApi implements ICredentialType {
|
||||
name = 'bannerbearApi';
|
||||
|
||||
displayName = 'Bannerbear API';
|
||||
|
||||
documentationUrl = 'bannerbear';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Project API Key',
|
||||
name: 'apiKey',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
// https://api.baserow.io/api/redoc/#section/Authentication
|
||||
|
||||
export class BaserowApi implements ICredentialType {
|
||||
name = 'baserowApi';
|
||||
|
||||
displayName = 'Baserow API';
|
||||
|
||||
documentationUrl = 'baserow';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Host',
|
||||
name: 'host',
|
||||
type: 'string',
|
||||
default: 'https://api.baserow.io',
|
||||
},
|
||||
{
|
||||
displayName: 'Username',
|
||||
name: 'username',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Password',
|
||||
name: 'password',
|
||||
type: 'string',
|
||||
default: '',
|
||||
typeOptions: {
|
||||
password: true,
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import type {
|
||||
IAuthenticateGeneric,
|
||||
ICredentialTestRequest,
|
||||
ICredentialType,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class BeeminderApi implements ICredentialType {
|
||||
name = 'beeminderApi';
|
||||
|
||||
displayName = 'Beeminder API';
|
||||
|
||||
documentationUrl = 'beeminder';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Auth Token',
|
||||
name: 'authToken',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
|
||||
authenticate: IAuthenticateGeneric = {
|
||||
type: 'generic',
|
||||
properties: {
|
||||
body: {
|
||||
auth_token: '={{$credentials.authToken}}',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: 'https://www.beeminder.com/api/v1',
|
||||
url: '/users/me.json',
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class BeeminderOAuth2Api implements ICredentialType {
|
||||
name = 'beeminderOAuth2Api';
|
||||
|
||||
extends = ['oAuth2Api'];
|
||||
|
||||
displayName = 'Beeminder OAuth2 API';
|
||||
|
||||
documentationUrl = 'beeminder';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Grant Type',
|
||||
name: 'grantType',
|
||||
type: 'hidden',
|
||||
default: 'authorizationCode',
|
||||
},
|
||||
{
|
||||
displayName: 'Authorization URL',
|
||||
name: 'authUrl',
|
||||
type: 'hidden',
|
||||
default: 'https://www.beeminder.com/apps/authorize',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Access Token URL',
|
||||
name: 'accessTokenUrl',
|
||||
type: 'hidden',
|
||||
default: 'https://www.beeminder.com/apps/authorize',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Auth URI Query Parameters',
|
||||
name: 'authQueryParameters',
|
||||
type: 'hidden',
|
||||
default: 'response_type=token',
|
||||
},
|
||||
{
|
||||
displayName: 'Authentication',
|
||||
name: 'authentication',
|
||||
type: 'hidden',
|
||||
default: 'body',
|
||||
},
|
||||
{
|
||||
displayName: 'Scope',
|
||||
name: 'scope',
|
||||
type: 'hidden',
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import type {
|
||||
ICredentialDataDecryptedObject,
|
||||
ICredentialTestRequest,
|
||||
ICredentialType,
|
||||
IHttpRequestOptions,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class BitbucketAccessTokenApi implements ICredentialType {
|
||||
name = 'bitbucketAccessTokenApi';
|
||||
|
||||
displayName = 'Bitbucket Access Token API';
|
||||
|
||||
documentationUrl = 'bitbuckettokenapi';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Email',
|
||||
name: 'email',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Access Token',
|
||||
name: 'accessToken',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
|
||||
async authenticate(
|
||||
credentials: ICredentialDataDecryptedObject,
|
||||
requestOptions: IHttpRequestOptions,
|
||||
): Promise<IHttpRequestOptions> {
|
||||
const encodedApiKey = Buffer.from(`${credentials.email}:${credentials.accessToken}`).toString(
|
||||
'base64',
|
||||
);
|
||||
if (!requestOptions.headers) {
|
||||
requestOptions.headers = {};
|
||||
}
|
||||
requestOptions.headers.Authorization = `Basic ${encodedApiKey}`;
|
||||
return requestOptions;
|
||||
}
|
||||
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: 'https://api.bitbucket.org/2.0',
|
||||
url: '/user',
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class BitbucketApi implements ICredentialType {
|
||||
name = 'bitbucketApi';
|
||||
|
||||
displayName = 'Bitbucket API';
|
||||
|
||||
documentationUrl = 'bitbucket';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Username',
|
||||
name: 'username',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'App Password',
|
||||
name: 'appPassword',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class BitlyApi implements ICredentialType {
|
||||
name = 'bitlyApi';
|
||||
|
||||
displayName = 'Bitly API';
|
||||
|
||||
documentationUrl = 'bitly';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Access Token',
|
||||
name: 'accessToken',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class BitlyOAuth2Api implements ICredentialType {
|
||||
name = 'bitlyOAuth2Api';
|
||||
|
||||
displayName = 'Bitly OAuth2 API';
|
||||
|
||||
documentationUrl = 'bitly';
|
||||
|
||||
extends = ['oAuth2Api'];
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Grant Type',
|
||||
name: 'grantType',
|
||||
type: 'hidden',
|
||||
default: 'authorizationCode',
|
||||
},
|
||||
{
|
||||
displayName: 'Authorization URL',
|
||||
name: 'authUrl',
|
||||
type: 'hidden',
|
||||
default: 'https://bitly.com/oauth/authorize',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Access Token URL',
|
||||
name: 'accessTokenUrl',
|
||||
type: 'hidden',
|
||||
default: 'https://api-ssl.bitly.com/oauth/access_token',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Client ID',
|
||||
name: 'clientId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Client Secret',
|
||||
name: 'clientSecret',
|
||||
type: 'string',
|
||||
typeOptions: {
|
||||
password: true,
|
||||
},
|
||||
default: '',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Scope',
|
||||
name: 'scope',
|
||||
type: 'hidden',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Auth URI Query Parameters',
|
||||
name: 'authQueryParameters',
|
||||
type: 'hidden',
|
||||
default: '',
|
||||
description:
|
||||
'For some services additional query parameters have to be set which can be defined here',
|
||||
placeholder: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Authentication',
|
||||
name: 'authentication',
|
||||
type: 'hidden',
|
||||
default: 'body',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
// https://bitwarden.com/help/article/public-api/#authentication
|
||||
|
||||
export class BitwardenApi implements ICredentialType {
|
||||
name = 'bitwardenApi';
|
||||
|
||||
displayName = 'Bitwarden API';
|
||||
|
||||
documentationUrl = 'bitwarden';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Client ID',
|
||||
name: 'clientId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Client Secret',
|
||||
name: 'clientSecret',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Environment',
|
||||
name: 'environment',
|
||||
type: 'options',
|
||||
default: 'cloudHosted',
|
||||
options: [
|
||||
{
|
||||
name: 'Cloud-Hosted',
|
||||
value: 'cloudHosted',
|
||||
},
|
||||
{
|
||||
name: 'Self-Hosted',
|
||||
value: 'selfHosted',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Self-Hosted Domain',
|
||||
name: 'domain',
|
||||
type: 'string',
|
||||
default: '',
|
||||
placeholder: 'https://www.mydomain.com',
|
||||
displayOptions: {
|
||||
show: {
|
||||
environment: ['selfHosted'],
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class BoxOAuth2Api implements ICredentialType {
|
||||
name = 'boxOAuth2Api';
|
||||
|
||||
extends = ['oAuth2Api'];
|
||||
|
||||
displayName = 'Box OAuth2 API';
|
||||
|
||||
documentationUrl = 'box';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Grant Type',
|
||||
name: 'grantType',
|
||||
type: 'hidden',
|
||||
default: 'authorizationCode',
|
||||
},
|
||||
{
|
||||
displayName: 'Authorization URL',
|
||||
name: 'authUrl',
|
||||
type: 'hidden',
|
||||
default: 'https://account.box.com/api/oauth2/authorize',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Access Token URL',
|
||||
name: 'accessTokenUrl',
|
||||
type: 'hidden',
|
||||
default: 'https://api.box.com/oauth2/token',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Scope',
|
||||
name: 'scope',
|
||||
type: 'hidden',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Auth URI Query Parameters',
|
||||
name: 'authQueryParameters',
|
||||
type: 'hidden',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Authentication',
|
||||
name: 'authentication',
|
||||
type: 'hidden',
|
||||
default: 'body',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import type {
|
||||
IAuthenticateGeneric,
|
||||
ICredentialTestRequest,
|
||||
ICredentialType,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class BrandfetchApi implements ICredentialType {
|
||||
name = 'brandfetchApi';
|
||||
|
||||
displayName = 'Brandfetch API';
|
||||
|
||||
documentationUrl = 'brandfetch';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'apiKey',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
|
||||
authenticate: IAuthenticateGeneric = {
|
||||
type: 'generic',
|
||||
properties: {
|
||||
headers: {
|
||||
Authorization: '=Bearer {{$credentials.apiKey}}',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: 'https://api.brandfetch.io',
|
||||
url: '/v2/brands/brandfetch.com',
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import type {
|
||||
IAuthenticateGeneric,
|
||||
ICredentialTestRequest,
|
||||
ICredentialType,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class BrevoApi implements ICredentialType {
|
||||
// keep sendinblue name for backward compatibility
|
||||
name = 'sendInBlueApi';
|
||||
|
||||
displayName = 'Brevo';
|
||||
|
||||
documentationUrl = 'brevo';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'apiKey',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
|
||||
authenticate: IAuthenticateGeneric = {
|
||||
type: 'generic',
|
||||
properties: {
|
||||
headers: {
|
||||
'api-key': '={{$credentials.apiKey}}',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: 'https://api.brevo.com/v3',
|
||||
url: '/account',
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class BubbleApi implements ICredentialType {
|
||||
name = 'bubbleApi';
|
||||
|
||||
displayName = 'Bubble API';
|
||||
|
||||
documentationUrl = 'bubble';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'API Token',
|
||||
name: 'apiToken',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'App Name',
|
||||
name: 'appName',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Environment',
|
||||
name: 'environment',
|
||||
type: 'options',
|
||||
default: 'live',
|
||||
options: [
|
||||
{
|
||||
name: 'Development',
|
||||
value: 'development',
|
||||
},
|
||||
{
|
||||
name: 'Live',
|
||||
value: 'live',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Hosting',
|
||||
name: 'hosting',
|
||||
type: 'options',
|
||||
default: 'bubbleHosted',
|
||||
options: [
|
||||
{
|
||||
name: 'Bubble-Hosted',
|
||||
value: 'bubbleHosted',
|
||||
},
|
||||
{
|
||||
name: 'Self-Hosted',
|
||||
value: 'selfHosted',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Domain',
|
||||
name: 'domain',
|
||||
type: 'string',
|
||||
placeholder: 'mydomain.com',
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
hosting: ['selfHosted'],
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
import type {
|
||||
IAuthenticateGeneric,
|
||||
ICredentialTestRequest,
|
||||
ICredentialType,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class CalApi implements ICredentialType {
|
||||
name = 'calApi';
|
||||
|
||||
displayName = 'Cal API';
|
||||
|
||||
documentationUrl = 'cal';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'apiKey',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Host',
|
||||
name: 'host',
|
||||
type: 'string',
|
||||
default: 'https://api.cal.com',
|
||||
},
|
||||
];
|
||||
|
||||
authenticate: IAuthenticateGeneric = {
|
||||
type: 'generic',
|
||||
properties: {
|
||||
qs: {
|
||||
apiKey: '={{$credentials.apiKey}}',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: '={{$credentials.host}}',
|
||||
url: '=/v1/memberships',
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import type {
|
||||
ICredentialDataDecryptedObject,
|
||||
ICredentialTestRequest,
|
||||
ICredentialType,
|
||||
IHttpRequestOptions,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
const getAuthenticationType = (data: string): 'accessToken' | 'apiKey' => {
|
||||
// The access token is a JWT, so it will always include dots to separate
|
||||
// header, payoload and signature.
|
||||
return data.includes('.') ? 'accessToken' : 'apiKey';
|
||||
};
|
||||
|
||||
export class CalendlyApi implements ICredentialType {
|
||||
name = 'calendlyApi';
|
||||
|
||||
displayName = 'Calendly API';
|
||||
|
||||
documentationUrl = 'calendly';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
// Change name to Personal Access Token once API Keys
|
||||
// are deprecated
|
||||
{
|
||||
displayName: 'API Key or Personal Access Token',
|
||||
name: 'apiKey',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
|
||||
async authenticate(
|
||||
credentials: ICredentialDataDecryptedObject,
|
||||
requestOptions: IHttpRequestOptions,
|
||||
): Promise<IHttpRequestOptions> {
|
||||
//check whether the token is an API Key or an access token
|
||||
const { apiKey } = credentials as { apiKey: string };
|
||||
const tokenType = getAuthenticationType(apiKey);
|
||||
// remove condition once v1 is deprecated
|
||||
// and only inject credentials as an access token
|
||||
if (tokenType === 'accessToken') {
|
||||
requestOptions.headers!.Authorization = `Bearer ${apiKey}`;
|
||||
} else {
|
||||
requestOptions.headers!['X-TOKEN'] = apiKey;
|
||||
}
|
||||
return requestOptions;
|
||||
}
|
||||
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: 'https://calendly.com',
|
||||
url: '/api/v1/users/me',
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import type { ICredentialType, INodeProperties, Icon } from 'n8n-workflow';
|
||||
|
||||
export class CalendlyOAuth2Api implements ICredentialType {
|
||||
name = 'calendlyOAuth2Api';
|
||||
|
||||
extends = ['oAuth2Api'];
|
||||
|
||||
displayName = 'Calendly OAuth2 API';
|
||||
|
||||
documentationUrl = 'calendly';
|
||||
|
||||
icon: Icon = 'file:icons/Calendly.svg';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Grant Type',
|
||||
name: 'grantType',
|
||||
type: 'hidden',
|
||||
default: 'authorizationCode',
|
||||
},
|
||||
{
|
||||
displayName: 'Authorization URL',
|
||||
name: 'authUrl',
|
||||
type: 'hidden',
|
||||
default: 'https://auth.calendly.com/oauth/authorize',
|
||||
},
|
||||
{
|
||||
displayName: 'Access Token URL',
|
||||
name: 'accessTokenUrl',
|
||||
type: 'hidden',
|
||||
default: 'https://auth.calendly.com/oauth/token',
|
||||
},
|
||||
{
|
||||
displayName: 'Authentication',
|
||||
name: 'authentication',
|
||||
type: 'hidden',
|
||||
default: 'header',
|
||||
},
|
||||
{
|
||||
displayName: 'Auth URI Query Parameters',
|
||||
name: 'authQueryParameters',
|
||||
type: 'hidden',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Scope',
|
||||
name: 'scope',
|
||||
type: 'hidden',
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
import type { IAuthenticateGeneric, ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class CarbonBlackApi implements ICredentialType {
|
||||
name = 'carbonBlackApi';
|
||||
|
||||
displayName = 'Carbon Black API';
|
||||
|
||||
icon = { light: 'file:icons/vmware.svg', dark: 'file:icons/vmware.dark.svg' } as const;
|
||||
|
||||
documentationUrl = 'carbonblack';
|
||||
|
||||
httpRequestNode = {
|
||||
name: 'Carbon Black',
|
||||
docsUrl: 'https://developer.carbonblack.com/reference',
|
||||
apiBaseUrl: '',
|
||||
};
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'URL',
|
||||
name: 'apiUrl',
|
||||
type: 'string',
|
||||
placeholder: 'https://defense.conferdeploy.net/',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Access Token',
|
||||
name: 'accessToken',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
required: true,
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
|
||||
authenticate: IAuthenticateGeneric = {
|
||||
type: 'generic',
|
||||
properties: {
|
||||
headers: {
|
||||
'X-Auth-Token': '={{$credentials.accessToken}}',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// test: ICredentialTestRequest = {
|
||||
// request: {
|
||||
// baseURL: '={{$credentials.apiUrl}}',
|
||||
// url: 'integrationServices/v3/auditlogs',
|
||||
// },
|
||||
// };
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class ChargebeeApi implements ICredentialType {
|
||||
name = 'chargebeeApi';
|
||||
|
||||
displayName = 'Chargebee API';
|
||||
|
||||
documentationUrl = 'chargebee';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Account Name',
|
||||
name: 'accountName',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Api Key',
|
||||
name: 'apiKey',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class CircleCiApi implements ICredentialType {
|
||||
name = 'circleCiApi';
|
||||
|
||||
displayName = 'CircleCI API';
|
||||
|
||||
documentationUrl = 'circleci';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Personal API Token',
|
||||
name: 'apiKey',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
import type { IAuthenticateGeneric, ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class CiscoMerakiApi implements ICredentialType {
|
||||
name = 'ciscoMerakiApi';
|
||||
|
||||
displayName = 'Cisco Meraki API';
|
||||
|
||||
documentationUrl = 'ciscomeraki';
|
||||
|
||||
icon = { light: 'file:icons/Cisco.svg', dark: 'file:icons/Cisco.dark.svg' } as const;
|
||||
|
||||
httpRequestNode = {
|
||||
name: 'Cisco Meraki',
|
||||
docsUrl: 'https://developer.cisco.com/meraki/api/',
|
||||
apiBaseUrl: 'https://api.meraki.com/api/v1/',
|
||||
};
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'apiKey',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
required: true,
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
|
||||
authenticate: IAuthenticateGeneric = {
|
||||
type: 'generic',
|
||||
properties: {
|
||||
headers: {
|
||||
'X-Cisco-Meraki-API-Key': '={{$credentials.apiKey}}',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// test: ICredentialTestRequest = {
|
||||
// request: {
|
||||
// baseURL: 'https://api.meraki.com/api/v1',
|
||||
// url: '/organizations',
|
||||
// },
|
||||
// };
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
import axios from 'axios';
|
||||
import type {
|
||||
ICredentialDataDecryptedObject,
|
||||
ICredentialTestRequest,
|
||||
ICredentialType,
|
||||
IHttpRequestOptions,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class CiscoSecureEndpointApi implements ICredentialType {
|
||||
name = 'ciscoSecureEndpointApi';
|
||||
|
||||
displayName = 'Cisco Secure Endpoint (AMP) API';
|
||||
|
||||
documentationUrl = 'ciscosecureendpoint';
|
||||
|
||||
icon = { light: 'file:icons/Cisco.svg', dark: 'file:icons/Cisco.dark.svg' } as const;
|
||||
|
||||
httpRequestNode = {
|
||||
name: 'Cisco Secure Endpoint',
|
||||
docsUrl: 'https://developer.cisco.com/docs/secure-endpoint/',
|
||||
apiBaseUrl: '',
|
||||
};
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Region',
|
||||
name: 'region',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Asia Pacific, Japan, and China',
|
||||
value: 'apjc.amp',
|
||||
},
|
||||
{
|
||||
name: 'Europe',
|
||||
value: 'eu.amp',
|
||||
},
|
||||
{
|
||||
name: 'North America',
|
||||
value: 'amp',
|
||||
},
|
||||
],
|
||||
default: 'amp',
|
||||
},
|
||||
{
|
||||
displayName: 'Client ID',
|
||||
name: 'clientId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Client Secret',
|
||||
name: 'clientSecret',
|
||||
type: 'string',
|
||||
typeOptions: {
|
||||
password: true,
|
||||
},
|
||||
default: '',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
|
||||
async authenticate(
|
||||
credentials: ICredentialDataDecryptedObject,
|
||||
requestOptions: IHttpRequestOptions,
|
||||
): Promise<IHttpRequestOptions> {
|
||||
const clientId = credentials.clientId as string;
|
||||
const clientSecret = credentials.clientSecret as string;
|
||||
const region = credentials.region as string;
|
||||
|
||||
const secureXToken = await axios({
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
Accept: 'application/json',
|
||||
},
|
||||
auth: {
|
||||
username: clientId,
|
||||
password: clientSecret,
|
||||
},
|
||||
method: 'POST',
|
||||
data: new URLSearchParams({
|
||||
grant_type: 'client_credentials',
|
||||
}).toString(),
|
||||
url: `https://visibility.${region}.cisco.com/iroh/oauth2/token`,
|
||||
});
|
||||
|
||||
const secureEndpointToken = await axios({
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
Accept: 'application/json',
|
||||
Authorization: `Bearer ${secureXToken.data.access_token}`,
|
||||
},
|
||||
method: 'POST',
|
||||
data: new URLSearchParams({
|
||||
grant_type: 'client_credentials',
|
||||
}).toString(),
|
||||
url: `https://api.${region}.cisco.com/v3/access_tokens`,
|
||||
});
|
||||
|
||||
const requestOptionsWithAuth: IHttpRequestOptions = {
|
||||
...requestOptions,
|
||||
headers: {
|
||||
...requestOptions.headers,
|
||||
Authorization: `Bearer ${secureEndpointToken.data.access_token}`,
|
||||
},
|
||||
};
|
||||
|
||||
return requestOptionsWithAuth;
|
||||
}
|
||||
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: '=https://api.{{$credentials.region}}.cisco.com',
|
||||
url: '/v3/organizations',
|
||||
qs: {
|
||||
size: 10,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
import type {
|
||||
IAuthenticateGeneric,
|
||||
ICredentialDataDecryptedObject,
|
||||
ICredentialTestRequest,
|
||||
ICredentialType,
|
||||
IHttpRequestHelper,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class CiscoUmbrellaApi implements ICredentialType {
|
||||
name = 'ciscoUmbrellaApi';
|
||||
|
||||
displayName = 'Cisco Umbrella API';
|
||||
|
||||
documentationUrl = 'ciscoumbrella';
|
||||
|
||||
icon = { light: 'file:icons/Cisco.svg', dark: 'file:icons/Cisco.dark.svg' } as const;
|
||||
|
||||
httpRequestNode = {
|
||||
name: 'Cisco Umbrella',
|
||||
docsUrl: 'https://developer.cisco.com/docs/cloud-security/',
|
||||
apiBaseUrl: 'https://api.umbrella.com/',
|
||||
};
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Session Token',
|
||||
name: 'sessionToken',
|
||||
type: 'hidden',
|
||||
|
||||
typeOptions: {
|
||||
expirable: true,
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'apiKey',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
required: true,
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Secret',
|
||||
name: 'secret',
|
||||
type: 'string',
|
||||
typeOptions: {
|
||||
password: true,
|
||||
},
|
||||
required: true,
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
|
||||
async preAuthentication(this: IHttpRequestHelper, credentials: ICredentialDataDecryptedObject) {
|
||||
const url = 'https://api.umbrella.com';
|
||||
const { access_token } = (await this.helpers.httpRequest({
|
||||
method: 'POST',
|
||||
url: `${
|
||||
url.endsWith('/') ? url.slice(0, -1) : url
|
||||
}/auth/v2/token?grant_type=client_credentials`,
|
||||
auth: {
|
||||
username: credentials.apiKey as string,
|
||||
password: credentials.secret as string,
|
||||
},
|
||||
headers: {
|
||||
'Content-Type': 'x-www-form-urlencoded',
|
||||
},
|
||||
})) as { access_token: string };
|
||||
return { sessionToken: access_token };
|
||||
}
|
||||
|
||||
authenticate: IAuthenticateGeneric = {
|
||||
type: 'generic',
|
||||
properties: {
|
||||
headers: {
|
||||
Authorization: '=Bearer {{$credentials.sessionToken}}',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: 'https://api.umbrella.com',
|
||||
url: '/users',
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class CiscoWebexOAuth2Api implements ICredentialType {
|
||||
name = 'ciscoWebexOAuth2Api';
|
||||
|
||||
extends = ['oAuth2Api'];
|
||||
|
||||
displayName = 'Cisco Webex OAuth2 API';
|
||||
|
||||
documentationUrl = 'ciscowebex';
|
||||
|
||||
icon = { light: 'file:icons/Cisco.svg', dark: 'file:icons/Cisco.dark.svg' } as const;
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Grant Type',
|
||||
name: 'grantType',
|
||||
type: 'hidden',
|
||||
default: 'authorizationCode',
|
||||
},
|
||||
{
|
||||
displayName: 'Authorization URL',
|
||||
name: 'authUrl',
|
||||
type: 'hidden',
|
||||
default: 'https://webexapis.com/v1/authorize',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Access Token URL',
|
||||
name: 'accessTokenUrl',
|
||||
type: 'hidden',
|
||||
default: 'https://webexapis.com/v1/access_token',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Scope',
|
||||
name: 'scope',
|
||||
type: 'hidden',
|
||||
default:
|
||||
'spark:memberships_read meeting:recordings_read spark:kms meeting:schedules_read spark:rooms_read spark:messages_write spark:memberships_write meeting:recordings_write meeting:preferences_read spark:messages_read meeting:schedules_write',
|
||||
},
|
||||
{
|
||||
displayName: 'Auth URI Query Parameters',
|
||||
name: 'authQueryParameters',
|
||||
type: 'hidden',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Authentication',
|
||||
name: 'authentication',
|
||||
type: 'hidden',
|
||||
default: 'body',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class ClearbitApi implements ICredentialType {
|
||||
name = 'clearbitApi';
|
||||
|
||||
displayName = 'Clearbit API';
|
||||
|
||||
documentationUrl = 'clearbit';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'apiKey',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import type {
|
||||
IAuthenticateGeneric,
|
||||
ICredentialTestRequest,
|
||||
ICredentialType,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class ClickUpApi implements ICredentialType {
|
||||
name = 'clickUpApi';
|
||||
|
||||
displayName = 'ClickUp API';
|
||||
|
||||
documentationUrl = 'clickup';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Access Token',
|
||||
name: 'accessToken',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
|
||||
authenticate: IAuthenticateGeneric = {
|
||||
type: 'generic',
|
||||
properties: {
|
||||
headers: {
|
||||
Authorization: '={{$credentials.accessToken}}',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: 'https://api.clickup.com/api/v2',
|
||||
url: '/team',
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class ClickUpOAuth2Api implements ICredentialType {
|
||||
name = 'clickUpOAuth2Api';
|
||||
|
||||
extends = ['oAuth2Api'];
|
||||
|
||||
displayName = 'ClickUp OAuth2 API';
|
||||
|
||||
documentationUrl = 'clickup';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Grant Type',
|
||||
name: 'grantType',
|
||||
type: 'hidden',
|
||||
default: 'authorizationCode',
|
||||
},
|
||||
{
|
||||
displayName: 'Authorization URL',
|
||||
name: 'authUrl',
|
||||
type: 'hidden',
|
||||
default: 'https://app.clickup.com/api',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Access Token URL',
|
||||
name: 'accessTokenUrl',
|
||||
type: 'hidden',
|
||||
default: 'https://api.clickup.com/api/v2/oauth/token',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Scope',
|
||||
name: 'scope',
|
||||
type: 'hidden',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Auth URI Query Parameters',
|
||||
name: 'authQueryParameters',
|
||||
type: 'hidden',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Authentication',
|
||||
name: 'authentication',
|
||||
type: 'hidden',
|
||||
default: 'body',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import type {
|
||||
IAuthenticateGeneric,
|
||||
ICredentialTestRequest,
|
||||
ICredentialType,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class ClockifyApi implements ICredentialType {
|
||||
name = 'clockifyApi';
|
||||
|
||||
displayName = 'Clockify API';
|
||||
|
||||
documentationUrl = 'clockify';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'apiKey',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
|
||||
authenticate: IAuthenticateGeneric = {
|
||||
type: 'generic',
|
||||
properties: {
|
||||
headers: {
|
||||
'X-Api-Key': '={{$credentials.apiKey}}',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: 'https://api.clockify.me/api/v1',
|
||||
url: '/workspaces',
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import type {
|
||||
IAuthenticateGeneric,
|
||||
ICredentialTestRequest,
|
||||
ICredentialType,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class CloudflareApi implements ICredentialType {
|
||||
name = 'cloudflareApi';
|
||||
|
||||
displayName = 'Cloudflare API';
|
||||
|
||||
documentationUrl = 'cloudflare';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'API Token',
|
||||
name: 'apiToken',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
|
||||
authenticate: IAuthenticateGeneric = {
|
||||
type: 'generic',
|
||||
properties: {
|
||||
headers: {
|
||||
Authorization: '=Bearer {{$credentials.apiToken}}',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: 'https://api.cloudflare.com/client/v4/user/tokens/verify',
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class CockpitApi implements ICredentialType {
|
||||
name = 'cockpitApi';
|
||||
|
||||
displayName = 'Cockpit API';
|
||||
|
||||
documentationUrl = 'cockpit';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Cockpit URL',
|
||||
name: 'url',
|
||||
type: 'string',
|
||||
default: '',
|
||||
placeholder: 'https://example.com',
|
||||
},
|
||||
{
|
||||
displayName: 'Access Token',
|
||||
name: 'accessToken',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import type { ICredentialTestRequest, ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class CodaApi implements ICredentialType {
|
||||
name = 'codaApi';
|
||||
|
||||
displayName = 'Coda API';
|
||||
|
||||
documentationUrl = 'coda';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Access Token',
|
||||
name: 'accessToken',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: 'https://coda.io/apis/v1/whoami',
|
||||
headers: {
|
||||
Authorization: '=Bearer {{$credentials.accessToken}}',
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
//https://www.contentful.com/developers/docs/references/authentication/
|
||||
export class ContentfulApi implements ICredentialType {
|
||||
name = 'contentfulApi';
|
||||
|
||||
displayName = 'Contentful API';
|
||||
|
||||
documentationUrl = 'contentful';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Space ID',
|
||||
name: 'spaceId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
description: 'The ID for the Contentful space',
|
||||
},
|
||||
{
|
||||
displayName: 'Content Delivery API Access Token',
|
||||
name: 'ContentDeliveryaccessToken',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
description:
|
||||
'Access token that has access to the space. Can be left empty if only Delivery API should be used.',
|
||||
},
|
||||
{
|
||||
displayName: 'Content Preview API Access Token',
|
||||
name: 'ContentPreviewaccessToken',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
description:
|
||||
'Access token that has access to the space. Can be left empty if only Preview API should be used.',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
import type {
|
||||
IAuthenticateGeneric,
|
||||
Icon,
|
||||
ICredentialTestRequest,
|
||||
ICredentialType,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class ConvertApi implements ICredentialType {
|
||||
name = 'convertApi';
|
||||
|
||||
displayName = 'ConvertAPI';
|
||||
|
||||
documentationUrl = 'convertapi';
|
||||
|
||||
icon: Icon = 'file:icons/ConvertApi.png';
|
||||
|
||||
httpRequestNode = {
|
||||
name: 'ConvertAPI',
|
||||
docsUrl: 'https://docs.convertapi.com/docs/getting-started',
|
||||
apiBaseUrl: 'https://v2.convertapi.com/',
|
||||
};
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'API Token',
|
||||
name: 'apiToken',
|
||||
type: 'string',
|
||||
typeOptions: {
|
||||
password: true,
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
|
||||
authenticate: IAuthenticateGeneric = {
|
||||
type: 'generic',
|
||||
properties: {
|
||||
headers: {
|
||||
Authorization: '=Bearer {{$credentials.apiToken}}',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: 'https://v2.convertapi.com',
|
||||
url: '/convert/docx/to/pdf',
|
||||
ignoreHttpStatusErrors: true,
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
type: 'responseSuccessBody',
|
||||
properties: {
|
||||
key: 'Code',
|
||||
value: 4013,
|
||||
message: 'API Token or Secret is invalid.',
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
import type {
|
||||
ICredentialDataDecryptedObject,
|
||||
ICredentialTestRequest,
|
||||
ICredentialType,
|
||||
IHttpRequestOptions,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
import { getUrl } from './common/http';
|
||||
|
||||
export class ConvertKitApi implements ICredentialType {
|
||||
name = 'convertKitApi';
|
||||
|
||||
displayName = 'ConvertKit API';
|
||||
|
||||
documentationUrl = 'convertkit';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'API Secret',
|
||||
name: 'apiSecret',
|
||||
type: 'string',
|
||||
default: '',
|
||||
typeOptions: {
|
||||
password: true,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
async authenticate(credentials: ICredentialDataDecryptedObject, options: IHttpRequestOptions) {
|
||||
const url = getUrl(options);
|
||||
const secret = {
|
||||
api_secret: credentials.apiSecret as string,
|
||||
};
|
||||
// it's a webhook so include the api secret on the body
|
||||
if (url?.includes('/automations/hooks')) {
|
||||
options.body = options.body || {};
|
||||
if (typeof options.body === 'object') {
|
||||
Object.assign(options.body, secret);
|
||||
}
|
||||
} else {
|
||||
options.qs = options.qs || {};
|
||||
if (typeof options.qs === 'object') {
|
||||
Object.assign(options.qs, secret);
|
||||
}
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
url: 'https://api.convertkit.com/v3/account',
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
import type {
|
||||
IAuthenticateGeneric,
|
||||
ICredentialTestRequest,
|
||||
ICredentialType,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class CopperApi implements ICredentialType {
|
||||
name = 'copperApi';
|
||||
|
||||
displayName = 'Copper API';
|
||||
|
||||
documentationUrl = 'copper';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'apiKey',
|
||||
required: true,
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Email',
|
||||
name: 'email',
|
||||
required: true,
|
||||
type: 'string',
|
||||
placeholder: 'name@email.com',
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
|
||||
authenticate: IAuthenticateGeneric = {
|
||||
type: 'generic',
|
||||
properties: {
|
||||
headers: {
|
||||
'X-PW-AccessToken': '={{$credentials.apiKey}}',
|
||||
'X-PW-Application': 'developer_api',
|
||||
'X-PW-UserEmail': '={{$credentials.email}}',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: 'https://api.copper.com/developer_api/v1/',
|
||||
url: 'users/me',
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import type {
|
||||
IAuthenticateGeneric,
|
||||
ICredentialTestRequest,
|
||||
ICredentialType,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class CortexApi implements ICredentialType {
|
||||
name = 'cortexApi';
|
||||
|
||||
displayName = 'Cortex API';
|
||||
|
||||
documentationUrl = 'cortex';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'cortexApiKey',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Cortex Instance',
|
||||
name: 'host',
|
||||
type: 'string',
|
||||
description: 'The URL of the Cortex instance',
|
||||
default: '',
|
||||
placeholder: 'https://localhost:9001',
|
||||
},
|
||||
];
|
||||
|
||||
authenticate: IAuthenticateGeneric = {
|
||||
type: 'generic',
|
||||
properties: {
|
||||
headers: {
|
||||
Authorization: '=Bearer {{$credentials.cortexApiKey}}',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: '={{$credentials.host}}',
|
||||
url: '/api/analyzer',
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class CrateDb implements ICredentialType {
|
||||
name = 'crateDb';
|
||||
|
||||
displayName = 'CrateDB';
|
||||
|
||||
documentationUrl = 'cratedb';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Host',
|
||||
name: 'host',
|
||||
type: 'string',
|
||||
default: 'localhost',
|
||||
},
|
||||
{
|
||||
displayName: 'Database',
|
||||
name: 'database',
|
||||
type: 'string',
|
||||
default: 'doc',
|
||||
},
|
||||
{
|
||||
displayName: 'User',
|
||||
name: 'user',
|
||||
type: 'string',
|
||||
default: 'crate',
|
||||
},
|
||||
{
|
||||
displayName: 'Password',
|
||||
name: 'password',
|
||||
type: 'string',
|
||||
typeOptions: {
|
||||
password: true,
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'SSL',
|
||||
name: 'ssl',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Allow',
|
||||
value: 'allow',
|
||||
},
|
||||
{
|
||||
name: 'Disable',
|
||||
value: 'disable',
|
||||
},
|
||||
{
|
||||
name: 'Require',
|
||||
value: 'require',
|
||||
},
|
||||
],
|
||||
default: 'disable',
|
||||
},
|
||||
{
|
||||
displayName: 'Port',
|
||||
name: 'port',
|
||||
type: 'number',
|
||||
default: 5432,
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
import type {
|
||||
IAuthenticateGeneric,
|
||||
ICredentialDataDecryptedObject,
|
||||
ICredentialTestRequest,
|
||||
ICredentialType,
|
||||
IHttpRequestHelper,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class CrowdStrikeOAuth2Api implements ICredentialType {
|
||||
name = 'crowdStrikeOAuth2Api';
|
||||
|
||||
displayName = 'CrowdStrike OAuth2 API';
|
||||
|
||||
documentationUrl = 'crowdstrike';
|
||||
|
||||
icon = { light: 'file:icons/CrowdStrike.svg', dark: 'file:icons/CrowdStrike.dark.svg' } as const;
|
||||
|
||||
httpRequestNode = {
|
||||
name: 'CrowdStrike',
|
||||
docsUrl: 'https://developer.crowdstrike.com/',
|
||||
apiBaseUrl: '',
|
||||
};
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Session Token',
|
||||
name: 'sessionToken',
|
||||
type: 'hidden',
|
||||
|
||||
typeOptions: {
|
||||
expirable: true,
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'URL',
|
||||
name: 'url',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Client ID',
|
||||
name: 'clientId',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Client Secret',
|
||||
name: 'clientSecret',
|
||||
type: 'string',
|
||||
typeOptions: {
|
||||
password: true,
|
||||
},
|
||||
required: true,
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
|
||||
async preAuthentication(this: IHttpRequestHelper, credentials: ICredentialDataDecryptedObject) {
|
||||
const url = credentials.url as string;
|
||||
const { access_token } = (await this.helpers.httpRequest({
|
||||
method: 'POST',
|
||||
url: `${url.endsWith('/') ? url.slice(0, -1) : url}/oauth2/token`,
|
||||
body: {
|
||||
client_id: credentials.clientId,
|
||||
client_secret: credentials.clientSecret,
|
||||
},
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
})) as { access_token: string };
|
||||
return { sessionToken: access_token };
|
||||
}
|
||||
|
||||
authenticate: IAuthenticateGeneric = {
|
||||
type: 'generic',
|
||||
properties: {
|
||||
headers: {
|
||||
Authorization: '=Bearer {{$credentials.sessionToken}}',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: '={{$credentials?.url}}',
|
||||
url: 'user-management/queries/users/v1',
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import type { ICredentialType, INodeProperties, Icon, ThemeIconColor } from 'n8n-workflow';
|
||||
|
||||
export class Crypto implements ICredentialType {
|
||||
name = 'crypto';
|
||||
|
||||
displayName = 'Crypto';
|
||||
|
||||
documentationUrl = 'crypto';
|
||||
|
||||
icon: Icon = 'fa:key';
|
||||
|
||||
iconColor: ThemeIconColor = 'green';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Hmac Secret',
|
||||
name: 'hmacSecret',
|
||||
type: 'string',
|
||||
description: 'Secret used in the Hmac action',
|
||||
typeOptions: {
|
||||
password: true,
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Private Key',
|
||||
name: 'signPrivateKey',
|
||||
type: 'string',
|
||||
description: 'Private Key used in the Sign action',
|
||||
typeOptions: {
|
||||
rows: 4,
|
||||
password: true,
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import type {
|
||||
IAuthenticateGeneric,
|
||||
ICredentialTestRequest,
|
||||
ICredentialType,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class CurrentsApi implements ICredentialType {
|
||||
name = 'currentsApi';
|
||||
|
||||
displayName = 'Currents API';
|
||||
|
||||
documentationUrl = 'https://docs.currents.dev/api';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'apiKey',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
required: true,
|
||||
description: 'API key from Currents Dashboard (Organization > API & Record Keys)',
|
||||
},
|
||||
];
|
||||
|
||||
authenticate: IAuthenticateGeneric = {
|
||||
type: 'generic',
|
||||
properties: {
|
||||
headers: {
|
||||
Authorization: '=Bearer {{$credentials.apiKey}}',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: 'https://api.currents.dev/v1',
|
||||
url: '/projects',
|
||||
method: 'GET',
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
import { ApplicationError } from '@n8n/errors';
|
||||
import type {
|
||||
ICredentialDataDecryptedObject,
|
||||
ICredentialType,
|
||||
IHttpRequestOptions,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class CustomerIoApi implements ICredentialType {
|
||||
name = 'customerIoApi';
|
||||
|
||||
displayName = 'Customer.io API';
|
||||
|
||||
documentationUrl = 'customerio';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Tracking API Key',
|
||||
name: 'trackingApiKey',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
description: 'Required for tracking API',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Region',
|
||||
name: 'region',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'EU region',
|
||||
value: 'track-eu.customer.io',
|
||||
},
|
||||
{
|
||||
name: 'Global region',
|
||||
value: 'track.customer.io',
|
||||
},
|
||||
],
|
||||
default: 'track.customer.io',
|
||||
description: 'Should be set based on your account region',
|
||||
hint: 'The region will be omitted when being used with the HTTP node',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Tracking Site ID',
|
||||
name: 'trackingSiteId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Required for tracking API',
|
||||
},
|
||||
{
|
||||
displayName: 'App API Key',
|
||||
name: 'appApiKey',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
description: 'Required for App API',
|
||||
},
|
||||
];
|
||||
|
||||
async authenticate(
|
||||
credentials: ICredentialDataDecryptedObject,
|
||||
requestOptions: IHttpRequestOptions,
|
||||
): Promise<IHttpRequestOptions> {
|
||||
// @ts-ignore
|
||||
const url = new URL(requestOptions.url ? requestOptions.url : requestOptions.uri);
|
||||
if (
|
||||
url.hostname === 'track.customer.io' ||
|
||||
url.hostname === 'track-eu.customer.io' ||
|
||||
url.hostname === 'api.customer.io' ||
|
||||
url.hostname === 'api-eu.customer.io'
|
||||
) {
|
||||
const basicAuthKey = Buffer.from(
|
||||
`${credentials.trackingSiteId}:${credentials.trackingApiKey}`,
|
||||
).toString('base64');
|
||||
// @ts-ignore
|
||||
Object.assign(requestOptions.headers, { Authorization: `Basic ${basicAuthKey}` });
|
||||
} else if (
|
||||
url.hostname === 'beta-api.customer.io' ||
|
||||
url.hostname === 'beta-api-eu.customer.io'
|
||||
) {
|
||||
// @ts-ignore
|
||||
Object.assign(requestOptions.headers, {
|
||||
Authorization: `Bearer ${credentials.appApiKey as string}`,
|
||||
});
|
||||
} else {
|
||||
throw new ApplicationError('Unknown way of authenticating', { level: 'warning' });
|
||||
}
|
||||
|
||||
return requestOptions;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
import type {
|
||||
ICredentialDataDecryptedObject,
|
||||
ICredentialTestRequest,
|
||||
ICredentialType,
|
||||
IHttpRequestOptions,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class DatadogApi implements ICredentialType {
|
||||
name = 'datadogApi';
|
||||
|
||||
displayName = 'Datadog API';
|
||||
|
||||
documentationUrl = 'datadog';
|
||||
|
||||
icon = { light: 'file:icons/Datadog.svg', dark: 'file:icons/Datadog.svg' } as const;
|
||||
|
||||
httpRequestNode = {
|
||||
name: 'Datadog',
|
||||
docsUrl: 'https://docs.datadoghq.com/api/latest/',
|
||||
apiBaseUrlPlaceholder: 'https://api.datadoghq.com/api/v1/metrics',
|
||||
};
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'URL',
|
||||
name: 'url',
|
||||
required: true,
|
||||
type: 'string',
|
||||
default: 'https://api.datadoghq.com',
|
||||
},
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'apiKey',
|
||||
required: true,
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'APP Key',
|
||||
name: 'appKey',
|
||||
required: false,
|
||||
type: 'string',
|
||||
default: '',
|
||||
typeOptions: { password: true },
|
||||
description: 'For some endpoints, you also need an Application key.',
|
||||
},
|
||||
];
|
||||
|
||||
async authenticate(
|
||||
credentials: ICredentialDataDecryptedObject,
|
||||
requestOptions: IHttpRequestOptions,
|
||||
): Promise<IHttpRequestOptions> {
|
||||
requestOptions.headers = {
|
||||
'DD-API-KEY': credentials.apiKey,
|
||||
'DD-APPLICATION-KEY': credentials.appKey,
|
||||
};
|
||||
if (!requestOptions.headers['DD-APPLICATION-KEY']) {
|
||||
delete requestOptions.headers['DD-APPLICATION-KEY'];
|
||||
}
|
||||
|
||||
return requestOptions;
|
||||
}
|
||||
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: '={{$credentials.url}}',
|
||||
url: '/api/v1/validate',
|
||||
method: 'GET',
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import type {
|
||||
IAuthenticateGeneric,
|
||||
ICredentialTestRequest,
|
||||
ICredentialType,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class DeepLApi implements ICredentialType {
|
||||
name = 'deepLApi';
|
||||
|
||||
displayName = 'DeepL API';
|
||||
|
||||
documentationUrl = 'deepl';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'apiKey',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'API Plan',
|
||||
name: 'apiPlan',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Pro Plan',
|
||||
value: 'pro',
|
||||
},
|
||||
{
|
||||
name: 'Free Plan',
|
||||
value: 'free',
|
||||
},
|
||||
],
|
||||
default: 'pro',
|
||||
},
|
||||
];
|
||||
|
||||
authenticate: IAuthenticateGeneric = {
|
||||
type: 'generic',
|
||||
properties: {
|
||||
qs: {
|
||||
auth_key: '={{$credentials.apiKey}}',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL:
|
||||
'={{$credentials.apiPlan === "pro" ? "https://api.deepl.com/v2" : "https://api-free.deepl.com/v2" }}',
|
||||
url: '/usage',
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class DemioApi implements ICredentialType {
|
||||
name = 'demioApi';
|
||||
|
||||
displayName = 'Demio API';
|
||||
|
||||
documentationUrl = 'demio';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'apiKey',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'API Secret',
|
||||
name: 'apiSecret',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
import type {
|
||||
IAuthenticateGeneric,
|
||||
ICredentialTestRequest,
|
||||
ICredentialType,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class DfirIrisApi implements ICredentialType {
|
||||
name = 'dfirIrisApi';
|
||||
|
||||
displayName = 'DFIR-IRIS API';
|
||||
|
||||
documentationUrl = 'dfiriris';
|
||||
|
||||
icon = { light: 'file:icons/DfirIris.svg', dark: 'file:icons/DfirIris.svg' } as const;
|
||||
|
||||
httpRequestNode = {
|
||||
name: 'DFIR-IRIS',
|
||||
docsUrl: 'https://docs.dfir-iris.org/operations/api/',
|
||||
apiBaseUrlPlaceholder: 'http://<yourserver_ip>/manage/cases/list',
|
||||
};
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Base URL',
|
||||
name: 'baseUrl',
|
||||
type: 'string',
|
||||
default: '',
|
||||
placeholder: 'e.g. https://localhost',
|
||||
description:
|
||||
'The API endpoints are reachable on the same Address and port as the web interface.',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'apiKey',
|
||||
required: true,
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Ignore SSL Issues (Insecure)',
|
||||
name: 'skipSslCertificateValidation',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
},
|
||||
];
|
||||
|
||||
authenticate: IAuthenticateGeneric = {
|
||||
type: 'generic',
|
||||
properties: {
|
||||
headers: {
|
||||
Authorization: '=Bearer {{$credentials.apiKey}}',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: '={{$credentials.baseUrl}}',
|
||||
url: '/api/ping',
|
||||
method: 'GET',
|
||||
skipSslCertificateValidation: '={{$credentials.skipSslCertificateValidation}}',
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class DhlApi implements ICredentialType {
|
||||
name = 'dhlApi';
|
||||
|
||||
displayName = 'DHL API';
|
||||
|
||||
documentationUrl = 'dhl';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'apiKey',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import type {
|
||||
IAuthenticateGeneric,
|
||||
ICredentialTestRequest,
|
||||
ICredentialType,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class DiscordBotApi implements ICredentialType {
|
||||
name = 'discordBotApi';
|
||||
|
||||
displayName = 'Discord Bot API';
|
||||
|
||||
documentationUrl = 'discord';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Bot Token',
|
||||
name: 'botToken',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
typeOptions: {
|
||||
password: true,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
authenticate: IAuthenticateGeneric = {
|
||||
type: 'generic',
|
||||
properties: {
|
||||
headers: {
|
||||
Authorization: '=Bot {{$credentials.botToken}}',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: 'https://discord.com/api/v10/',
|
||||
url: '/users/@me/guilds',
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
const defaultScopes = ['identify', 'guilds', 'guilds.join', 'bot'];
|
||||
|
||||
export class DiscordOAuth2Api implements ICredentialType {
|
||||
name = 'discordOAuth2Api';
|
||||
|
||||
extends = ['oAuth2Api'];
|
||||
|
||||
displayName = 'Discord OAuth2 API';
|
||||
|
||||
documentationUrl = 'discord';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Bot Token',
|
||||
name: 'botToken',
|
||||
type: 'string',
|
||||
default: '',
|
||||
typeOptions: {
|
||||
password: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Grant Type',
|
||||
name: 'grantType',
|
||||
type: 'hidden',
|
||||
default: 'authorizationCode',
|
||||
},
|
||||
{
|
||||
displayName: 'Authorization URL',
|
||||
name: 'authUrl',
|
||||
type: 'hidden',
|
||||
default: 'https://discord.com/api/oauth2/authorize',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Access Token URL',
|
||||
name: 'accessTokenUrl',
|
||||
type: 'hidden',
|
||||
default: 'https://discord.com/api/oauth2/token',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Auth URI Query Parameters',
|
||||
name: 'authQueryParameters',
|
||||
type: 'hidden',
|
||||
default: 'permissions=1642758929655',
|
||||
},
|
||||
|
||||
{
|
||||
displayName: 'Custom Scopes',
|
||||
name: 'customScopes',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Define custom scopes',
|
||||
},
|
||||
{
|
||||
displayName:
|
||||
'The default scopes needed for the node to work are already set, If you change these the node may not function correctly.',
|
||||
name: 'customScopesNotice',
|
||||
type: 'notice',
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
customScopes: [true],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Enabled Scopes',
|
||||
name: 'enabledScopes',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
customScopes: [true],
|
||||
},
|
||||
},
|
||||
default: defaultScopes.join(' '),
|
||||
description: 'Scopes that should be enabled',
|
||||
},
|
||||
{
|
||||
displayName: 'Scope',
|
||||
name: 'scope',
|
||||
type: 'hidden',
|
||||
default:
|
||||
'={{$self["customScopes"] ? $self["enabledScopes"] : "' + defaultScopes.join(' ') + '"}}',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import type { ICredentialTestRequest, ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class DiscordWebhookApi implements ICredentialType {
|
||||
name = 'discordWebhookApi';
|
||||
|
||||
displayName = 'Discord Webhook';
|
||||
|
||||
documentationUrl = 'discord';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Webhook URL',
|
||||
name: 'webhookUri',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: '',
|
||||
placeholder: 'https://discord.com/api/webhooks/ID/TOKEN',
|
||||
typeOptions: {
|
||||
password: true,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: '={{ $credentials.webhookUri }}',
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
import type {
|
||||
ICredentialDataDecryptedObject,
|
||||
ICredentialTestRequest,
|
||||
ICredentialType,
|
||||
IHttpRequestOptions,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class DiscourseApi implements ICredentialType {
|
||||
name = 'discourseApi';
|
||||
|
||||
displayName = 'Discourse API';
|
||||
|
||||
documentationUrl = 'discourse';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'URL',
|
||||
name: 'url',
|
||||
required: true,
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'apiKey',
|
||||
required: true,
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Username',
|
||||
name: 'username',
|
||||
required: true,
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
|
||||
async authenticate(
|
||||
credentials: ICredentialDataDecryptedObject,
|
||||
requestOptions: IHttpRequestOptions,
|
||||
): Promise<IHttpRequestOptions> {
|
||||
requestOptions.headers = {
|
||||
'Api-Key': credentials.apiKey,
|
||||
'Api-Username': credentials.username,
|
||||
};
|
||||
|
||||
if (requestOptions.method === 'GET') {
|
||||
delete requestOptions.body;
|
||||
}
|
||||
|
||||
return requestOptions;
|
||||
}
|
||||
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: '={{$credentials.url}}',
|
||||
url: '/groups.json',
|
||||
method: 'GET',
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class DisqusApi implements ICredentialType {
|
||||
name = 'disqusApi';
|
||||
|
||||
displayName = 'Disqus API';
|
||||
|
||||
documentationUrl = 'disqus';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Access Token',
|
||||
name: 'accessToken',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
description:
|
||||
'Visit your account details page, and grab the Access Token. See <a href="https://disqus.com/api/docs/auth/">Disqus auth</a>.',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class DriftApi implements ICredentialType {
|
||||
name = 'driftApi';
|
||||
|
||||
displayName = 'Drift API';
|
||||
|
||||
documentationUrl = 'drift';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Personal Access Token',
|
||||
name: 'accessToken',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
description:
|
||||
'Visit your account details page, and grab the Access Token. See <a href="https://devdocs.drift.com/docs/quick-start">Drift auth</a>.',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class DriftOAuth2Api implements ICredentialType {
|
||||
name = 'driftOAuth2Api';
|
||||
|
||||
extends = ['oAuth2Api'];
|
||||
|
||||
displayName = 'Drift OAuth2 API';
|
||||
|
||||
documentationUrl = 'drift';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Grant Type',
|
||||
name: 'grantType',
|
||||
type: 'hidden',
|
||||
default: 'authorizationCode',
|
||||
},
|
||||
{
|
||||
displayName: 'Authorization URL',
|
||||
name: 'authUrl',
|
||||
type: 'hidden',
|
||||
default: 'https://dev.drift.com/authorize',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Access Token URL',
|
||||
name: 'accessTokenUrl',
|
||||
type: 'hidden',
|
||||
default: 'https://driftapi.com/oauth2/token',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Auth URI Query Parameters',
|
||||
name: 'authQueryParameters',
|
||||
type: 'hidden',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Scope',
|
||||
name: 'scope',
|
||||
type: 'hidden',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Authentication',
|
||||
name: 'authentication',
|
||||
type: 'hidden',
|
||||
default: 'body',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import type {
|
||||
IAuthenticateGeneric,
|
||||
ICredentialTestRequest,
|
||||
ICredentialType,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class DropboxApi implements ICredentialType {
|
||||
name = 'dropboxApi';
|
||||
|
||||
displayName = 'Dropbox API';
|
||||
|
||||
documentationUrl = 'dropbox';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Access Token',
|
||||
name: 'accessToken',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'APP Access Type',
|
||||
name: 'accessType',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'App Folder',
|
||||
value: 'folder',
|
||||
},
|
||||
{
|
||||
name: 'Full Dropbox',
|
||||
value: 'full',
|
||||
},
|
||||
],
|
||||
default: 'full',
|
||||
},
|
||||
];
|
||||
|
||||
authenticate: IAuthenticateGeneric = {
|
||||
type: 'generic',
|
||||
properties: {
|
||||
headers: {
|
||||
Authorization: '=Bearer {{$credentials.accessToken}}',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: 'https://api.dropboxapi.com/2',
|
||||
url: '/users/get_current_account',
|
||||
method: 'POST',
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
const scopes = ['files.content.write', 'files.content.read', 'sharing.read', 'account_info.read'];
|
||||
|
||||
export class DropboxOAuth2Api implements ICredentialType {
|
||||
name = 'dropboxOAuth2Api';
|
||||
|
||||
extends = ['oAuth2Api'];
|
||||
|
||||
displayName = 'Dropbox OAuth2 API';
|
||||
|
||||
documentationUrl = 'dropbox';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Grant Type',
|
||||
name: 'grantType',
|
||||
type: 'hidden',
|
||||
default: 'authorizationCode',
|
||||
},
|
||||
{
|
||||
displayName: 'Authorization URL',
|
||||
name: 'authUrl',
|
||||
type: 'hidden',
|
||||
default: 'https://www.dropbox.com/oauth2/authorize',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Access Token URL',
|
||||
name: 'accessTokenUrl',
|
||||
type: 'hidden',
|
||||
default: 'https://api.dropboxapi.com/oauth2/token',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Scope',
|
||||
name: 'scope',
|
||||
type: 'hidden',
|
||||
default: scopes.join(' '),
|
||||
},
|
||||
{
|
||||
displayName: 'Auth URI Query Parameters',
|
||||
name: 'authQueryParameters',
|
||||
type: 'hidden',
|
||||
default: 'token_access_type=offline&force_reapprove=true',
|
||||
},
|
||||
{
|
||||
displayName: 'Authentication',
|
||||
name: 'authentication',
|
||||
type: 'hidden',
|
||||
default: 'header',
|
||||
},
|
||||
{
|
||||
displayName: 'APP Access Type',
|
||||
name: 'accessType',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'App Folder',
|
||||
value: 'folder',
|
||||
},
|
||||
{
|
||||
name: 'Full Dropbox',
|
||||
value: 'full',
|
||||
},
|
||||
],
|
||||
default: 'full',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import type {
|
||||
IAuthenticateGeneric,
|
||||
ICredentialTestRequest,
|
||||
ICredentialType,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class DropcontactApi implements ICredentialType {
|
||||
name = 'dropcontactApi';
|
||||
|
||||
displayName = 'Dropcontact API';
|
||||
|
||||
documentationUrl = 'dropcontact';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'apiKey',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
|
||||
authenticate: IAuthenticateGeneric = {
|
||||
type: 'generic',
|
||||
properties: {
|
||||
headers: {
|
||||
'user-agent': 'n8n',
|
||||
'X-Access-Token': '={{$credentials.apiKey}}',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: 'https://api.dropcontact.io',
|
||||
url: '/batch',
|
||||
method: 'POST',
|
||||
body: {
|
||||
data: [{ email: '' }],
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import type { IAuthenticateGeneric, ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class DynatraceApi implements ICredentialType {
|
||||
name = 'dynatraceApi';
|
||||
|
||||
displayName = 'DynatraceAPI';
|
||||
|
||||
documentationUrl = 'dynatrace';
|
||||
|
||||
icon = { light: 'file:icons/Dynatrace.svg', dark: 'file:icons/Dynatrace.svg' } as const;
|
||||
|
||||
httpRequestNode = {
|
||||
name: 'Dynatrace',
|
||||
docsUrl: 'https://docs.dynatrace.com/docs/dynatrace-api',
|
||||
apiBaseUrlPlaceholder: 'https://{your-environment-id}.live.dynatrace.com/api/v2/events',
|
||||
};
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'apiKey',
|
||||
required: true,
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
|
||||
authenticate: IAuthenticateGeneric = {
|
||||
type: 'generic',
|
||||
properties: {
|
||||
headers: {
|
||||
Authorization: '=Api-Token {{$credentials.apiKey}}',
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
import type {
|
||||
IAuthenticateGeneric,
|
||||
ICredentialTestRequest,
|
||||
ICredentialType,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class ERPNextApi implements ICredentialType {
|
||||
name = 'erpNextApi';
|
||||
|
||||
displayName = 'ERPNext API';
|
||||
|
||||
documentationUrl = 'erpnext';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'apiKey',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'API Secret',
|
||||
name: 'apiSecret',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Environment',
|
||||
name: 'environment',
|
||||
type: 'options',
|
||||
default: 'cloudHosted',
|
||||
options: [
|
||||
{
|
||||
name: 'Cloud-Hosted',
|
||||
value: 'cloudHosted',
|
||||
},
|
||||
{
|
||||
name: 'Self-Hosted',
|
||||
value: 'selfHosted',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Subdomain',
|
||||
name: 'subdomain',
|
||||
type: 'string',
|
||||
default: '',
|
||||
placeholder: 'n8n',
|
||||
description:
|
||||
'Subdomain of cloud-hosted ERPNext instance. For example, "n8n" is the subdomain in: <code>https://n8n.erpnext.com</code>',
|
||||
displayOptions: {
|
||||
show: {
|
||||
environment: ['cloudHosted'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Domain',
|
||||
name: 'domain',
|
||||
type: 'options',
|
||||
default: 'erpnext.com',
|
||||
options: [
|
||||
{
|
||||
name: 'erpnext.com',
|
||||
value: 'erpnext.com',
|
||||
},
|
||||
{
|
||||
name: 'frappe.cloud',
|
||||
value: 'frappe.cloud',
|
||||
},
|
||||
],
|
||||
description: 'Domain for your cloud hosted ERPNext instance.',
|
||||
displayOptions: {
|
||||
show: {
|
||||
environment: ['cloudHosted'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Domain',
|
||||
name: 'domain',
|
||||
type: 'string',
|
||||
default: '',
|
||||
placeholder: 'https://www.mydomain.com',
|
||||
description: 'Fully qualified domain name of self-hosted ERPNext instance',
|
||||
displayOptions: {
|
||||
show: {
|
||||
environment: ['selfHosted'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Ignore SSL Issues (Insecure)',
|
||||
name: 'allowUnauthorizedCerts',
|
||||
type: 'boolean',
|
||||
description: 'Whether to connect even if SSL certificate validation is not possible',
|
||||
default: false,
|
||||
},
|
||||
];
|
||||
|
||||
authenticate: IAuthenticateGeneric = {
|
||||
type: 'generic',
|
||||
properties: {
|
||||
headers: {
|
||||
Authorization: '=token {{$credentials.apiKey}}:{{$credentials.apiSecret}}',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL:
|
||||
'={{$credentials.environment === "cloudHosted" ? "https://" + $credentials.subdomain + "." + $credentials.domain : $credentials.domain}}',
|
||||
url: '/api/method/frappe.auth.get_logged_user',
|
||||
skipSslCertificateValidation: '={{ $credentials.allowUnauthorizedCerts }}',
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
type: 'responseSuccessBody',
|
||||
properties: {
|
||||
key: 'message',
|
||||
value: undefined,
|
||||
message: 'Unable to authenticate, Check the credentials and the url',
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class EgoiApi implements ICredentialType {
|
||||
name = 'egoiApi';
|
||||
|
||||
displayName = 'E-Goi API';
|
||||
|
||||
documentationUrl = 'egoi';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
// The credentials to get from user and save encrypted.
|
||||
// Properties can be defined exactly in the same way
|
||||
// as node properties.
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'apiKey',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
import type {
|
||||
ICredentialDataDecryptedObject,
|
||||
ICredentialTestRequest,
|
||||
ICredentialType,
|
||||
IHttpRequestOptions,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class ElasticSecurityApi implements ICredentialType {
|
||||
name = 'elasticSecurityApi';
|
||||
|
||||
displayName = 'Elastic Security API';
|
||||
|
||||
documentationUrl = 'elasticsecurity';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Base URL',
|
||||
name: 'baseUrl',
|
||||
type: 'string',
|
||||
default: '',
|
||||
placeholder: 'e.g. https://mydeployment.kb.us-central1.gcp.cloud.es.io:9243',
|
||||
description: "Referred to as Kibana 'endpoint' in the Elastic deployment dashboard",
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Type',
|
||||
name: 'type',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'API Key',
|
||||
value: 'apiKey',
|
||||
},
|
||||
{
|
||||
name: 'Basic Auth',
|
||||
value: 'basicAuth',
|
||||
},
|
||||
],
|
||||
default: 'basicAuth',
|
||||
},
|
||||
{
|
||||
displayName: 'Username',
|
||||
name: 'username',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
type: ['basicAuth'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Password',
|
||||
name: 'password',
|
||||
type: 'string',
|
||||
typeOptions: {
|
||||
password: true,
|
||||
},
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
type: ['basicAuth'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'apiKey',
|
||||
required: true,
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
type: ['apiKey'],
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
async authenticate(
|
||||
credentials: ICredentialDataDecryptedObject,
|
||||
requestOptions: IHttpRequestOptions,
|
||||
): Promise<IHttpRequestOptions> {
|
||||
if (credentials.type === 'apiKey') {
|
||||
requestOptions.headers = {
|
||||
Authorization: `ApiKey ${credentials.apiKey}`,
|
||||
};
|
||||
} else {
|
||||
requestOptions.auth = {
|
||||
username: credentials.username as string,
|
||||
password: credentials.password as string,
|
||||
};
|
||||
requestOptions.headers = {
|
||||
'kbn-xsrf': true,
|
||||
};
|
||||
}
|
||||
return requestOptions;
|
||||
}
|
||||
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: '={{$credentials.baseUrl}}',
|
||||
url: '/api/endpoint/metadata',
|
||||
method: 'GET',
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
import type {
|
||||
IAuthenticateGeneric,
|
||||
ICredentialTestRequest,
|
||||
ICredentialType,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class ElasticsearchApi implements ICredentialType {
|
||||
name = 'elasticsearchApi';
|
||||
|
||||
displayName = 'Elasticsearch API';
|
||||
|
||||
documentationUrl = 'elasticsearch';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Username',
|
||||
name: 'username',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Password',
|
||||
name: 'password',
|
||||
type: 'string',
|
||||
typeOptions: {
|
||||
password: true,
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Base URL',
|
||||
name: 'baseUrl',
|
||||
type: 'string',
|
||||
default: '',
|
||||
placeholder: 'https://mydeployment.es.us-central1.gcp.cloud.es.io:9243',
|
||||
description: "Referred to as Elasticsearch 'endpoint' in the Elastic deployment dashboard",
|
||||
},
|
||||
{
|
||||
displayName: 'Ignore SSL Issues (Insecure)',
|
||||
name: 'ignoreSSLIssues',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
},
|
||||
];
|
||||
|
||||
authenticate: IAuthenticateGeneric = {
|
||||
type: 'generic',
|
||||
properties: {
|
||||
auth: {
|
||||
username: '={{$credentials.username}}',
|
||||
password: '={{$credentials.password}}',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: '={{$credentials.baseUrl}}'.replace(/\/$/, ''),
|
||||
url: '/_xpack?human=false',
|
||||
skipSslCertificateValidation: '={{$credentials.ignoreSSLIssues}}',
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class EmeliaApi implements ICredentialType {
|
||||
name = 'emeliaApi';
|
||||
|
||||
displayName = 'Emelia API';
|
||||
|
||||
documentationUrl = 'emelia';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'apiKey',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class EventbriteApi implements ICredentialType {
|
||||
name = 'eventbriteApi';
|
||||
|
||||
displayName = 'Eventbrite API';
|
||||
|
||||
documentationUrl = 'eventbrite';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Private Key',
|
||||
name: 'apiKey',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class EventbriteOAuth2Api implements ICredentialType {
|
||||
name = 'eventbriteOAuth2Api';
|
||||
|
||||
extends = ['oAuth2Api'];
|
||||
|
||||
displayName = 'Eventbrite OAuth2 API';
|
||||
|
||||
documentationUrl = 'eventbrite';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Grant Type',
|
||||
name: 'grantType',
|
||||
type: 'hidden',
|
||||
default: 'authorizationCode',
|
||||
},
|
||||
{
|
||||
displayName: 'Authorization URL',
|
||||
name: 'authUrl',
|
||||
type: 'hidden',
|
||||
default: 'https://www.eventbrite.com/oauth/authorize',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Access Token URL',
|
||||
name: 'accessTokenUrl',
|
||||
type: 'hidden',
|
||||
default: 'https://www.eventbrite.com/oauth/token',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Scope',
|
||||
name: 'scope',
|
||||
type: 'hidden',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Auth URI Query Parameters',
|
||||
name: 'authQueryParameters',
|
||||
type: 'hidden',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Authentication',
|
||||
name: 'authentication',
|
||||
type: 'hidden',
|
||||
default: 'body',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import type { IAuthenticateGeneric, ICredentialType, INodeProperties, Icon } from 'n8n-workflow';
|
||||
|
||||
export class F5BigIpApi implements ICredentialType {
|
||||
name = 'f5BigIpApi';
|
||||
|
||||
displayName = 'F5 Big-IP API';
|
||||
|
||||
documentationUrl = 'f5bigip';
|
||||
|
||||
icon: Icon = 'file:icons/F5.svg';
|
||||
|
||||
httpRequestNode = {
|
||||
name: 'F5 Big-IP',
|
||||
docsUrl: 'https://clouddocs.f5.com/api/',
|
||||
apiBaseUrl: '',
|
||||
};
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Username',
|
||||
name: 'username',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Password',
|
||||
name: 'password',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
|
||||
authenticate: IAuthenticateGeneric = {
|
||||
type: 'generic',
|
||||
properties: {
|
||||
auth: {
|
||||
username: '={{$credentials.username}}',
|
||||
password: '={{$credentials.password}}',
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import type {
|
||||
IAuthenticateGeneric,
|
||||
ICredentialTestRequest,
|
||||
ICredentialType,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class FacebookGraphApi implements ICredentialType {
|
||||
name = 'facebookGraphApi';
|
||||
|
||||
displayName = 'Facebook Graph API';
|
||||
|
||||
documentationUrl = 'facebookgraph';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Access Token',
|
||||
name: 'accessToken',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
|
||||
authenticate: IAuthenticateGeneric = {
|
||||
type: 'generic',
|
||||
properties: {
|
||||
qs: {
|
||||
access_token: '={{$credentials.accessToken}}',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: 'https://graph.facebook.com/v8.0',
|
||||
url: '/me',
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class FacebookGraphAppApi implements ICredentialType {
|
||||
name = 'facebookGraphAppApi';
|
||||
|
||||
displayName = 'Facebook Graph API (App)';
|
||||
|
||||
documentationUrl = 'facebookapp';
|
||||
|
||||
extends = ['facebookGraphApi'];
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'App Secret',
|
||||
name: 'appSecret',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
description:
|
||||
'(Optional) When the app secret is set the node will verify this signature to validate the integrity and origin of the payload',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class FacebookLeadAdsOAuth2Api implements ICredentialType {
|
||||
name = 'facebookLeadAdsOAuth2Api';
|
||||
|
||||
extends = ['oAuth2Api'];
|
||||
|
||||
displayName = 'Facebook Lead Ads OAuth2 API';
|
||||
|
||||
documentationUrl = 'facebookleadads';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Grant Type',
|
||||
name: 'grantType',
|
||||
type: 'hidden',
|
||||
default: 'authorizationCode',
|
||||
},
|
||||
{
|
||||
displayName: 'Authorization URL',
|
||||
name: 'authUrl',
|
||||
type: 'hidden',
|
||||
default: 'https://www.facebook.com/v17.0/dialog/oauth',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Access Token URL',
|
||||
name: 'accessTokenUrl',
|
||||
type: 'hidden',
|
||||
default: 'https://graph.facebook.com/v17.0/oauth/access_token',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Scope',
|
||||
name: 'scope',
|
||||
type: 'hidden',
|
||||
default:
|
||||
'leads_retrieval pages_show_list pages_manage_metadata pages_manage_ads business_management',
|
||||
},
|
||||
{
|
||||
displayName: 'Auth URI Query Parameters',
|
||||
name: 'authQueryParameters',
|
||||
type: 'hidden',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Authentication',
|
||||
name: 'authentication',
|
||||
type: 'hidden',
|
||||
default: 'header',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class FigmaApi implements ICredentialType {
|
||||
name = 'figmaApi';
|
||||
|
||||
displayName = 'Figma API';
|
||||
|
||||
documentationUrl = 'figma';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Access Token',
|
||||
name: 'accessToken',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export class FileMaker implements ICredentialType {
|
||||
name = 'fileMaker';
|
||||
|
||||
displayName = 'FileMaker API';
|
||||
|
||||
documentationUrl = 'filemaker';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Host',
|
||||
name: 'host',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Database',
|
||||
name: 'db',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Login',
|
||||
name: 'login',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Password',
|
||||
name: 'password',
|
||||
type: 'string',
|
||||
typeOptions: {
|
||||
password: true,
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import type {
|
||||
IAuthenticateGeneric,
|
||||
ICredentialTestRequest,
|
||||
ICredentialType,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class FilescanApi implements ICredentialType {
|
||||
name = 'filescanApi';
|
||||
|
||||
displayName = 'Filescan API';
|
||||
|
||||
documentationUrl = 'filescan';
|
||||
|
||||
icon = { light: 'file:icons/Filescan.svg', dark: 'file:icons/Filescan.svg' } as const;
|
||||
|
||||
httpRequestNode = {
|
||||
name: 'Filescan',
|
||||
docsUrl: 'https://www.filescan.io/api/docs',
|
||||
apiBaseUrlPlaceholder: 'https://www.filescan.io/api/system/do-healthcheck',
|
||||
};
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'apiKey',
|
||||
required: true,
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
|
||||
authenticate: IAuthenticateGeneric = {
|
||||
type: 'generic',
|
||||
properties: {
|
||||
headers: {
|
||||
'X-Api-Key': '={{$credentials.apiKey}}',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: 'https://www.filescan.io/api',
|
||||
url: '/system/do-healthcheck',
|
||||
method: 'GET',
|
||||
},
|
||||
};
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user