PSA/shared/workflow/runtime/schemas/inboundWebhookSchemas.ts
Hermes 284313f908
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
Initial import of AlgaPSA codebase from PSA server
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz

Source: /opt/alga-psa on psa.joliet.tech
2026-06-22 16:12:17 -05:00

81 lines
3.5 KiB
TypeScript

import { z } from 'zod';
/**
* Headers carried by the inbound webhook envelope. Sensitive headers (authorization,
* cookie, set-cookie, proxy-authorization, x-api-key) are stripped server-side.
*/
const inboundWebhookHeadersSchema = z
.record(z.union([z.string(), z.array(z.string())]))
.describe('Filtered request headers from the incoming request');
/**
* Common nested shape for monitoring-style payloads (RMM alerts, SIEM events, etc.).
* Catchall on every level keeps the schema permissive — any payload field can still be
* passed through — while exposing the common keys so the workflow designer's reference
* picker can drill into payload.body.alert.<field> directly.
*/
const inboundWebhookAlertSchema = z
.object({
id: z.string().optional().describe('External alert identifier'),
ticket_number: z.string().optional().describe('Alga ticket number to target'),
ticket_external_ref: z.string().optional().describe('External reference of an Alga ticket'),
severity: z.string().optional().describe('Alert severity / priority'),
subject: z.string().optional().describe('Alert subject or short title'),
body: z.string().optional().describe('Alert body / detail text'),
source: z.string().optional().describe('Originating source identifier'),
device: z
.object({
hostname: z.string().optional().describe('Device hostname'),
ip: z.string().optional().describe('Device IP address'),
external_id: z.string().optional().describe('External device identifier'),
})
.catchall(z.unknown())
.optional()
.describe('Device or asset context, if the alert is asset-bound'),
})
.catchall(z.unknown())
.describe('Common alert payload shape');
const inboundWebhookEventSchema = z
.object({
type: z.string().optional().describe('Event type identifier'),
id: z.string().optional().describe('External event identifier'),
})
.catchall(z.unknown())
.describe('Common event payload shape');
/**
* Envelope delivered to workflows when an inbound webhook fires with handler_type='workflow'.
* Mirrors the `WorkflowWebhookEnvelope` type in
* `server/src/lib/inboundWebhooks/types.ts`.
*
* `body` is shaped as a permissive object with two common nested shapes (`alert`, `event`)
* pre-typed so the workflow designer's reference picker can drill into typical RMM /
* SIEM / alerting payloads. Catchall(unknown) on every level means non-conforming
* payloads still pass through unchanged.
*/
export const inboundWebhookBodySchema = z
.object({
alert: inboundWebhookAlertSchema.optional(),
event: inboundWebhookEventSchema.optional(),
})
.catchall(z.unknown())
.describe('Parsed JSON request body as received from the external system');
export const inboundWebhookReceivedEventPayloadSchema = z
.object({
source: z.string().describe('Inbound webhook slug that received the request'),
body: inboundWebhookBodySchema,
headers: inboundWebhookHeadersSchema,
verified: z.literal(true).describe('Always true; auth verification has already passed'),
delivery_id: z.string().uuid().describe('Inbound webhook delivery row UUID'),
idempotency_key: z
.string()
.nullable()
.describe('Idempotency key extracted from header or JSONata expression, or null'),
received_at: z.string().datetime().describe('ISO timestamp when the request was received'),
})
.describe('Payload for INBOUND_WEBHOOK_RECEIVED');
export type InboundWebhookReceivedEventPayload = z.infer<typeof inboundWebhookReceivedEventPayloadSchema>;