n8n-nodes-aixyte
Version:
Complete n8n node for Aixyte API - Manage Excites, Domains, and Files for personalized web experiences
802 lines (801 loc) • 39.2 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Aixyte = void 0;
const n8n_workflow_1 = require("n8n-workflow");
class Aixyte {
constructor() {
this.description = {
displayName: 'Aixyte API',
name: 'aixyte',
icon: 'fa:rocket',
group: ['output'],
version: 4,
description: 'Complete API for managing personalized web experiences - Excites, Domains, and Files (Rate limited: 300 requests/min)',
defaults: {
name: 'Aixyte API',
color: '#772244',
},
inputs: ["main" /* NodeConnectionType.Main */],
outputs: ["main" /* NodeConnectionType.Main */],
credentials: [
{
name: 'aixyteApi',
required: true,
},
],
properties: [
// === UNIFIED OPERATIONS ===
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
options: [
// EXCITE OPERATIONS
{ name: 'Excite: List', value: 'excite_list', description: 'Retrieve paginated list of excites with optional filtering' },
{ name: 'Excite: Create', value: 'excite_create', description: 'Create a new excite with optional files' },
{ name: 'Excite: Get', value: 'excite_get', description: 'Retrieve specific excite by ID with files' },
{ name: 'Excite: Update', value: 'excite_update', description: 'Update existing excite and files' },
{ name: 'Excite: Delete', value: 'excite_delete', description: 'Delete an excite permanently' },
// DOMAIN OPERATIONS
{ name: 'Domain: List', value: 'domain_list', description: 'Retrieve all domains with optional search' },
{ name: 'Domain: Create', value: 'domain_create', description: 'Create a new domain configuration' },
{ name: 'Domain: Get', value: 'domain_get', description: 'Retrieve specific domain by ID' },
{ name: 'Domain: Update', value: 'domain_update', description: 'Update existing domain configuration' },
{ name: 'Domain: Delete', value: 'domain_delete', description: 'Delete domain permanently' },
// FILE OPERATIONS
{ name: 'File: List', value: 'file_list', description: 'List all files for a specific excite' },
{ name: 'File: Add', value: 'file_add', description: 'Add new file (photo/video) to an excite' },
{ name: 'File: Update', value: 'file_update', description: 'Update existing file metadata' },
{ name: 'File: Delete', value: 'file_delete', description: 'Remove file from excite' },
],
default: 'excite_list',
description: 'Choose the operation to perform',
},
// === ID PARAMETERS ===
{
displayName: 'Excite ID',
name: 'exciteId',
type: 'string',
required: true,
displayOptions: {
show: {
operation: ['excite_get', 'excite_update', 'excite_delete'],
},
},
default: '',
description: 'UUID of the excite to operate on',
placeholder: 'e.g. 123e4567-e89b-12d3-a456-426614174000',
},
{
displayName: 'Domain ID',
name: 'domainId',
type: 'string',
required: true,
displayOptions: {
show: {
operation: ['domain_get', 'domain_update', 'domain_delete'],
},
},
default: '',
description: 'UUID of the domain to operate on',
placeholder: 'e.g. 123e4567-e89b-12d3-a456-426614174000',
},
{
displayName: 'Excite ID',
name: 'fileExciteId',
type: 'string',
required: true,
displayOptions: {
show: {
operation: ['file_list', 'file_add', 'file_update', 'file_delete'],
},
},
default: '',
description: 'UUID of the excite that owns the files',
placeholder: 'e.g. 123e4567-e89b-12d3-a456-426614174000',
},
{
displayName: 'File ID',
name: 'fileId',
type: 'string',
required: true,
displayOptions: {
show: {
operation: ['file_update', 'file_delete'],
},
},
default: '',
description: 'UUID of the file to operate on',
placeholder: 'e.g. 123e4567-e89b-12d3-a456-426614174000',
},
// === EXCITE FIELDS ===
{
displayName: 'Title',
name: 'title',
type: 'string',
required: true,
displayOptions: {
show: {
operation: ['excite_create', 'excite_update'],
},
},
default: '',
description: 'Display title for the excite (1-255 characters)',
typeOptions: {
validation: [
{
type: 'minLength',
properties: {
minLength: 1,
errorMessage: 'Title is required and must be at least 1 character',
},
},
{
type: 'maxLength',
properties: {
maxLength: 255,
errorMessage: 'Title must be 255 characters or less',
},
},
],
},
},
{
displayName: 'Goal',
name: 'goal',
type: 'string',
required: true,
displayOptions: {
show: {
operation: ['excite_create', 'excite_update'],
},
},
default: '',
description: 'The objective or purpose of this excite (1-500 characters)',
typeOptions: {
validation: [
{
type: 'minLength',
properties: {
minLength: 1,
errorMessage: 'Goal is required and must be at least 1 character',
},
},
{
type: 'maxLength',
properties: {
maxLength: 500,
errorMessage: 'Goal must be 500 characters or less',
},
},
],
},
},
{
displayName: 'Domain ID',
name: 'exciteDomainId',
type: 'string',
required: true,
displayOptions: {
show: {
operation: ['excite_create', 'excite_update'],
},
},
default: '',
description: 'UUID of the domain this excite belongs to',
placeholder: 'e.g. 123e4567-e89b-12d3-a456-426614174000',
},
{
displayName: 'Slug',
name: 'slug',
type: 'string',
required: true,
displayOptions: {
show: {
operation: ['excite_create', 'excite_update'],
},
},
default: '',
description: 'URL-friendly identifier, unique per user (lowercase letters, numbers, hyphens only, 1-50 chars)',
placeholder: 'e.g. my-awesome-excite',
typeOptions: {
validation: [
{
type: 'minLength',
properties: {
minLength: 1,
errorMessage: 'Slug is required and must be at least 1 character',
},
},
{
type: 'regex',
properties: {
regex: '^[a-z0-9-]+$',
errorMessage: 'Slug must contain only lowercase letters, numbers, and hyphens',
},
},
{
type: 'maxLength',
properties: {
maxLength: 50,
errorMessage: 'Slug must be 50 characters or less',
},
},
],
},
},
{
displayName: 'Is Global',
name: 'isGlobal',
type: 'boolean',
displayOptions: {
show: {
operation: ['excite_create', 'excite_update'],
},
},
default: false,
description: 'When true, applies to entire domain; when false, applies only to specified paths',
},
{
displayName: 'Paths',
name: 'paths',
type: 'fixedCollection',
displayOptions: {
show: {
operation: ['excite_create', 'excite_update'],
},
},
default: {},
placeholder: 'Add Path',
typeOptions: {
multipleValues: true,
},
options: [
{
name: 'path',
displayName: 'Path',
values: [
{
displayName: 'URL Path',
name: 'value',
type: 'string',
default: '',
placeholder: '/example-path',
description: 'Specific URL path where this excite applies',
},
],
},
],
description: 'Array of URL paths where this excite applies (ignored if is_global is true)',
},
{
displayName: 'Additional Data',
name: 'additionalData',
type: 'json',
displayOptions: {
show: {
operation: ['excite_create', 'excite_update'],
},
},
default: '{}',
description: 'Custom JSON data for additional configuration or metadata',
placeholder: '{"key": "value", "config": {"option": true}}',
},
// === EXCITE FILES (for create/update) ===
{
displayName: 'Files',
name: 'exciteFiles',
type: 'fixedCollection',
displayOptions: {
show: {
operation: ['excite_create', 'excite_update'],
},
},
default: {},
placeholder: 'Add File',
typeOptions: {
multipleValues: true,
},
options: [
{
name: 'file',
displayName: 'File',
values: [
{
displayName: 'File Type',
name: 'file_type',
type: 'options',
options: [
{ name: 'Photo', value: 'photo' },
{ name: 'Video', value: 'video' },
],
default: 'photo',
description: 'Type of file',
},
{
displayName: 'File URL',
name: 'file_url',
type: 'string',
default: '',
placeholder: 'https://example.com/file.jpg',
description: 'Direct URL to the file',
},
{
displayName: 'File Name',
name: 'file_name',
type: 'string',
default: '',
placeholder: 'My Photo',
description: 'Display name for the file',
},
{
displayName: 'Description',
name: 'description',
type: 'string',
default: '',
placeholder: 'Optional file description',
description: 'Optional description of the file',
},
],
},
],
description: 'Files to attach to this excite (optional)',
},
// === DOMAIN FIELDS ===
{
displayName: 'Domain Name',
name: 'domainName',
type: 'string',
displayOptions: {
show: {
operation: ['domain_create', 'domain_update'],
},
},
default: '',
description: 'Display name for the domain (1-100 characters)',
typeOptions: {
validation: [
{
type: 'minLength',
properties: {
minLength: 1,
errorMessage: 'Domain name must be at least 1 character',
},
},
{
type: 'maxLength',
properties: {
maxLength: 100,
errorMessage: 'Domain name must be 100 characters or less',
},
},
],
},
},
{
displayName: 'Domain URL',
name: 'domainUrl',
type: 'string',
required: true,
displayOptions: {
show: {
operation: ['domain_create', 'domain_update'],
},
},
default: '',
description: 'The domain URL (1-255 characters)',
placeholder: 'https://example.com',
typeOptions: {
validation: [
{
type: 'minLength',
properties: {
minLength: 1,
errorMessage: 'Domain URL is required',
},
},
{
type: 'maxLength',
properties: {
maxLength: 255,
errorMessage: 'Domain URL must be 255 characters or less',
},
},
],
},
},
// === FILE FIELDS ===
{
displayName: 'File Type',
name: 'fileType',
type: 'options',
required: true,
displayOptions: {
show: {
operation: ['file_add', 'file_update'],
},
},
options: [
{ name: 'Photo', value: 'photo', description: 'Image file (JPG, PNG, etc.)' },
{ name: 'Video', value: 'video', description: 'Video file (MP4, MOV, etc.)' },
],
default: 'photo',
description: 'Type of file being uploaded',
},
{
displayName: 'File URL',
name: 'fileUrl',
type: 'string',
required: true,
displayOptions: {
show: {
operation: ['file_add', 'file_update'],
},
},
default: '',
description: 'Direct URL to the file',
placeholder: 'https://example.com/files/image.jpg',
},
{
displayName: 'File Name',
name: 'fileName',
type: 'string',
required: true,
displayOptions: {
show: {
operation: ['file_add', 'file_update'],
},
},
default: '',
description: 'Display name for the file (1-255 characters)',
typeOptions: {
validation: [
{
type: 'minLength',
properties: {
minLength: 1,
errorMessage: 'File name is required',
},
},
{
type: 'maxLength',
properties: {
maxLength: 255,
errorMessage: 'File name must be 255 characters or less',
},
},
],
},
},
{
displayName: 'Description',
name: 'fileDescription',
type: 'string',
displayOptions: {
show: {
operation: ['file_add', 'file_update'],
},
},
default: '',
description: 'Optional description of the file (max 500 characters)',
typeOptions: {
validation: [
{
type: 'maxLength',
properties: {
maxLength: 500,
errorMessage: 'Description must be 500 characters or less',
},
},
],
},
},
// === LIST PARAMETERS ===
{
displayName: 'Limit',
name: 'limit',
type: 'number',
displayOptions: {
show: {
operation: ['excite_list'],
},
},
default: 10,
description: 'Number of excites to return (1-100)',
typeOptions: {
minValue: 1,
maxValue: 100,
},
},
{
displayName: 'Offset',
name: 'offset',
type: 'number',
displayOptions: {
show: {
operation: ['excite_list'],
},
},
default: 0,
description: 'Number of excites to skip for pagination',
typeOptions: {
minValue: 0,
},
},
{
displayName: 'Search',
name: 'search',
type: 'string',
displayOptions: {
show: {
operation: ['excite_list', 'domain_list'],
},
},
default: '',
description: 'Search term to filter results by title, goal, or domain',
placeholder: 'Enter search term...',
},
],
};
}
async execute() {
var _a, _b;
const items = this.getInputData();
const returnData = [];
const credentials = await this.getCredentials('aixyteApi');
const baseUrl = 'https://azxjgkopxmhwzvkxouuy.supabase.co/functions/v1/api';
for (let i = 0; i < items.length; i++) {
try {
const operation = this.getNodeParameter('operation', i);
const options = {
headers: {
'Authorization': `Bearer ${credentials.apiKey}`,
'Content-Type': 'application/json',
},
method: 'GET',
json: true,
};
let responseData;
// === EXCITE OPERATIONS ===
if (operation.startsWith('excite_')) {
const exciteOp = operation.replace('excite_', '');
options.url = `${baseUrl}/excites`;
switch (exciteOp) {
case 'list':
const limit = this.getNodeParameter('limit', i);
const offset = this.getNodeParameter('offset', i);
const search = this.getNodeParameter('search', i);
options.qs = {};
if (limit)
options.qs.limit = limit;
if (offset)
options.qs.offset = offset;
if (search)
options.qs.search = search;
responseData = await this.helpers.request(options);
if (responseData.data && Array.isArray(responseData.data)) {
responseData.data.forEach((item) => {
returnData.push({ json: item });
});
}
break;
case 'create':
const title = this.getNodeParameter('title', i);
const goal = this.getNodeParameter('goal', i);
const exciteDomainId = this.getNodeParameter('exciteDomainId', i);
const slug = this.getNodeParameter('slug', i);
const isGlobal = this.getNodeParameter('isGlobal', i);
const pathsCollection = this.getNodeParameter('paths', i);
const additionalDataStr = this.getNodeParameter('additionalData', i);
const exciteFilesCollection = this.getNodeParameter('exciteFiles', i);
const paths = ((_a = pathsCollection === null || pathsCollection === void 0 ? void 0 : pathsCollection.path) === null || _a === void 0 ? void 0 : _a.map((p) => p.value)) || [];
let additionalData = {};
try {
additionalData = additionalDataStr ? JSON.parse(additionalDataStr) : {};
}
catch (error) {
additionalData = {};
}
const files = (exciteFilesCollection === null || exciteFilesCollection === void 0 ? void 0 : exciteFilesCollection.file) || [];
options.method = 'POST';
options.body = {
title,
goal,
domain_id: exciteDomainId,
slug,
is_global: isGlobal,
paths,
additional_data: additionalData,
files,
};
responseData = await this.helpers.request(options);
returnData.push({ json: responseData.data });
break;
case 'get':
const exciteId = this.getNodeParameter('exciteId', i);
options.url += `/${exciteId}`;
responseData = await this.helpers.request(options);
returnData.push({ json: responseData.data });
break;
case 'update':
const updateExciteId = this.getNodeParameter('exciteId', i);
const updateTitle = this.getNodeParameter('title', i);
const updateGoal = this.getNodeParameter('goal', i);
const updateDomainId = this.getNodeParameter('exciteDomainId', i);
const updateSlug = this.getNodeParameter('slug', i);
const updateIsGlobal = this.getNodeParameter('isGlobal', i);
const updatePathsCollection = this.getNodeParameter('paths', i);
const updateAdditionalDataStr = this.getNodeParameter('additionalData', i);
const updateExciteFilesCollection = this.getNodeParameter('exciteFiles', i);
const updatePaths = ((_b = updatePathsCollection === null || updatePathsCollection === void 0 ? void 0 : updatePathsCollection.path) === null || _b === void 0 ? void 0 : _b.map((p) => p.value)) || [];
let updateAdditionalData = {};
try {
updateAdditionalData = updateAdditionalDataStr ? JSON.parse(updateAdditionalDataStr) : {};
}
catch (error) {
updateAdditionalData = {};
}
const updateFiles = (updateExciteFilesCollection === null || updateExciteFilesCollection === void 0 ? void 0 : updateExciteFilesCollection.file) || [];
options.method = 'PUT';
options.url += `/${updateExciteId}`;
options.body = {
title: updateTitle,
goal: updateGoal,
domain_id: updateDomainId,
slug: updateSlug,
is_global: updateIsGlobal,
paths: updatePaths,
additional_data: updateAdditionalData,
files: updateFiles,
};
responseData = await this.helpers.request(options);
returnData.push({ json: responseData.data });
break;
case 'delete':
const deleteExciteId = this.getNodeParameter('exciteId', i);
options.method = 'DELETE';
options.url += `/${deleteExciteId}`;
responseData = await this.helpers.request(options);
returnData.push({ json: responseData.data || { message: 'excite deleted successfully' } });
break;
}
}
// === DOMAIN OPERATIONS ===
else if (operation.startsWith('domain_')) {
const domainOp = operation.replace('domain_', '');
options.url = `${baseUrl}/domains`;
switch (domainOp) {
case 'list':
const domainSearch = this.getNodeParameter('search', i);
if (domainSearch) {
options.qs = { search: domainSearch };
}
responseData = await this.helpers.request(options);
if (responseData.data && Array.isArray(responseData.data)) {
responseData.data.forEach((item) => {
returnData.push({ json: item });
});
}
break;
case 'create':
const domainName = this.getNodeParameter('domainName', i);
const domainUrl = this.getNodeParameter('domainUrl', i);
options.method = 'POST';
options.body = {
name: domainName,
domain: domainUrl,
};
responseData = await this.helpers.request(options);
returnData.push({ json: responseData.data });
break;
case 'get':
const getDomainId = this.getNodeParameter('domainId', i);
options.url += `/${getDomainId}`;
responseData = await this.helpers.request(options);
returnData.push({ json: responseData.data });
break;
case 'update':
const updateDomainIdParam = this.getNodeParameter('domainId', i);
const updateDomainName = this.getNodeParameter('domainName', i);
const updateDomainUrl = this.getNodeParameter('domainUrl', i);
options.method = 'PUT';
options.url += `/${updateDomainIdParam}`;
options.body = {
name: updateDomainName,
domain: updateDomainUrl,
};
responseData = await this.helpers.request(options);
returnData.push({ json: responseData.data });
break;
case 'delete':
const deleteDomainId = this.getNodeParameter('domainId', i);
options.method = 'DELETE';
options.url += `/${deleteDomainId}`;
responseData = await this.helpers.request(options);
returnData.push({ json: responseData.data || { message: 'domain deleted successfully' } });
break;
}
}
// === FILE OPERATIONS ===
else if (operation.startsWith('file_')) {
const fileOp = operation.replace('file_', '');
const fileExciteId = this.getNodeParameter('fileExciteId', i);
switch (fileOp) {
case 'list':
options.url = `${baseUrl}/excites/${fileExciteId}/files`;
responseData = await this.helpers.request(options);
if (responseData.data && Array.isArray(responseData.data)) {
responseData.data.forEach((item) => {
returnData.push({ json: item });
});
}
break;
case 'add':
const fileType = this.getNodeParameter('fileType', i);
const fileUrl = this.getNodeParameter('fileUrl', i);
const fileName = this.getNodeParameter('fileName', i);
const fileDescription = this.getNodeParameter('fileDescription', i);
options.method = 'POST';
options.url = `${baseUrl}/excites/${fileExciteId}/files`;
options.body = {
file_type: fileType,
file_url: fileUrl,
file_name: fileName,
};
if (fileDescription) {
options.body.description = fileDescription;
}
responseData = await this.helpers.request(options);
returnData.push({ json: responseData.data });
break;
case 'update':
const updateFileId = this.getNodeParameter('fileId', i);
const updateFileType = this.getNodeParameter('fileType', i);
const updateFileUrl = this.getNodeParameter('fileUrl', i);
const updateFileName = this.getNodeParameter('fileName', i);
const updateFileDescription = this.getNodeParameter('fileDescription', i);
options.method = 'PUT';
options.url = `${baseUrl}/excites/${fileExciteId}/files/${updateFileId}`;
options.body = {
file_type: updateFileType,
file_url: updateFileUrl,
file_name: updateFileName,
};
if (updateFileDescription) {
options.body.description = updateFileDescription;
}
responseData = await this.helpers.request(options);
returnData.push({ json: responseData.data });
break;
case 'delete':
const deleteFileId = this.getNodeParameter('fileId', i);
options.method = 'DELETE';
options.url = `${baseUrl}/excites/${fileExciteId}/files/${deleteFileId}`;
responseData = await this.helpers.request(options);
returnData.push({ json: responseData.data || { message: 'file deleted successfully' } });
break;
}
}
}
catch (error) {
let errorMessage = error instanceof Error ? error.message : 'Unknown error';
// Handle rate limiting (429 responses)
if (error.statusCode === 429 || error.status === 429) {
errorMessage = 'Rate limit exceeded (300 requests/min). Please wait and try again later.';
}
if (this.continueOnFail()) {
returnData.push({
json: { error: errorMessage },
pairedItem: { item: i },
});
}
else {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), errorMessage);
}
}
}
return [returnData];
}
}
exports.Aixyte = Aixyte;