ArchitecturePins

Data Pin

Data pins are the primary mechanism for passing information between nodes in Xentom workflows. They carry actual data values-strings, numbers, objects, arrays-and form the backbone of data flow throughout your automation processes.

Key Characteristics

  • Data Transport: Carry actual information between nodes
  • Type-Safe: Support TypeScript type inference and validation
  • UI Integration: Can include controls for user input
  • Schema Validation: Support Standard Schema specification for data validation
  • Examples: Can provide sample data for users and AI assistance

Basic Usage

import * as i from '@xentom/integration-framework';

// Simple data pin
i.pins.data();

// Data pin with display information
i.pins.data({
  displayName: 'User Email',
  description: 'Email address of the user',
});

// Data pin with control for user input
i.pins.data({
  displayName: 'Message',
  description: 'Message to send to the user',
  control: i.controls.text({
    label: 'Message Content',
    placeholder: 'Enter your message...',
    rows: 3,
  }),
});

Configuration Options

Prop

Type

Controls

Data pins can include controls to allow user input:

Text Input

i.pins.data({
  displayName: 'Email Subject',
  control: i.controls.text({
    label: 'Subject Line',
    placeholder: 'Enter email subject...',
    defaultValue: 'Welcome to our service!',
  }),
});
i.pins.data({
  displayName: 'Task Priority',
  control: i.controls.select({
    label: 'Priority Level',
    options: [
      { value: 'low', label: 'Low Priority' },
      { value: 'medium', label: 'Medium Priority' },
      { value: 'high', label: 'High Priority' },
      { value: 'urgent', label: 'Urgent' },
    ],
    defaultValue: 'medium',
  }),
});

Boolean Toggle

i.pins.data({
  displayName: 'Enable Notifications',
  control: i.controls.switch({
    label: 'Send Email Notifications',
    defaultValue: true,
  }),
});

JavaScript Expression

i.pins.data({
  displayName: 'Data Transform',
  control: i.controls.expression({
    label: 'Transform Logic',
    rows: 6,
    placeholder: 'return data.map(item => ({ ...item, processed: true }))',
  }),
});

Schema Validation

Data pins support schema validation using the Standard Schema specification. For comprehensive examples with Valibot, Zod, ArkType, and detailed documentation, see Schema Validation.

import * as v from 'valibot'; // or any Standard Schema compatible validator

// String validation
i.pins.data({
  displayName: 'Email Address',
  schema: v.pipe(
    v.string(),
    v.email('Please enter a valid email address'),
    v.trim(),
  ),
  control: i.controls.text({
    label: 'Email',
    placeholder: '[email protected]',
  }),
});

Examples

Provide sample data to help users understand expected formats:

i.pins.data({
  displayName: 'API Request Body',
  description: 'JSON data to send in the API request',
  control: i.controls.expression({
    label: 'Request Data',
    rows: 10,
  }),
  examples: [
    {
      title: 'Simple User Creation',
      value: {
        name: 'John Doe',
        email: '[email protected]',
        role: 'user',
      },
    },
    {
      title: 'Bulk User Import',
      value: {
        users: [
          { name: 'Alice Smith', email: '[email protected]' },
          { name: 'Bob Johnson', email: '[email protected]' },
        ],
        sendWelcomeEmail: true,
      },
    },
    {
      title: 'Product Data',
      value: {
        product: {
          name: 'Widget Pro',
          price: 29.99,
          categories: ['electronics', 'gadgets'],
          specifications: {
            weight: '100g',
            dimensions: '10x5x2 cm',
          },
        },
      },
    },
  ],
});

Optional Pins

Optional pins are hidden by default to reduce UI clutter:

// Node definition with optional pins
export const apiCall = i.nodes.callable({
  inputs: {
    // Always visible
    url: i.pins.data({
      control: i.controls.text({
        label: 'API URL',
        placeholder: 'https://api.example.com/endpoint',
      }),
    }),

    // Optional - hidden initially
    headers: i.pins.data({
      displayName: 'Custom Headers',
      description: 'Additional HTTP headers to include',
      optional: true,
      control: i.controls.expression({
        label: 'Headers',
        defaultValue: {
          'Content-Type': 'application/json',
          'User-Agent': 'Xentom-Workflow/1.0',
        },
      }),
    }),

    timeout: i.pins.data({
      displayName: 'Timeout (ms)',
      description: 'Request timeout in milliseconds',
      optional: true,
      control: i.controls.text({
        label: 'Timeout',
        defaultValue: '30000',
      }),
    }),
  },

  // Implementation...
});

Method Chaining

Use the .with() method to extend pin configurations:

// Base pin
const baseEmailPin = i.pins.data({
  schema: v.pipe(v.string(), v.email()),
  control: i.controls.text({
    placeholder: 'Enter email address...',
  }),
});

// Extended versions
const userEmailPin = baseEmailPin.with({
  displayName: 'User Email',
  description: 'Primary email address for the user account',
});

const notificationEmailPin = baseEmailPin.with({
  displayName: 'Notification Email',
  description: 'Email address for system notifications',
  optional: true,
});

Common Patterns

API Configuration

// URL input
i.pins.data({
  displayName: 'API Endpoint',
  description: 'Full URL to the API endpoint',
  control: i.controls.text({
    label: 'URL',
    placeholder: 'https://api.example.com/v1/users',
  }),
  examples: [
    {
      title: 'Users API',
      value: 'https://api.example.com/v1/users',
    },
    {
      title: 'Products API',
      value: 'https://api.example.com/v1/products',
    },
  ],
});

// Headers configuration
i.pins.data({
  displayName: 'HTTP Headers',
  description: 'Key-value pairs for HTTP headers',
  optional: true,
  control: i.controls.expression({
    label: 'Headers',
    defaultValue: {
      Authorization: 'Bearer {{ token }}',
      'Content-Type': 'application/json',
    },
  }),
});

Data Filtering

i.pins.data({
  displayName: 'Filter Criteria',
  description: 'Conditions to filter the dataset',
  control: i.controls.expression({
    label: 'Filter Expression',
    rows: 4,
    placeholder: 'item => item.status === "active" && item.age > 18',
  }),
  examples: [
    {
      title: 'Active Users Only',
      value: 'item => item.status === "active"',
    },
    {
      title: 'Recent Orders',
      value: 'item => new Date(item.createdAt) > new Date("2024-01-01")',
    },
    {
      title: 'High Value Customers',
      value: 'item => item.totalSpent > 1000',
    },
  ],
});

Template Processing

i.pins.data({
  displayName: 'Email Template',
  description: 'Email content with template variables',
  control: i.controls.text({
    label: 'Template',
    rows: 8,
    placeholder: 'Hello {{ user.name }},\n\nWelcome to our service!',
  }),
  examples: [
    {
      title: 'Welcome Email',
      value:
        'Hello {{ user.name }},\n\nThank you for joining our service. Your account is now active!',
    },
    {
      title: 'Order Confirmation',
      value:
        'Order #{{ order.id }} confirmed!\n\nTotal: ${{ order.total }}\nDelivery: {{ order.deliveryDate }}',
    },
  ],
});

Best Practices

Use Descriptive Names

// Good - Clear purpose
i.pins.data({
  displayName: 'User Email Address',
  description: 'Primary email for user communications',
});

// Avoid - Generic names
i.pins.data({
  displayName: 'Data',
});

Provide Helpful Examples

// Good - Multiple realistic examples
i.pins.data({
  examples: [
    {
      title: 'User Creation',
      value: {
        name: 'John',
        email: '[email protected]',
      },
    },
    {
      title: 'Product Update',
      value: {
        id: '123',
        price: 29.99,
        stock: 50,
      },
    },
  ],
});

// Avoid - Single or unclear examples
i.pins.data({
  examples: [
    {
      title: 'Example',
      value: {
        foo: 'bar',
      },
    },
  ],
});

Use Appropriate Controls

// Good - Suitable control for data type
i.pins.data({
  displayName: 'Status',
  control: i.controls.select({
    options: [
      { value: 'active', label: 'Active' },
      { value: 'inactive', label: 'Inactive' },
    ],
  }),
});

// Avoid - Wrong control type
i.pins.data({
  displayName: 'Status',
  control: i.controls.expression(), // Overkill for simple status
});

Leverage Optional Pins

// Good - Optional for advanced features
i.pins.data({
  control: i.controls.expression({
    label: 'Advanced Configuration',
  }),
  optional: true, // Hidden by default
});

Data pins are fundamental to creating powerful, user-friendly integrations in Xentom. They provide the data flow backbone while offering rich configuration options for both simple and complex use cases.

On this page