This directory contains a consolidated extractor system for all types of Attio attribute values. The extractors convert Attio API data into human-readable strings for display in Slack notifications.
Import and use the single extractor function:
import { extractAttributeValue } from "./extractors/index.ts";
const extractedValue = await extractAttributeValue(attributeValue);
The extractor system uses a registry pattern where all extractors are defined in a single object and automatically selected based on the attribute type. This provides:
- Type Safety: Each extractor is properly typed for its specific attribute type
- Automatic Selection: No need to manually choose which extractor to use
- Centralized Management: All extractors are defined in one place
- No Setup Required: All extractors are available immediately
The system automatically handles all Attio attribute types:
text
- Simple text valuesstatus
- Status values with titlesselect
- Dropdown/select values with option titlesdate
- Date valuestimestamp
- Timestamp valuesrating
- Numeric rating valuescheckbox
- Boolean checkbox valuescurrency
- Currency values with proper formattingrecord-reference
- References to other records (fetches record name)actor-reference
- References to users/actors (fetches actor name)
domain
- Domain valuesemail-address
- Email address valuesinteraction
- Interaction values with type and timestamplocation
- Location values with address formattingnumber
- Numeric valuespersonal-name
- Personal name valuesphone-number
- Phone number values
You can override existing extractors using the overrideExtractors()
function:
import { overrideExtractors } from "./extractors/index.ts";
// Override text formatting with fancy styling
overrideExtractors({
text: (value) => `✨ ${value.value} ✨`,
});
// Override status formatting
overrideExtractors({
status: (value) => `🔸 ${value.status.title}`,
});
// Override currency formatting
overrideExtractors({
currency: (value) =>
`💰 ${Intl.NumberFormat("en-US", {
style: "currency",
currency: value.currency_code,
}).format(Number(value.currency_value))}`,
});
The overrideExtractors()
function only accepts valid Attio attribute types. This prevents typos and ensures type safety:
import { overrideExtractors } from "./extractors/index.ts";
// ✅ Valid - these are real Attio attribute types
overrideExtractors({
text: (value) => `✨ ${value.value} ✨`,
status: (value) => `🔸 ${value.status.title}`,
});
// ❌ Invalid - will throw an error
overrideExtractors({
"custom-type": (value) => value.custom_field, // Error: Invalid attribute type
});
The best place to add extractor customizations depends on your use case:
// webhook.ts or main.ts
import { overrideExtractors } from "./extractors/index.ts";
// Override extractors at startup
overrideExtractors({
text: (value) => `✨ ${value.value} ✨`,
});
// ... rest of your application
// config/extractors.ts
import { overrideExtractors } from "../extractors/index.ts";
export function setupCustomExtractors() {
overrideExtractors({
text: (value) => `✨ ${value.value} ✨`,
status: (value) => `🔸 ${value.status.title}`,
});
}
// Then call setupCustomExtractors() in your main file
// In your webhook handler
import { overrideExtractors } from "./extractors/index.ts";
import type { AttioAttributeValue } from "./shared/types.ts";
export async function handleWebhook(
req: Request,
customExtractors?: Partial<{
[K in AttioAttributeValue["attribute_type"]]: (
value: Extract<AttioAttributeValue, { attribute_type: K }>
) => string | Promise<string>;
}>
) {
if (customExtractors) {
overrideExtractors(customExtractors);
}
// ... rest of webhook handling
}
The current implementation doesn't include a reset function. If you need to reset to defaults, you can restart your application or manually override with default values.
import { extractAttributeValue } from "./extractors/index.ts";
// Text value
const textValue = await extractAttributeValue({
attribute_type: "text",
value: "Hello World",
// ... other properties
});
// Returns: "Hello World"
// Status value
const statusValue = await extractAttributeValue({
attribute_type: "status",
status: { title: "Active" /* ... */ },
// ... other properties
});
// Returns: "Active"
// Currency value
const currencyValue = await extractAttributeValue({
attribute_type: "currency",
currency_value: 1234.56,
currency_code: "USD",
// ... other properties
});
// Returns: "$1,234.56"
// Domain value
const domainValue = await extractAttributeValue({
attribute_type: "domain",
domain: "example.com",
// ... other properties
});
// Returns: "example.com"
// Email value
const emailValue = await extractAttributeValue({
attribute_type: "email-address",
email_address: "user@example.com",
// ... other properties
});
// Returns: "user@example.com"
// Location value
const locationValue = await extractAttributeValue({
attribute_type: "location",
line_1: "123 Main St",
locality: "San Francisco",
region: "CA",
country_code: "US",
// ... other properties
});
// Returns: "123 Main St, San Francisco, CA, US"
// Phone number value
const phoneValue = await extractAttributeValue({
attribute_type: "phone-number",
original_phone_number: "+1-555-123-4567",
// ... other properties
});
// Returns: "+1-555-123-4567"
// Personal name value
const nameValue = await extractAttributeValue({
attribute_type: "personal-name",
full_name: "John Doe",
// ... other properties
});
// Returns: "John Doe"