Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
170 lines
7.7 KiB
TypeScript
170 lines
7.7 KiB
TypeScript
import { z } from 'zod';
|
|
import { BaseDomainEventPayloadSchema } from './commonEventPayloadSchemas';
|
|
|
|
/**
|
|
* Schema for email sender/recipient address
|
|
*/
|
|
const emailAddressSchema = z.object({
|
|
email: z.string().email().describe('Email address'),
|
|
name: z.string().optional().describe('Display name')
|
|
}).describe('Email address with optional display name');
|
|
|
|
/**
|
|
* Schema for email body content
|
|
*/
|
|
const emailBodySchema = z.object({
|
|
text: z.string().optional().describe('Plain text content'),
|
|
html: z.string().optional().describe('HTML content')
|
|
}).describe('Email body in text and/or HTML format');
|
|
|
|
/**
|
|
* Schema for email attachment metadata
|
|
*/
|
|
const emailAttachmentSchema = z.object({
|
|
id: z.string().describe('Attachment ID'),
|
|
name: z.string().describe('Filename'),
|
|
contentType: z.string().describe('MIME content type'),
|
|
size: z.number().int().positive().describe('Size in bytes'),
|
|
contentId: z.string().optional().describe('Content-ID for inline attachments')
|
|
}).describe('Email attachment metadata');
|
|
|
|
/**
|
|
* Schema for inbound email data - the core email information
|
|
*/
|
|
const emailDataSchema = z.object({
|
|
id: z.string().describe('Email message ID'),
|
|
mailhogId: z.string().optional().describe('Mailhog ID (for testing)'),
|
|
threadId: z.string().optional().describe('Email thread ID'),
|
|
from: emailAddressSchema.describe('Sender address'),
|
|
to: z.array(emailAddressSchema).optional().describe('Recipients'),
|
|
cc: z.array(emailAddressSchema).optional().describe('CC recipients'),
|
|
bcc: z.array(emailAddressSchema).optional().describe('BCC recipients'),
|
|
subject: z.string().describe('Email subject line'),
|
|
body: emailBodySchema.describe('Email body content'),
|
|
inReplyTo: z.string().optional().describe('In-Reply-To header (for threading)'),
|
|
references: z.array(z.string()).optional().describe('References header values'),
|
|
attachments: z.array(emailAttachmentSchema).optional().describe('Email attachments'),
|
|
receivedAt: z.string().optional().describe('When the email was received (ISO 8601)'),
|
|
tenant: z.string().optional().describe('Tenant ID'),
|
|
providerId: z.string().optional().describe('Email provider ID')
|
|
}).describe('Inbound email data from the email provider');
|
|
|
|
/**
|
|
* Schema for parsed email reply result
|
|
*/
|
|
const parsedEmailSchema = z.object({
|
|
sanitizedText: z.string().describe('Cleaned text without quoted content'),
|
|
sanitizedHtml: z.string().optional().describe('Cleaned HTML content'),
|
|
confidence: z.enum(['high', 'medium', 'low']).describe('Parser confidence'),
|
|
metadata: z.object({
|
|
parser: z.object({
|
|
confidence: z.enum(['high', 'medium', 'low']).optional(),
|
|
strategy: z.string().optional().describe('Parsing strategy used'),
|
|
heuristics: z.array(z.string()).optional().describe('Applied heuristics'),
|
|
warnings: z.array(z.string()).optional().describe('Parser warnings'),
|
|
tokens: z.object({
|
|
conversationToken: z.string().optional().describe('Reply token')
|
|
}).optional()
|
|
}).optional()
|
|
}).optional().describe('Parser metadata')
|
|
}).describe('Parsed email content with quoted text removed');
|
|
|
|
/**
|
|
* Schema for existing ticket match
|
|
*/
|
|
const existingTicketSchema = z.object({
|
|
ticketId: z.string().describe('Ticket ID'),
|
|
ticketNumber: z.string().optional().describe('Ticket number'),
|
|
subject: z.string().optional().describe('Ticket subject'),
|
|
status: z.string().optional().describe('Current status')
|
|
}).describe('Existing ticket matched via threading');
|
|
|
|
/**
|
|
* Schema for matched client/contact
|
|
*/
|
|
const matchedClientSchema = z.object({
|
|
clientId: z.string().optional().describe('Client ID'),
|
|
clientName: z.string().optional().describe('Client name'),
|
|
contactId: z.string().optional().describe('Contact ID'),
|
|
contactName: z.string().optional().describe('Contact name'),
|
|
primaryEmail: z.string().email().optional().describe('Primary/default contact email from contacts.email'),
|
|
matchedEmail: z.string().email().optional().describe('Exact sender email that matched the contact lookup')
|
|
}).describe('Client/contact matched from email address');
|
|
|
|
/**
|
|
* Schema for ticket defaults
|
|
*/
|
|
const ticketDefaultsSchema = z.object({
|
|
board_id: z.string().optional().describe('Default board ID'),
|
|
status_id: z.string().optional().describe('Default status ID'),
|
|
priority_id: z.string().optional().describe('Default priority ID'),
|
|
client_id: z.string().optional().describe('Default client ID'),
|
|
entered_by: z.string().optional().describe('Default entered_by user'),
|
|
category_id: z.string().optional().describe('Default category ID'),
|
|
subcategory_id: z.string().optional().describe('Default subcategory ID'),
|
|
location_id: z.string().optional().describe('Default location ID')
|
|
}).describe('Default values for ticket creation');
|
|
|
|
/**
|
|
* Main email workflow payload schema
|
|
* This represents ONLY the trigger input - data available from the start.
|
|
* Step outputs (parsedEmail, matchedClient, ticketDefaults, etc.) should be
|
|
* accessed via step output references, not the payload.
|
|
*/
|
|
export const emailWorkflowPayloadSchema = z.object({
|
|
emailData: emailDataSchema.describe('The inbound email data from the trigger event'),
|
|
providerId: z.string().describe('Email provider ID'),
|
|
tenantId: z.string().describe('Tenant ID')
|
|
});
|
|
|
|
export type EmailWorkflowPayload = z.infer<typeof emailWorkflowPayloadSchema>;
|
|
|
|
// =============================================================================
|
|
// EVENT PAYLOAD SCHEMAS - for use with event catalog + simulation
|
|
// =============================================================================
|
|
|
|
const emailProviderTypeSchema = z.enum(['microsoft', 'google']).describe('Email provider type');
|
|
|
|
export const inboundEmailReceivedEventPayloadSchema = BaseDomainEventPayloadSchema.extend({
|
|
emailData: emailDataSchema.describe('The inbound email data from the event'),
|
|
providerId: z.string().describe('Email provider ID')
|
|
}).describe('Payload for INBOUND_EMAIL_RECEIVED');
|
|
|
|
export type InboundEmailReceivedEventPayload = z.infer<typeof inboundEmailReceivedEventPayloadSchema>;
|
|
|
|
export const emailProviderConnectedEventPayloadSchema = BaseDomainEventPayloadSchema.extend({
|
|
providerId: z.string().describe('Email provider configuration ID'),
|
|
providerType: emailProviderTypeSchema,
|
|
providerName: z.string().describe('Human-friendly provider name'),
|
|
mailbox: z.string().email().describe('Mailbox email address being monitored'),
|
|
connectedAt: z.string().describe('Timestamp when connection was established (ISO 8601)')
|
|
}).describe('Payload for EMAIL_PROVIDER_CONNECTED');
|
|
|
|
export type EmailProviderConnectedEventPayload = z.infer<typeof emailProviderConnectedEventPayloadSchema>;
|
|
|
|
export const emailProviderDisconnectedEventPayloadSchema = BaseDomainEventPayloadSchema.extend({
|
|
providerId: z.string().describe('Email provider configuration ID'),
|
|
providerType: emailProviderTypeSchema,
|
|
providerName: z.string().describe('Human-friendly provider name'),
|
|
disconnectedAt: z.string().describe('Timestamp when disconnection occurred (ISO 8601)'),
|
|
reason: z.string().optional().describe('Reason for disconnection (manual, error, token_expired, etc.)')
|
|
}).describe('Payload for EMAIL_PROVIDER_DISCONNECTED');
|
|
|
|
export type EmailProviderDisconnectedEventPayload = z.infer<typeof emailProviderDisconnectedEventPayloadSchema>;
|
|
|
|
// =============================================================================
|
|
// STEP OUTPUT SCHEMAS - for use with action outputSchema definitions
|
|
// =============================================================================
|
|
|
|
/** Output schema for parse_email_reply action */
|
|
export { parsedEmailSchema };
|
|
|
|
/** Output schema for find_ticket_by_email_thread action */
|
|
export { existingTicketSchema };
|
|
|
|
/** Output schema for find_contact_by_email / client matching */
|
|
export { matchedClientSchema };
|
|
|
|
/** Output schema for resolve_inbound_ticket_defaults action */
|
|
export { ticketDefaultsSchema };
|