fix: 修复TypeScript配置错误并更新项目文档

详细说明:
- 修复了@n8n/config包的TypeScript配置错误
- 移除了不存在的jest-expect-message类型引用
- 清理了所有TypeScript构建缓存
- 更新了可行性分析文档,添加了技术实施方案
- 更新了Agent prompt文档
- 添加了会展策划工作流文档
- 包含了n8n-chinese-translation子项目
- 添加了exhibition-demo展示系统框架
This commit is contained in:
Yep_Q
2025-09-08 10:49:45 +08:00
parent 8cf9d36d81
commit 3db7af209c
426 changed files with 71699 additions and 4401 deletions

View File

@@ -1,137 +0,0 @@
import { NodeTestHarness } from '@nodes-testing/node-test-harness';
import { mock } from 'jest-mock-extended';
import { DateTime } from 'luxon';
import { NodeOperationError, type IExecuteFunctions } from 'n8n-workflow';
import { Wait } from '../Wait.node';
describe('Execute Wait Node', () => {
let timer: NodeJS.Timeout;
const { clearInterval, setInterval } = global;
const nextDay = DateTime.now().startOf('day').plus({ days: 1 });
beforeAll(() => {
timer = setInterval(() => jest.advanceTimersByTime(1000), 10);
jest.useFakeTimers().setSystemTime(new Date('2025-01-01'));
});
afterAll(() => {
clearInterval(timer);
jest.useRealTimers();
});
test.each([
{ value: 'invalid_date', isValid: false },
{
value: nextDay.toISO(),
isValid: true,
expectedWaitTill: nextDay.toJSDate(),
},
{
value: nextDay.toISO({ includeOffset: true }),
isValid: true,
expectedWaitTill: nextDay.toUTC().toJSDate(),
},
{
value: nextDay.toJSDate(),
isValid: true,
expectedWaitTill: nextDay.toJSDate(),
},
{
value: nextDay,
isValid: true,
expectedWaitTill: nextDay.toJSDate(),
},
])(
'Test Wait Node with specificTime $value and isValid $isValid',
async ({ value, isValid, expectedWaitTill }) => {
const putExecutionToWaitSpy = jest.fn();
const waitNode = new Wait();
const executeFunctionsMock = mock<IExecuteFunctions>({
getNodeParameter: jest.fn().mockImplementation((paramName: string) => {
if (paramName === 'resume') return 'specificTime';
if (paramName === 'dateTime') return value;
}),
getTimezone: jest.fn().mockReturnValue('UTC'),
putExecutionToWait: putExecutionToWaitSpy,
getInputData: jest.fn(),
getNode: jest.fn(),
});
if (isValid) {
await expect(waitNode.execute(executeFunctionsMock)).resolves.not.toThrow();
expect(putExecutionToWaitSpy).toHaveBeenCalledWith(expectedWaitTill);
} else {
await expect(waitNode.execute(executeFunctionsMock)).rejects.toThrow(NodeOperationError);
}
},
);
describe('Validation', () => {
describe('Time interval', () => {
it.each([
{
unit: 'seconds',
amount: 300,
expectedWaitTill: () => DateTime.now().plus({ seconds: 300 }).toJSDate(),
},
{
unit: 'minutes',
amount: 2,
expectedWaitTill: () => DateTime.now().plus({ minutes: 2 }).toJSDate(),
},
{
unit: 'hours',
amount: 1,
expectedWaitTill: () => DateTime.now().plus({ hours: 1 }).toJSDate(),
},
{
unit: 'days',
amount: 10,
expectedWaitTill: () => DateTime.now().plus({ days: 10 }).toJSDate(),
},
{
unit: 'seconds',
amount: -10,
error: 'Invalid wait amount. It must be a positive number.',
},
{
unit: 'years',
amount: 10,
error: "Invalid wait unit. Valid units are 'seconds', 'minutes', 'hours', or 'days'.",
},
{
unit: 'minutes',
amount: 'test',
error: 'Invalid wait amount. It must be a positive number.',
},
])(
'Validate wait unit: $unit, amount: $amount',
async ({ unit, amount, expectedWaitTill, error }) => {
const putExecutionToWaitSpy = jest.fn();
const waitNode = new Wait();
const executeFunctionsMock = mock<IExecuteFunctions>({
getNodeParameter: jest.fn().mockImplementation((paramName: string) => {
if (paramName === 'resume') return 'timeInterval';
if (paramName === 'amount') return amount;
if (paramName === 'unit') return unit;
}),
getTimezone: jest.fn().mockReturnValue('UTC'),
putExecutionToWait: putExecutionToWaitSpy,
getInputData: jest.fn(),
getNode: jest.fn(),
});
if (!error) {
await expect(waitNode.execute(executeFunctionsMock)).resolves.not.toThrow();
expect(putExecutionToWaitSpy).toHaveBeenCalledWith(expectedWaitTill?.());
} else {
await expect(waitNode.execute(executeFunctionsMock)).rejects.toThrowError(error);
}
},
);
});
});
new NodeTestHarness().setupTests();
});

View File

@@ -1,162 +0,0 @@
{
"name": "[Unit Test] Wait Node",
"nodes": [
{
"parameters": {},
"id": "76e5dcfd-fdc7-472f-8832-bccc0eb122c0",
"name": "When clicking \"Execute Workflow\"",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [120, 420]
},
{
"parameters": {
"amount": 42,
"unit": "seconds"
},
"id": "37f2c758-6fb2-43ce-86ae-ca11ec957cbd",
"name": "Wait",
"type": "n8n-nodes-base.wait",
"typeVersion": 1,
"position": [560, 420],
"webhookId": "35edc971-c3e4-48cf-835d-4d73a4fd1fd8"
},
{
"parameters": {
"conditions": {
"number": [
{
"value1": "={{ parseInt($json.afterTimestamp) }}",
"operation": "largerEqual",
"value2": "={{ parseInt($json.startTimestamp) + 42 }}"
}
]
}
},
"id": "c5c53934-2677-4adf-a4df-b32f3b0642a2",
"name": "IF",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [960, 420]
},
{
"parameters": {
"keepOnlySet": true,
"values": {
"boolean": [
{
"name": "success",
"value": true
}
]
},
"options": {}
},
"id": "a78417b6-d3f5-4bbc-916a-d4b9d46961cc",
"name": "Set1",
"type": "n8n-nodes-base.set",
"typeVersion": 1,
"position": [1180, 400]
},
{
"parameters": {
"value": "={{ $now }}",
"dataPropertyName": "afterTimestamp",
"toFormat": "X",
"options": {}
},
"id": "94f042ea-49d5-44ea-9ccf-93dac8d27d4a",
"name": "After",
"type": "n8n-nodes-base.dateTime",
"typeVersion": 1,
"position": [760, 420]
},
{
"parameters": {
"value": "={{ $now }}",
"dataPropertyName": "startTimestamp",
"toFormat": "X",
"options": {}
},
"id": "43f8a396-1bf7-484e-962c-120f677dfa51",
"name": "Before",
"type": "n8n-nodes-base.dateTime",
"typeVersion": 1,
"position": [360, 420]
}
],
"pinData": {
"Set1": [
{
"json": {
"success": true
}
}
]
},
"connections": {
"When clicking \"Execute Workflow\"": {
"main": [
[
{
"node": "Before",
"type": "main",
"index": 0
}
]
]
},
"Wait": {
"main": [
[
{
"node": "After",
"type": "main",
"index": 0
}
]
]
},
"IF": {
"main": [
[
{
"node": "Set1",
"type": "main",
"index": 0
}
]
]
},
"After": {
"main": [
[
{
"node": "IF",
"type": "main",
"index": 0
}
]
]
},
"Before": {
"main": [
[
{
"node": "Wait",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {},
"versionId": "8ed794a0-5c04-4b8a-9a49-02c2c7f8003f",
"id": "500",
"meta": {
"instanceId": "8c8c5237b8e37b006a7adce87f4369350c58e41f3ca9de16196d3197f69eabcd"
},
"tags": []
}

View File

@@ -1,60 +0,0 @@
{
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "test",
"options": {
"binaryData": false
}
},
"id": "ec188f16-b2c5-44e3-bd83-259a94f15c94",
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 1,
"webhookId": "a59a3be7-6d43-47e7-951d-86b8172c2006"
}
],
"connections": {
"Webhook": {
"main": [[]]
}
},
"trigger": {
"mode": "webhook",
"input": {
"json": {
"headers": {
"host": "localhost:5678",
"user-agent": "curl/8.2.0",
"accept": "*/*",
"content-length": "137",
"content-type": "multipart/form-data; boundary=--boundary"
},
"params": { "path": "test" },
"query": {},
"body": { "a": ["b"] }
}
}
},
"pinData": {
"Webhook": [
{
"json": {
"headers": {
"host": "localhost:5678",
"user-agent": "curl/8.2.0",
"accept": "*/*",
"content-length": "137",
"content-type": "multipart/form-data; boundary=--boundary"
},
"params": { "path": "test" },
"query": {},
"body": {
"a": ["b"]
}
}
}
]
}
}

View File

@@ -1,137 +0,0 @@
import { NodeTestHarness } from '@nodes-testing/node-test-harness';
import type { Request, Response } from 'express';
import fs from 'fs/promises';
import { mock } from 'jest-mock-extended';
import type { IWebhookFunctions } from 'n8n-workflow';
import { Webhook } from '../Webhook.node';
jest.mock('fs/promises');
const mockFs = jest.mocked(fs);
describe('Test Webhook Node', () => {
new NodeTestHarness().setupTests();
describe('handleFormData', () => {
const node = new Webhook();
const context = mock<IWebhookFunctions>({
nodeHelpers: mock(),
});
context.getNodeParameter.calledWith('options').mockReturnValue({});
context.getNode.calledWith().mockReturnValue({
type: 'n8n-nodes-base.webhook',
typeVersion: 1.1,
} as any);
const req = mock<Request>();
req.contentType = 'multipart/form-data';
context.getRequestObject.mockReturnValue(req);
it('should handle when no files are present', async () => {
req.body = {
files: {},
};
const returnData = await node.webhook(context);
expect(returnData.workflowData?.[0][0].binary).toBeUndefined();
expect(context.nodeHelpers.copyBinaryFile).not.toHaveBeenCalled();
});
it('should handle when files are present', async () => {
req.body = {
files: { file1: { filepath: '/tmp/test.txt' } },
};
const returnData = await node.webhook(context);
expect(returnData.workflowData?.[0][0].binary).not.toBeUndefined();
expect(context.nodeHelpers.copyBinaryFile).toHaveBeenCalled();
expect(mockFs.rm).toHaveBeenCalledWith('/tmp/test.txt', { force: true });
});
});
describe('streaming response mode', () => {
const node = new Webhook();
const context = mock<IWebhookFunctions>({
nodeHelpers: mock(),
});
const req = mock<Request>();
const res = mock<Response>();
beforeEach(() => {
jest.clearAllMocks();
context.getRequestObject.mockReturnValue(req);
context.getResponseObject.mockReturnValue(res);
context.getChildNodes.mockReturnValue([]);
context.getNode.mockReturnValue({
type: 'n8n-nodes-base.webhook',
typeVersion: 2,
name: 'Webhook',
} as any);
context.getNodeParameter.mockImplementation((paramName: string) => {
if (paramName === 'options') return {};
if (paramName === 'responseMode') return 'streaming';
return undefined;
});
req.headers = {};
req.params = {};
req.query = {};
req.body = { message: 'test' };
Object.defineProperty(req, 'ips', { value: [], configurable: true });
Object.defineProperty(req, 'ip', { value: '127.0.0.1', configurable: true });
res.writeHead.mockImplementation(() => res);
res.flushHeaders.mockImplementation(() => undefined);
});
it('should enable streaming when responseMode is "streaming"', async () => {
const result = await node.webhook(context);
// Verify streaming headers are set
expect(res.writeHead).toHaveBeenCalledWith(200, {
'Content-Type': 'application/json; charset=utf-8',
'Transfer-Encoding': 'chunked',
'Cache-Control': 'no-cache',
Connection: 'keep-alive',
});
expect(res.flushHeaders).toHaveBeenCalled();
// Verify response structure for streaming
expect(result).toEqual({
noWebhookResponse: true,
workflowData: expect.any(Array),
});
});
it('should not enable streaming when responseMode is not "streaming"', async () => {
context.getNodeParameter.mockImplementation((paramName: string) => {
if (paramName === 'options') return {};
if (paramName === 'responseMode') return 'onReceived';
return undefined;
});
const result = await node.webhook(context);
// Verify streaming headers are NOT set
expect(res.writeHead).not.toHaveBeenCalled();
expect(res.flushHeaders).not.toHaveBeenCalled();
// Verify normal response structure
expect(result).toEqual({
webhookResponse: undefined,
workflowData: expect.any(Array),
});
});
it('should handle multipart form data with streaming enabled', async () => {
req.contentType = 'multipart/form-data';
req.body = {
data: { message: 'Hello' },
files: {},
};
const result = await node.webhook(context);
// For multipart form data, streaming is handled in handleFormData method
// The current implementation returns normal workflowData for form data
expect(result).toEqual({
workflowData: expect.any(Array),
});
});
});
});

View File

@@ -1,474 +0,0 @@
import jwt from 'jsonwebtoken';
import { ApplicationError, type IWebhookFunctions } from 'n8n-workflow';
import type { WebhookParameters } from '../utils';
import {
checkResponseModeConfiguration,
configuredOutputs,
getResponseCode,
getResponseData,
isIpWhitelisted,
setupOutputConnection,
validateWebhookAuthentication,
} from '../utils';
jest.mock('jsonwebtoken', () => ({
verify: jest.fn(),
}));
describe('Webhook Utils', () => {
describe('getResponseCode', () => {
it('should return the response code if it exists', () => {
const parameters: WebhookParameters = {
responseCode: 404,
httpMethod: '',
responseMode: '',
responseData: '',
};
const responseCode = getResponseCode(parameters);
expect(responseCode).toBe(404);
});
it('should return the custom response code if it exists', () => {
const parameters: WebhookParameters = {
options: {
responseCode: {
values: {
responseCode: 200,
customCode: 201,
},
},
},
httpMethod: '',
responseMode: '',
responseData: '',
};
const responseCode = getResponseCode(parameters);
expect(responseCode).toBe(201);
});
it('should return the default response code if no response code is provided', () => {
const parameters: WebhookParameters = {
httpMethod: '',
responseMode: '',
responseData: '',
};
const responseCode = getResponseCode(parameters);
expect(responseCode).toBe(200);
});
});
describe('getResponseData', () => {
it('should return the response data if it exists', () => {
const parameters: WebhookParameters = {
responseData: 'Hello World',
httpMethod: '',
responseMode: '',
};
const responseData = getResponseData(parameters);
expect(responseData).toBe('Hello World');
});
it('should return the options response data if response mode is "onReceived"', () => {
const parameters: WebhookParameters = {
responseMode: 'onReceived',
options: {
responseData: 'Hello World',
},
httpMethod: '',
responseData: '',
};
const responseData = getResponseData(parameters);
expect(responseData).toBe('Hello World');
});
it('should return "noData" if options noResponseBody is true', () => {
const parameters: WebhookParameters = {
responseMode: 'onReceived',
options: {
noResponseBody: true,
},
httpMethod: '',
responseData: '',
};
const responseData = getResponseData(parameters);
expect(responseData).toBe('noData');
});
it('should return undefined if no response data is provided', () => {
const parameters: WebhookParameters = {
responseMode: 'onReceived',
httpMethod: '',
responseData: '',
};
const responseData = getResponseData(parameters);
expect(responseData).toBeUndefined();
});
});
describe('configuredOutputs', () => {
it('should return an array with a single output if httpMethod is not an array', () => {
const parameters: WebhookParameters = {
httpMethod: 'GET',
responseMode: '',
responseData: '',
};
const outputs = configuredOutputs(parameters);
expect(outputs).toEqual([
{
type: 'main',
displayName: 'GET',
},
]);
});
it('should return an array of outputs if httpMethod is an array', () => {
const parameters: WebhookParameters = {
httpMethod: ['GET', 'POST'],
responseMode: '',
responseData: '',
};
const outputs = configuredOutputs(parameters);
expect(outputs).toEqual([
{
type: 'main',
displayName: 'GET',
},
{
type: 'main',
displayName: 'POST',
},
]);
});
});
describe('setupOutputConnection', () => {
it('should return a function that sets the webhookUrl and executionMode in the output data', () => {
const ctx: Partial<IWebhookFunctions> = {
getNodeParameter: jest.fn().mockReturnValue('GET'),
getNodeWebhookUrl: jest.fn().mockReturnValue('https://example.com/webhook/'),
getMode: jest.fn().mockReturnValue('manual'),
};
const method = 'GET';
const additionalData = {
jwtPayload: {
userId: '123',
},
};
const outputData = {
json: {},
};
const setupOutput = setupOutputConnection(ctx as IWebhookFunctions, method, additionalData);
const result = setupOutput(outputData);
expect(result).toEqual([
[
{
json: {
webhookUrl: 'https://example.com/webhook-test/',
executionMode: 'test',
jwtPayload: { userId: '123' },
},
},
],
]);
});
it('should return a function that sets the webhookUrl and executionMode in the output data for multiple methods', () => {
const ctx: Partial<IWebhookFunctions> = {
getNodeParameter: jest.fn().mockReturnValue(['GET', 'POST']),
getNodeWebhookUrl: jest.fn().mockReturnValue('https://example.com/webhook/'),
getMode: jest.fn().mockReturnValue('manual'),
};
const method = 'POST';
const additionalData = {
jwtPayload: {
userId: '123',
},
};
const outputData = {
json: {},
};
const setupOutput = setupOutputConnection(ctx as IWebhookFunctions, method, additionalData);
const result = setupOutput(outputData);
expect(result).toEqual([
[],
[
{
json: {
webhookUrl: 'https://example.com/webhook-test/',
executionMode: 'test',
jwtPayload: { userId: '123' },
},
},
],
]);
});
});
describe('isIpWhitelisted', () => {
it('should return true if whitelist is undefined', () => {
expect(isIpWhitelisted(undefined, ['192.168.1.1'], '192.168.1.1')).toBe(true);
});
it('should return true if whitelist is an empty string', () => {
expect(isIpWhitelisted('', ['192.168.1.1'], '192.168.1.1')).toBe(true);
});
it('should return true if ip is in the whitelist', () => {
expect(isIpWhitelisted('192.168.1.1', ['192.168.1.2'], '192.168.1.1')).toBe(true);
});
it('should return true if any ip in ips is in the whitelist', () => {
expect(isIpWhitelisted('192.168.1.1', ['192.168.1.1', '192.168.1.2'])).toBe(true);
});
it('should return false if ip and ips are not in the whitelist', () => {
expect(isIpWhitelisted('192.168.1.3', ['192.168.1.1', '192.168.1.2'], '192.168.1.4')).toBe(
false,
);
});
it('should return true if any ip in ips matches any address in the whitelist array', () => {
expect(isIpWhitelisted(['192.168.1.1', '192.168.1.2'], ['192.168.1.2', '192.168.1.3'])).toBe(
true,
);
});
it('should return true if ip matches any address in the whitelist array', () => {
expect(isIpWhitelisted(['192.168.1.1', '192.168.1.2'], ['192.168.1.3'], '192.168.1.2')).toBe(
true,
);
});
it('should return false if ip and ips do not match any address in the whitelist array', () => {
expect(
isIpWhitelisted(
['192.168.1.4', '192.168.1.5'],
['192.168.1.1', '192.168.1.2'],
'192.168.1.3',
),
).toBe(false);
});
it('should handle comma-separated whitelist string', () => {
expect(isIpWhitelisted('192.168.1.1, 192.168.1.2', ['192.168.1.3'], '192.168.1.2')).toBe(
true,
);
});
it('should trim whitespace in comma-separated whitelist string', () => {
expect(isIpWhitelisted(' 192.168.1.1 , 192.168.1.2 ', ['192.168.1.3'], '192.168.1.2')).toBe(
true,
);
});
});
describe('checkResponseModeConfiguration', () => {
it('should throw an error if response mode is "responseNode" but no Respond to Webhook node is found', () => {
const context: Partial<IWebhookFunctions> = {
getNodeParameter: jest.fn().mockReturnValue('responseNode'),
getChildNodes: jest.fn().mockReturnValue([]),
getNode: jest.fn().mockReturnValue({ name: 'Webhook' }),
};
expect(() => {
checkResponseModeConfiguration(context as IWebhookFunctions);
}).toThrowError('No Respond to Webhook node found in the workflow');
});
it('should throw an error if response mode is not "responseNode" but a Respond to Webhook node is found', () => {
const context: Partial<IWebhookFunctions> = {
getNodeParameter: jest.fn().mockReturnValue('onReceived'),
getChildNodes: jest.fn().mockReturnValue([{ type: 'n8n-nodes-base.respondToWebhook' }]),
getNode: jest.fn().mockReturnValue({ name: 'Webhook' }),
};
expect(() => {
checkResponseModeConfiguration(context as IWebhookFunctions);
}).toThrowError('Webhook node not correctly configured');
});
});
describe('validateWebhookAuthentication', () => {
it('should return early if authentication is "none"', async () => {
const ctx: Partial<IWebhookFunctions> = {
getNodeParameter: jest.fn().mockReturnValue('none'),
};
const authPropertyName = 'authentication';
const result = await validateWebhookAuthentication(
ctx as IWebhookFunctions,
authPropertyName,
);
expect(result).toBeUndefined();
});
it('should throw an error if basicAuth is enabled but no authentication data is defined on the node', async () => {
const headers = {
authorization: 'Basic some-token',
};
const ctx: Partial<IWebhookFunctions> = {
getNodeParameter: jest.fn().mockReturnValue('basicAuth'),
getCredentials: jest.fn().mockRejectedValue(new Error()),
getRequestObject: jest.fn().mockReturnValue({
headers,
}),
getHeaderData: jest.fn().mockReturnValue(headers),
};
const authPropertyName = 'authentication';
await expect(
validateWebhookAuthentication(ctx as IWebhookFunctions, authPropertyName),
).rejects.toThrowError('No authentication data defined on node!');
});
it('should throw an error if basicAuth is enabled but the provided authentication data is wrong', async () => {
const headers = {
authorization: 'Basic some-token',
};
const ctx: Partial<IWebhookFunctions> = {
getNodeParameter: jest.fn().mockReturnValue('basicAuth'),
getCredentials: jest.fn().mockResolvedValue({
user: 'admin',
password: 'password',
}),
getRequestObject: jest.fn().mockReturnValue({
headers,
}),
getHeaderData: jest.fn().mockReturnValue(headers),
};
const authPropertyName = 'authentication';
await expect(
validateWebhookAuthentication(ctx as IWebhookFunctions, authPropertyName),
).rejects.toThrowError('Authorization is required!');
});
it('should throw an error if headerAuth is enabled but no authentication data is defined on the node', async () => {
const ctx: Partial<IWebhookFunctions> = {
getNodeParameter: jest.fn().mockReturnValue('headerAuth'),
getCredentials: jest
.fn()
.mockRejectedValue(new Error('No authentication data defined on node!')),
getRequestObject: jest.fn().mockReturnValue({
headers: {},
}),
getHeaderData: jest.fn().mockReturnValue({}),
};
const authPropertyName = 'authentication';
await expect(
validateWebhookAuthentication(ctx as IWebhookFunctions, authPropertyName),
).rejects.toThrowError('No authentication data defined on node!');
});
it('should throw an error if headerAuth is enabled but the provided authentication data is wrong', async () => {
const headers = {
authorization: 'Bearer invalid-token',
};
const ctx: Partial<IWebhookFunctions> = {
getNodeParameter: jest.fn().mockReturnValue('headerAuth'),
getCredentials: jest.fn().mockResolvedValue({
name: 'Authorization',
value: 'Bearer token',
}),
getRequestObject: jest.fn().mockReturnValue({
headers,
}),
getHeaderData: jest.fn().mockReturnValue(headers),
};
const authPropertyName = 'authentication';
await expect(
validateWebhookAuthentication(ctx as IWebhookFunctions, authPropertyName),
).rejects.toThrowError('Authorization data is wrong!');
});
it('should throw an error if jwtAuth is enabled but no authentication data is defined on the node', async () => {
const ctx: Partial<IWebhookFunctions> = {
getNodeParameter: jest.fn().mockReturnValue('jwtAuth'),
getCredentials: jest
.fn()
.mockRejectedValue(new Error('No authentication data defined on node!')),
getRequestObject: jest.fn().mockReturnValue({}),
getHeaderData: jest.fn().mockReturnValue({}),
};
const authPropertyName = 'authentication';
await expect(
validateWebhookAuthentication(ctx as IWebhookFunctions, authPropertyName),
).rejects.toThrowError('No authentication data defined on node!');
});
it('should throw an error if jwtAuth is enabled but no token is provided', async () => {
const ctx: Partial<IWebhookFunctions> = {
getNodeParameter: jest.fn().mockReturnValue('jwtAuth'),
getCredentials: jest.fn().mockResolvedValue({
keyType: 'passphrase',
publicKey: '',
secret: 'secret',
algorithm: 'HS256',
}),
getRequestObject: jest.fn().mockReturnValue({
headers: {},
}),
getHeaderData: jest.fn().mockReturnValue({}),
};
const authPropertyName = 'authentication';
await expect(
validateWebhookAuthentication(ctx as IWebhookFunctions, authPropertyName),
).rejects.toThrowError('No token provided');
});
it('should throw an error if jwtAuth is enabled but the provided token is invalid', async () => {
const headers = {
authorization: 'Bearer invalid-token',
};
const ctx: Partial<IWebhookFunctions> = {
getNodeParameter: jest.fn().mockReturnValue('jwtAuth'),
getCredentials: jest.fn().mockResolvedValue({
keyType: 'passphrase',
publicKey: '',
secret: 'secret',
algorithm: 'HS256',
}),
getRequestObject: jest.fn().mockReturnValue({
headers,
}),
getHeaderData: jest.fn().mockReturnValue(headers),
};
(jwt.verify as jest.Mock).mockImplementationOnce(() => {
throw new ApplicationError('jwt malformed');
});
const authPropertyName = 'authentication';
await expect(
validateWebhookAuthentication(ctx as IWebhookFunctions, authPropertyName),
).rejects.toThrowError('jwt malformed');
});
it('should return the decoded JWT payload if jwtAuth is enabled and the token is valid', async () => {
const decodedPayload = {
sub: '1234567890',
name: 'John Doe',
iat: 1516239022,
};
(jwt.verify as jest.Mock).mockReturnValue(decodedPayload);
const headers = {
authorization:
'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c',
};
const ctx: Partial<IWebhookFunctions> = {
getNodeParameter: jest.fn().mockReturnValue('jwtAuth'),
getCredentials: jest.fn().mockResolvedValue({
keyType: 'passphrase',
publicKey: '',
secret: 'secret',
algorithm: 'HS256',
}),
getRequestObject: jest.fn().mockReturnValue({
headers,
}),
getHeaderData: jest.fn().mockReturnValue(headers),
};
const authPropertyName = 'authentication';
const result = await validateWebhookAuthentication(
ctx as IWebhookFunctions,
authPropertyName,
);
expect(result).toEqual(decodedPayload);
});
});
});

View File

@@ -1,60 +0,0 @@
{
"type": "object",
"properties": {
"active": {
"type": "boolean"
},
"balances": {
"type": "array",
"items": {
"type": "object",
"properties": {
"amount": {
"type": "object",
"properties": {
"currency": {
"type": "string"
}
}
},
"balanceType": {
"type": "string"
},
"currency": {
"type": "string"
},
"id": {
"type": "integer"
},
"reservedAmount": {
"type": "object",
"properties": {
"currency": {
"type": "string"
}
}
}
}
}
},
"creationTime": {
"type": "string"
},
"eligible": {
"type": "boolean"
},
"id": {
"type": "integer"
},
"modificationTime": {
"type": "string"
},
"profileId": {
"type": "integer"
},
"recipientId": {
"type": "integer"
}
},
"version": 1
}

View File

@@ -1,18 +0,0 @@
{
"type": "object",
"properties": {
"rate": {
"type": "number"
},
"source": {
"type": "string"
},
"target": {
"type": "string"
},
"time": {
"type": "string"
}
},
"version": 2
}

View File

@@ -1,225 +0,0 @@
import type { INodeProperties } from 'n8n-workflow';
import { customerCreateFields, customerUpdateFields } from './shared';
export const customerOperations: INodeProperties[] = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
displayOptions: {
show: {
resource: ['customer'],
},
},
options: [
{
name: 'Create',
value: 'create',
description: 'Create a customer',
action: 'Create a customer',
},
{
name: 'Delete',
value: 'delete',
description: 'Delete a customer',
action: 'Delete a customer',
},
{
name: 'Get',
value: 'get',
description: 'Retrieve a customer',
action: 'Get a customer',
},
{
name: 'Get Many',
value: 'getAll',
description: 'Retrieve many customers',
action: 'Get many customers',
},
{
name: 'Update',
value: 'update',
description: 'Update a customer',
action: 'Update a customer',
},
],
default: 'create',
},
];
export const customerFields: INodeProperties[] = [
// ----------------------------------------
// customer: create
// ----------------------------------------
{
displayName: 'Email',
name: 'email',
type: 'string',
placeholder: 'name@email.com',
required: true,
default: '',
displayOptions: {
show: {
resource: ['customer'],
operation: ['create'],
},
},
},
customerCreateFields,
// ----------------------------------------
// customer: delete
// ----------------------------------------
{
displayName: 'Customer ID',
name: 'customerId',
description: 'ID of the customer to delete',
type: 'string',
required: true,
default: '',
displayOptions: {
show: {
resource: ['customer'],
operation: ['delete'],
},
},
},
// ----------------------------------------
// customer: get
// ----------------------------------------
{
displayName: 'Customer ID',
name: 'customerId',
description: 'ID of the customer to retrieve',
type: 'string',
required: true,
default: '',
displayOptions: {
show: {
resource: ['customer'],
operation: ['get'],
},
},
},
// ----------------------------------------
// customer: getAll
// ----------------------------------------
{
displayName: 'Return All',
name: 'returnAll',
type: 'boolean',
default: false,
description: 'Whether to return all results or only up to a given limit',
displayOptions: {
show: {
resource: ['customer'],
operation: ['getAll'],
},
},
},
{
displayName: 'Limit',
name: 'limit',
type: 'number',
default: 50,
description: 'Max number of results to return',
typeOptions: {
minValue: 1,
},
displayOptions: {
show: {
resource: ['customer'],
operation: ['getAll'],
returnAll: [false],
},
},
},
{
displayName: 'Filters',
name: 'filters',
type: 'collection',
placeholder: 'Add Filter',
default: {},
displayOptions: {
show: {
resource: ['customer'],
operation: ['getAll'],
},
},
options: [
{
displayName: 'Email',
name: 'email',
type: 'string',
placeholder: 'name@email.com',
default: '',
description: 'Email address to filter customers by',
},
{
displayName: 'Sort Order',
name: 'order',
description: 'Order to sort customers in',
type: 'options',
options: [
{
name: 'Ascending',
value: 'asc',
},
{
name: 'Descending',
value: 'desc',
},
],
default: 'asc',
},
{
displayName: 'Order By',
name: 'orderby',
description: 'Field to sort customers by',
type: 'options',
options: [
{
name: 'ID',
value: 'id',
},
{
name: 'Include',
value: 'include',
},
{
name: 'Name',
value: 'name',
},
{
name: 'Registered Date',
value: 'registered_date',
},
],
default: 'id',
},
],
},
// ----------------------------------------
// customer: update
// ----------------------------------------
{
displayName: 'Customer ID',
name: 'customerId',
description: 'ID of the customer to update',
type: 'string',
required: true,
default: '',
displayOptions: {
show: {
resource: ['customer'],
operation: ['update'],
},
},
},
customerUpdateFields,
];

View File

@@ -1 +0,0 @@
export * from './CustomerDescription';

View File

@@ -1,185 +0,0 @@
import type { INodeProperties } from 'n8n-workflow';
const customerAddressOptions: INodeProperties[] = [
{
displayName: 'First Name',
name: 'first_name',
type: 'string',
default: '',
},
{
displayName: 'Last Name',
name: 'last_name',
type: 'string',
default: '',
},
{
displayName: 'Company',
name: 'company',
type: 'string',
default: '',
},
{
displayName: 'Address 1',
name: 'address_1',
type: 'string',
default: '',
},
{
displayName: 'Address 2',
name: 'address_2',
type: 'string',
default: '',
},
{
displayName: 'City',
name: 'city',
type: 'string',
default: '',
},
{
displayName: 'State',
name: 'state',
type: 'string',
default: '',
},
{
displayName: 'Postcode',
name: 'postcode',
type: 'string',
default: '',
},
{
displayName: 'Country',
name: 'country',
type: 'string',
default: '',
},
{
displayName: 'Email',
name: 'email',
type: 'string',
placeholder: 'name@email.com',
default: '',
},
{
displayName: 'Phone',
name: 'phone',
type: 'string',
default: '',
},
];
const customerUpdateOptions: INodeProperties[] = [
{
displayName: 'Billing Address',
name: 'billing',
type: 'collection',
default: {},
placeholder: 'Add Field',
options: customerAddressOptions,
},
{
displayName: 'First Name',
name: 'first_name',
type: 'string',
default: '',
},
{
displayName: 'Last Name',
name: 'last_name',
type: 'string',
default: '',
},
{
displayName: 'Metadata',
name: 'meta_data',
type: 'fixedCollection',
typeOptions: {
multipleValues: true,
},
default: {},
placeholder: 'Add Metadata Field',
options: [
{
displayName: 'Metadata Fields',
name: 'meta_data_fields',
values: [
{
displayName: 'Key',
name: 'key',
type: 'string',
default: '',
},
{
displayName: 'Value',
name: 'value',
type: 'string',
default: '',
},
],
},
],
},
{
displayName: 'Password',
name: 'password',
type: 'string',
typeOptions: { password: true },
displayOptions: {
show: {
'/resource': ['customer'],
'/operation': ['create'],
},
},
default: '',
},
{
displayName: 'Shipping Address',
name: 'shipping',
type: 'collection',
default: {},
placeholder: 'Add Field',
options: customerAddressOptions,
},
];
const customerCreateOptions: INodeProperties[] = [
...customerUpdateOptions,
{
displayName: 'Username',
name: 'username',
type: 'string',
default: '',
},
];
export const customerCreateFields: INodeProperties = {
displayName: 'Additional Fields',
name: 'additionalFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
resource: ['customer'],
operation: ['create'],
},
},
options: customerCreateOptions,
};
export const customerUpdateFields: INodeProperties = {
displayName: 'Update Fields',
name: 'updateFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
resource: ['customer'],
operation: ['update'],
},
},
options: customerUpdateOptions,
};

View File

@@ -1,76 +0,0 @@
{
"type": "object",
"properties": {
"Addresses": {
"type": "array",
"items": {
"type": "object",
"properties": {
"AddressType": {
"type": "string"
},
"City": {
"type": "string"
},
"Country": {
"type": "string"
},
"PostalCode": {
"type": "string"
},
"Region": {
"type": "string"
}
}
}
},
"BankAccountDetails": {
"type": "string"
},
"ContactID": {
"type": "string"
},
"ContactStatus": {
"type": "string"
},
"EmailAddress": {
"type": "string"
},
"HasValidationErrors": {
"type": "boolean"
},
"IsCustomer": {
"type": "boolean"
},
"IsSupplier": {
"type": "boolean"
},
"Name": {
"type": "string"
},
"Phones": {
"type": "array",
"items": {
"type": "object",
"properties": {
"PhoneAreaCode": {
"type": "string"
},
"PhoneCountryCode": {
"type": "string"
},
"PhoneNumber": {
"type": "string"
},
"PhoneType": {
"type": "string"
}
}
}
},
"UpdatedDateUTC": {
"type": "string"
}
},
"version": 1
}

View File

@@ -1,122 +0,0 @@
{
"type": "object",
"properties": {
"Addresses": {
"type": "array",
"items": {
"type": "object",
"properties": {
"AddressLine1": {
"type": "string"
},
"AddressType": {
"type": "string"
},
"City": {
"type": "string"
},
"Country": {
"type": "string"
},
"PostalCode": {
"type": "string"
},
"Region": {
"type": "string"
}
}
}
},
"BankAccountDetails": {
"type": "string"
},
"ContactGroups": {
"type": "array",
"items": {
"type": "object",
"properties": {
"ContactGroupID": {
"type": "string"
},
"HasValidationErrors": {
"type": "boolean"
},
"Name": {
"type": "string"
},
"Status": {
"type": "string"
}
}
}
},
"ContactID": {
"type": "string"
},
"ContactPersons": {
"type": "array",
"items": {
"type": "object",
"properties": {
"EmailAddress": {
"type": "string"
},
"FirstName": {
"type": "string"
},
"IncludeInEmails": {
"type": "boolean"
},
"LastName": {
"type": "string"
}
}
}
},
"ContactStatus": {
"type": "string"
},
"EmailAddress": {
"type": "string"
},
"HasAttachments": {
"type": "boolean"
},
"HasValidationErrors": {
"type": "boolean"
},
"IsCustomer": {
"type": "boolean"
},
"IsSupplier": {
"type": "boolean"
},
"Name": {
"type": "string"
},
"Phones": {
"type": "array",
"items": {
"type": "object",
"properties": {
"PhoneAreaCode": {
"type": "string"
},
"PhoneCountryCode": {
"type": "string"
},
"PhoneNumber": {
"type": "string"
},
"PhoneType": {
"type": "string"
}
}
}
},
"UpdatedDateUTC": {
"type": "string"
}
},
"version": 1
}

View File

@@ -1,79 +0,0 @@
{
"type": "object",
"properties": {
"Addresses": {
"type": "array",
"items": {
"type": "object",
"properties": {
"AddressType": {
"type": "string"
},
"City": {
"type": "string"
},
"Country": {
"type": "string"
},
"PostalCode": {
"type": "string"
},
"Region": {
"type": "string"
}
}
}
},
"BankAccountDetails": {
"type": "string"
},
"ContactID": {
"type": "string"
},
"ContactStatus": {
"type": "string"
},
"EmailAddress": {
"type": "string"
},
"HasAttachments": {
"type": "boolean"
},
"HasValidationErrors": {
"type": "boolean"
},
"IsCustomer": {
"type": "boolean"
},
"IsSupplier": {
"type": "boolean"
},
"Name": {
"type": "string"
},
"Phones": {
"type": "array",
"items": {
"type": "object",
"properties": {
"PhoneAreaCode": {
"type": "string"
},
"PhoneCountryCode": {
"type": "string"
},
"PhoneNumber": {
"type": "string"
},
"PhoneType": {
"type": "string"
}
}
}
},
"UpdatedDateUTC": {
"type": "string"
}
},
"version": 2
}

View File

@@ -1,147 +0,0 @@
{
"type": "object",
"properties": {
"$approval": {
"type": "object",
"properties": {
"approve": {
"type": "boolean"
},
"delegate": {
"type": "boolean"
},
"reject": {
"type": "boolean"
},
"resubmit": {
"type": "boolean"
},
"takeover": {
"type": "boolean"
}
}
},
"$approval_state": {
"type": "string"
},
"$approved": {
"type": "boolean"
},
"$currency_symbol": {
"type": "string"
},
"$editable": {
"type": "boolean"
},
"$field_states": {
"type": "null"
},
"$in_merge": {
"type": "boolean"
},
"$is_duplicate": {
"type": "boolean"
},
"$layout_id": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"$locked_for_me": {
"type": "boolean"
},
"$process_flow": {
"type": "boolean"
},
"$review": {
"type": "null"
},
"$review_process": {
"type": "object",
"properties": {
"approve": {
"type": "boolean"
},
"reject": {
"type": "boolean"
},
"resubmit": {
"type": "boolean"
}
}
},
"$state": {
"type": "string"
},
"Account_Name": {
"type": "string"
},
"Account_Number": {
"type": "string"
},
"Created_By": {
"type": "object",
"properties": {
"email": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"Created_Time": {
"type": "string"
},
"id": {
"type": "string"
},
"Locked__s": {
"type": "boolean"
},
"Modified_By": {
"type": "object",
"properties": {
"email": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"Modified_Time": {
"type": "string"
},
"Owner": {
"type": "object",
"properties": {
"email": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"Parent_Account": {
"type": "null"
}
},
"version": 1
}

View File

@@ -1,124 +0,0 @@
{
"type": "object",
"properties": {
"$approval": {
"type": "object",
"properties": {
"approve": {
"type": "boolean"
},
"delegate": {
"type": "boolean"
},
"reject": {
"type": "boolean"
},
"resubmit": {
"type": "boolean"
},
"takeover": {
"type": "boolean"
}
}
},
"$approval_state": {
"type": "string"
},
"$approved": {
"type": "boolean"
},
"$currency_symbol": {
"type": "string"
},
"$editable": {
"type": "boolean"
},
"$field_states": {
"type": "null"
},
"$in_merge": {
"type": "boolean"
},
"$is_duplicate": {
"type": "boolean"
},
"$layout_id": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"$locked_for_me": {
"type": "boolean"
},
"$process_flow": {
"type": "boolean"
},
"$review": {
"type": "null"
},
"$review_process": {
"type": "object",
"properties": {
"approve": {
"type": "boolean"
},
"reject": {
"type": "boolean"
},
"resubmit": {
"type": "boolean"
}
}
},
"$state": {
"type": "string"
},
"Account_Name": {
"type": "string"
},
"Account_Number": {
"type": "string"
},
"id": {
"type": "string"
},
"Locked__s": {
"type": "boolean"
},
"Owner": {
"type": "object",
"properties": {
"email": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"Tag": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
}
}
},
"version": 1
}

View File

@@ -1,37 +0,0 @@
{
"type": "object",
"properties": {
"Created_By": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"Created_Time": {
"type": "string"
},
"id": {
"type": "string"
},
"Modified_By": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"Modified_Time": {
"type": "string"
}
},
"version": 1
}

View File

@@ -1,194 +0,0 @@
{
"type": "object",
"properties": {
"$approval": {
"type": "object",
"properties": {
"approve": {
"type": "boolean"
},
"delegate": {
"type": "boolean"
},
"reject": {
"type": "boolean"
},
"resubmit": {
"type": "boolean"
},
"takeover": {
"type": "boolean"
}
}
},
"$approval_state": {
"type": "string"
},
"$approved": {
"type": "boolean"
},
"$currency_symbol": {
"type": "string"
},
"$editable": {
"type": "boolean"
},
"$field_states": {
"type": "null"
},
"$in_merge": {
"type": "boolean"
},
"$is_duplicate": {
"type": "boolean"
},
"$layout_id": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"$locked_for_me": {
"type": "boolean"
},
"$process_flow": {
"type": "boolean"
},
"$review": {
"type": "null"
},
"$review_process": {
"type": "object",
"properties": {
"approve": {
"type": "boolean"
},
"reject": {
"type": "boolean"
},
"resubmit": {
"type": "boolean"
}
}
},
"$state": {
"type": "string"
},
"Created_By": {
"type": "object",
"properties": {
"email": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"Created_Time": {
"type": "string"
},
"Email_Opt_Out": {
"type": "boolean"
},
"Fax": {
"type": "null"
},
"Full_Name": {
"type": "string"
},
"Home_Phone": {
"type": "null"
},
"id": {
"type": "string"
},
"Last_Name": {
"type": "string"
},
"Locked__s": {
"type": "boolean"
},
"Modified_By": {
"type": "object",
"properties": {
"email": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"Modified_Time": {
"type": "string"
},
"Other_City": {
"type": "null"
},
"Other_Country": {
"type": "null"
},
"Other_State": {
"type": "null"
},
"Other_Street": {
"type": "null"
},
"Other_Zip": {
"type": "null"
},
"Owner": {
"type": "object",
"properties": {
"email": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"Reporting_To": {
"type": "null"
},
"Tag": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
}
},
"Unsubscribed_Mode": {
"type": "null"
},
"Unsubscribed_Time": {
"type": "null"
},
"Vendor_Name": {
"type": "null"
}
},
"version": 1
}

View File

@@ -1,165 +0,0 @@
{
"type": "object",
"properties": {
"$approval": {
"type": "object",
"properties": {
"approve": {
"type": "boolean"
},
"delegate": {
"type": "boolean"
},
"reject": {
"type": "boolean"
},
"resubmit": {
"type": "boolean"
},
"takeover": {
"type": "boolean"
}
}
},
"$approval_state": {
"type": "string"
},
"$approved": {
"type": "boolean"
},
"$currency_symbol": {
"type": "string"
},
"$editable": {
"type": "boolean"
},
"$field_states": {
"type": "null"
},
"$in_merge": {
"type": "boolean"
},
"$is_duplicate": {
"type": "boolean"
},
"$layout_id": {
"type": "object",
"properties": {
"display_label": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"$locked_for_me": {
"type": "boolean"
},
"$process_flow": {
"type": "boolean"
},
"$review": {
"type": "null"
},
"$review_process": {
"type": "object",
"properties": {
"approve": {
"type": "boolean"
},
"reject": {
"type": "boolean"
},
"resubmit": {
"type": "boolean"
}
}
},
"$state": {
"type": "string"
},
"Created_By": {
"type": "object",
"properties": {
"email": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"Created_Time": {
"type": "string"
},
"Email_Opt_Out": {
"type": "boolean"
},
"Full_Name": {
"type": "string"
},
"Home_Phone": {
"type": "null"
},
"id": {
"type": "string"
},
"Last_Name": {
"type": "string"
},
"Locked__s": {
"type": "boolean"
},
"Modified_By": {
"type": "object",
"properties": {
"email": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"Modified_Time": {
"type": "string"
},
"Other_Phone": {
"type": "null"
},
"Owner": {
"type": "object",
"properties": {
"email": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"Unsubscribed_Mode": {
"type": "null"
},
"Unsubscribed_Time": {
"type": "null"
},
"Vendor_Name": {
"type": "null"
}
},
"version": 6
}

View File

@@ -1,37 +0,0 @@
{
"type": "object",
"properties": {
"Created_By": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"Created_Time": {
"type": "string"
},
"id": {
"type": "string"
},
"Modified_By": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"Modified_Time": {
"type": "string"
}
},
"version": 1
}

View File

@@ -1,37 +0,0 @@
{
"type": "object",
"properties": {
"Created_By": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"Created_Time": {
"type": "string"
},
"id": {
"type": "string"
},
"Modified_By": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"Modified_Time": {
"type": "string"
}
},
"version": 1
}

View File

@@ -1,37 +0,0 @@
{
"type": "object",
"properties": {
"Created_By": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"Created_Time": {
"type": "string"
},
"id": {
"type": "string"
},
"Modified_By": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"Modified_Time": {
"type": "string"
}
},
"version": 1
}

View File

@@ -1,169 +0,0 @@
{
"type": "object",
"properties": {
"$approval": {
"type": "object",
"properties": {
"approve": {
"type": "boolean"
},
"delegate": {
"type": "boolean"
},
"reject": {
"type": "boolean"
},
"resubmit": {
"type": "boolean"
},
"takeover": {
"type": "boolean"
}
}
},
"$approval_state": {
"type": "string"
},
"$approved": {
"type": "boolean"
},
"$canvas_id": {
"type": "null"
},
"$currency_symbol": {
"type": "string"
},
"$editable": {
"type": "boolean"
},
"$field_states": {
"type": "null"
},
"$in_merge": {
"type": "boolean"
},
"$locked_for_me": {
"type": "boolean"
},
"$process_flow": {
"type": "boolean"
},
"$review": {
"type": "null"
},
"$review_process": {
"type": "object",
"properties": {
"approve": {
"type": "boolean"
},
"reject": {
"type": "boolean"
},
"resubmit": {
"type": "boolean"
}
}
},
"$state": {
"type": "string"
},
"Account_Name": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"Contact_Name": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"Created_By": {
"type": "object",
"properties": {
"email": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"Created_Time": {
"type": "string"
},
"Deal_Name": {
"type": "string"
},
"id": {
"type": "string"
},
"Locked__s": {
"type": "boolean"
},
"Modified_By": {
"type": "object",
"properties": {
"email": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"Modified_Time": {
"type": "string"
},
"Owner": {
"type": "object",
"properties": {
"email": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"Probability": {
"type": "integer"
},
"Tag": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
}
}
},
"version": 1
}

View File

@@ -1,169 +0,0 @@
{
"type": "object",
"properties": {
"$approval": {
"type": "object",
"properties": {
"approve": {
"type": "boolean"
},
"delegate": {
"type": "boolean"
},
"reject": {
"type": "boolean"
},
"resubmit": {
"type": "boolean"
},
"takeover": {
"type": "boolean"
}
}
},
"$approval_state": {
"type": "string"
},
"$approved": {
"type": "boolean"
},
"$currency_symbol": {
"type": "string"
},
"$editable": {
"type": "boolean"
},
"$field_states": {
"type": "null"
},
"$in_merge": {
"type": "boolean"
},
"$layout_id": {
"type": "object",
"properties": {
"display_label": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"$locked_for_me": {
"type": "boolean"
},
"$process_flow": {
"type": "boolean"
},
"$review": {
"type": "null"
},
"$review_process": {
"type": "object",
"properties": {
"approve": {
"type": "boolean"
},
"reject": {
"type": "boolean"
},
"resubmit": {
"type": "boolean"
}
}
},
"$state": {
"type": "string"
},
"Account_Name": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"Created_By": {
"type": "object",
"properties": {
"email": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"Created_Time": {
"type": "string"
},
"Deal_Name": {
"type": "string"
},
"id": {
"type": "string"
},
"Locked__s": {
"type": "boolean"
},
"Modified_By": {
"type": "object",
"properties": {
"email": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"Modified_Time": {
"type": "string"
},
"Owner": {
"type": "object",
"properties": {
"email": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"Probability": {
"type": "integer"
},
"Tag": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
}
}
},
"version": 2
}

View File

@@ -1,37 +0,0 @@
{
"type": "object",
"properties": {
"Created_By": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"Created_Time": {
"type": "string"
},
"id": {
"type": "string"
},
"Modified_By": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"Modified_Time": {
"type": "string"
}
},
"version": 1
}

View File

@@ -1,37 +0,0 @@
{
"type": "object",
"properties": {
"Created_By": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"Created_Time": {
"type": "string"
},
"id": {
"type": "string"
},
"Modified_By": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"Modified_Time": {
"type": "string"
}
},
"version": 1
}

View File

@@ -1,179 +0,0 @@
{
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"type": "object",
"properties": {
"$approval": {
"type": "object",
"properties": {
"approve": {
"type": "boolean"
},
"delegate": {
"type": "boolean"
},
"reject": {
"type": "boolean"
},
"resubmit": {
"type": "boolean"
},
"takeover": {
"type": "boolean"
}
}
},
"$approval_state": {
"type": "string"
},
"$approved": {
"type": "boolean"
},
"$converted": {
"type": "boolean"
},
"$currency_symbol": {
"type": "string"
},
"$editable": {
"type": "boolean"
},
"$field_states": {
"type": "null"
},
"$in_merge": {
"type": "boolean"
},
"$locked_for_me": {
"type": "boolean"
},
"$process_flow": {
"type": "boolean"
},
"$review": {
"type": "null"
},
"$review_process": {
"type": "object",
"properties": {
"approve": {
"type": "boolean"
},
"reject": {
"type": "boolean"
},
"resubmit": {
"type": "boolean"
}
}
},
"$state": {
"type": "string"
},
"$zia_owner_assignment": {
"type": "string"
},
"Created_By": {
"type": "object",
"properties": {
"email": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"Created_Time": {
"type": "string"
},
"Email_Opt_Out": {
"type": "boolean"
},
"Fax": {
"type": "null"
},
"Full_Name": {
"type": "string"
},
"id": {
"type": "string"
},
"Last_Name": {
"type": "string"
},
"Locked__s": {
"type": "boolean"
},
"Modified_By": {
"type": "object",
"properties": {
"email": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"Modified_Time": {
"type": "string"
},
"No_of_Employees": {
"type": "null"
},
"Owner": {
"type": "object",
"properties": {
"email": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"Rating": {
"type": "null"
},
"Secondary_Email": {
"type": "null"
},
"Tag": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
}
},
"Unsubscribed_Mode": {
"type": "null"
},
"Unsubscribed_Time": {
"type": "null"
}
}
}
}
},
"version": 1
}

View File

@@ -1,139 +0,0 @@
{
"type": "object",
"properties": {
"$approval": {
"type": "object",
"properties": {
"approve": {
"type": "boolean"
},
"delegate": {
"type": "boolean"
},
"reject": {
"type": "boolean"
},
"resubmit": {
"type": "boolean"
},
"takeover": {
"type": "boolean"
}
}
},
"$approval_state": {
"type": "string"
},
"$approved": {
"type": "boolean"
},
"$converted": {
"type": "boolean"
},
"$currency_symbol": {
"type": "string"
},
"$editable": {
"type": "boolean"
},
"$field_states": {
"type": "null"
},
"$in_merge": {
"type": "boolean"
},
"$layout_id": {
"type": "object",
"properties": {
"display_label": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"$locked_for_me": {
"type": "boolean"
},
"$process_flow": {
"type": "boolean"
},
"$review": {
"type": "null"
},
"$review_process": {
"type": "object",
"properties": {
"approve": {
"type": "boolean"
},
"reject": {
"type": "boolean"
},
"resubmit": {
"type": "boolean"
}
}
},
"$state": {
"type": "string"
},
"Created_Time": {
"type": "string"
},
"Email_Opt_Out": {
"type": "boolean"
},
"Full_Name": {
"type": "string"
},
"id": {
"type": "string"
},
"Last_Name": {
"type": "string"
},
"Locked__s": {
"type": "boolean"
},
"Owner": {
"type": "object",
"properties": {
"email": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"Tag": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
}
},
"Unsubscribed_Mode": {
"type": "null"
},
"Unsubscribed_Time": {
"type": "null"
}
},
"version": 5
}

View File

@@ -1,120 +0,0 @@
{
"type": "object",
"properties": {
"api_name": {
"type": "string"
},
"association_details": {
"type": "null"
},
"businesscard_supported": {
"type": "boolean"
},
"convert_mapping": {
"type": "object",
"properties": {
"Deals": {
"type": "null"
}
}
},
"created_source": {
"type": "string"
},
"crypt": {
"type": "null"
},
"custom_field": {
"type": "boolean"
},
"data_type": {
"type": "string"
},
"decimal_place": {
"type": "null"
},
"display_label": {
"type": "string"
},
"external": {
"type": "null"
},
"field_label": {
"type": "string"
},
"field_read_only": {
"type": "boolean"
},
"history_tracking": {
"type": "boolean"
},
"id": {
"type": "string"
},
"json_type": {
"type": "string"
},
"length": {
"type": "integer"
},
"mass_update": {
"type": "boolean"
},
"pick_list_values": {
"type": "array",
"items": {
"type": "object",
"properties": {
"actual_value": {
"type": "string"
},
"display_value": {
"type": "string"
},
"reference_value": {
"type": "string"
}
}
}
},
"quick_sequence_number": {
"type": "string"
},
"read_only": {
"type": "boolean"
},
"subform": {
"type": "null"
},
"system_mandatory": {
"type": "boolean"
},
"ui_type": {
"type": "integer"
},
"view_type": {
"type": "object",
"properties": {
"create": {
"type": "boolean"
},
"edit": {
"type": "boolean"
},
"quick_create": {
"type": "boolean"
},
"view": {
"type": "boolean"
}
}
},
"visible": {
"type": "boolean"
},
"webhook": {
"type": "boolean"
}
},
"version": 1
}

View File

@@ -1,37 +0,0 @@
{
"type": "object",
"properties": {
"Created_By": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"Created_Time": {
"type": "string"
},
"id": {
"type": "string"
},
"Modified_By": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"Modified_Time": {
"type": "string"
}
},
"version": 1
}

View File

@@ -1,37 +0,0 @@
{
"type": "object",
"properties": {
"Created_By": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"Created_Time": {
"type": "string"
},
"id": {
"type": "string"
},
"Modified_By": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"Modified_Time": {
"type": "string"
}
},
"version": 1
}

View File

@@ -1,223 +0,0 @@
{
"type": "object",
"properties": {
"created_at": {
"type": "string"
},
"creation_source": {
"type": "string"
},
"duration": {
"type": "integer"
},
"encrypted_password": {
"type": "string"
},
"h323_password": {
"type": "string"
},
"host_email": {
"type": "string"
},
"host_id": {
"type": "string"
},
"id": {
"type": "integer"
},
"join_url": {
"type": "string"
},
"password": {
"type": "string"
},
"pre_schedule": {
"type": "boolean"
},
"pstn_password": {
"type": "string"
},
"settings": {
"type": "object",
"properties": {
"allow_host_control_participant_mute_state": {
"type": "boolean"
},
"allow_multiple_devices": {
"type": "boolean"
},
"alternative_host_update_polls": {
"type": "boolean"
},
"alternative_hosts": {
"type": "string"
},
"alternative_hosts_email_notification": {
"type": "boolean"
},
"approval_type": {
"type": "integer"
},
"approved_or_denied_countries_or_regions": {
"type": "object",
"properties": {
"enable": {
"type": "boolean"
}
}
},
"audio": {
"type": "string"
},
"auto_recording": {
"type": "string"
},
"breakout_room": {
"type": "object",
"properties": {
"enable": {
"type": "boolean"
}
}
},
"close_registration": {
"type": "boolean"
},
"cn_meeting": {
"type": "boolean"
},
"continuous_meeting_chat": {
"type": "object",
"properties": {
"auto_add_invited_external_users": {
"type": "boolean"
},
"auto_add_meeting_participants": {
"type": "boolean"
},
"channel_id": {
"type": "string"
},
"enable": {
"type": "boolean"
}
}
},
"device_testing": {
"type": "boolean"
},
"email_in_attendee_report": {
"type": "boolean"
},
"email_notification": {
"type": "boolean"
},
"encryption_type": {
"type": "string"
},
"enforce_login": {
"type": "boolean"
},
"enforce_login_domains": {
"type": "string"
},
"focus_mode": {
"type": "boolean"
},
"host_save_video_order": {
"type": "boolean"
},
"host_video": {
"type": "boolean"
},
"in_meeting": {
"type": "boolean"
},
"internal_meeting": {
"type": "boolean"
},
"jbh_time": {
"type": "integer"
},
"join_before_host": {
"type": "boolean"
},
"meeting_authentication": {
"type": "boolean"
},
"mute_upon_entry": {
"type": "boolean"
},
"participant_focused_meeting": {
"type": "boolean"
},
"participant_video": {
"type": "boolean"
},
"private_meeting": {
"type": "boolean"
},
"push_change_to_calendar": {
"type": "boolean"
},
"registrants_confirmation_email": {
"type": "boolean"
},
"registrants_email_notification": {
"type": "boolean"
},
"request_permission_to_unmute_participants": {
"type": "boolean"
},
"show_join_info": {
"type": "boolean"
},
"show_share_button": {
"type": "boolean"
},
"sign_language_interpretation": {
"type": "object",
"properties": {
"enable": {
"type": "boolean"
}
}
},
"use_pmi": {
"type": "boolean"
},
"waiting_room": {
"type": "boolean"
},
"watermark": {
"type": "boolean"
}
}
},
"start_time": {
"type": "string"
},
"start_url": {
"type": "string"
},
"status": {
"type": "string"
},
"supportGoLive": {
"type": "boolean"
},
"timezone": {
"type": "string"
},
"topic": {
"type": "string"
},
"type": {
"type": "integer"
},
"uuid": {
"type": "string"
}
},
"version": 1
}

View File

@@ -1,254 +0,0 @@
{
"type": "object",
"properties": {
"agenda": {
"type": "string"
},
"assistant_id": {
"type": "string"
},
"created_at": {
"type": "string"
},
"duration": {
"type": "integer"
},
"host_email": {
"type": "string"
},
"host_id": {
"type": "string"
},
"id": {
"type": "integer"
},
"join_url": {
"type": "string"
},
"pre_schedule": {
"type": "boolean"
},
"settings": {
"type": "object",
"properties": {
"allow_multiple_devices": {
"type": "boolean"
},
"alternative_host_update_polls": {
"type": "boolean"
},
"alternative_hosts": {
"type": "string"
},
"alternative_hosts_email_notification": {
"type": "boolean"
},
"approval_type": {
"type": "integer"
},
"approved_or_denied_countries_or_regions": {
"type": "object",
"properties": {
"enable": {
"type": "boolean"
}
}
},
"audio": {
"type": "string"
},
"auto_recording": {
"type": "string"
},
"auto_start_ai_companion_questions": {
"type": "boolean"
},
"auto_start_meeting_summary": {
"type": "boolean"
},
"breakout_room": {
"type": "object",
"properties": {
"enable": {
"type": "boolean"
}
}
},
"close_registration": {
"type": "boolean"
},
"cn_meeting": {
"type": "boolean"
},
"continuous_meeting_chat": {
"type": "object",
"properties": {
"auto_add_invited_external_users": {
"type": "boolean"
},
"channel_id": {
"type": "string"
},
"enable": {
"type": "boolean"
}
}
},
"device_testing": {
"type": "boolean"
},
"email_in_attendee_report": {
"type": "boolean"
},
"email_notification": {
"type": "boolean"
},
"enable_dedicated_group_chat": {
"type": "boolean"
},
"encryption_type": {
"type": "string"
},
"enforce_login": {
"type": "boolean"
},
"enforce_login_domains": {
"type": "string"
},
"focus_mode": {
"type": "boolean"
},
"global_dial_in_countries": {
"type": "array",
"items": {
"type": "string"
}
},
"global_dial_in_numbers": {
"type": "array",
"items": {
"type": "object",
"properties": {
"city": {
"type": "string"
},
"country": {
"type": "string"
},
"country_name": {
"type": "string"
},
"number": {
"type": "string"
},
"type": {
"type": "string"
}
}
}
},
"host_save_video_order": {
"type": "boolean"
},
"host_video": {
"type": "boolean"
},
"in_meeting": {
"type": "boolean"
},
"internal_meeting": {
"type": "boolean"
},
"jbh_time": {
"type": "integer"
},
"join_before_host": {
"type": "boolean"
},
"meeting_authentication": {
"type": "boolean"
},
"meeting_invitees": {
"type": "array",
"items": {
"type": "object",
"properties": {
"email": {
"type": "string"
}
}
}
},
"mute_upon_entry": {
"type": "boolean"
},
"participant_focused_meeting": {
"type": "boolean"
},
"participant_video": {
"type": "boolean"
},
"private_meeting": {
"type": "boolean"
},
"push_change_to_calendar": {
"type": "boolean"
},
"registrants_confirmation_email": {
"type": "boolean"
},
"registrants_email_notification": {
"type": "boolean"
},
"request_permission_to_unmute_participants": {
"type": "boolean"
},
"show_join_info": {
"type": "boolean"
},
"show_share_button": {
"type": "boolean"
},
"sign_language_interpretation": {
"type": "object",
"properties": {
"enable": {
"type": "boolean"
}
}
},
"use_pmi": {
"type": "boolean"
},
"waiting_room": {
"type": "boolean"
},
"watermark": {
"type": "boolean"
}
}
},
"start_time": {
"type": "string"
},
"start_url": {
"type": "string"
},
"status": {
"type": "string"
},
"timezone": {
"type": "string"
},
"topic": {
"type": "string"
},
"type": {
"type": "integer"
},
"uuid": {
"type": "string"
}
},
"version": 1
}

View File

@@ -1,36 +0,0 @@
{
"type": "object",
"properties": {
"created_at": {
"type": "string"
},
"duration": {
"type": "integer"
},
"host_id": {
"type": "string"
},
"id": {
"type": "integer"
},
"join_url": {
"type": "string"
},
"start_time": {
"type": "string"
},
"timezone": {
"type": "string"
},
"topic": {
"type": "string"
},
"type": {
"type": "integer"
},
"uuid": {
"type": "string"
}
},
"version": 2
}