/** * Sweep expired claims back to the available pool. * * In the implicit-claim model an expired claim is already available at query * time (`assigned_until <= NOW()`), so this is a cosmetic cleanup — but it is * long-tail's public contract (returns a count, clears `assigned_to`) and the * SDK's `releaseExpired()` is a no-op, so it runs as direct SQL on the shared * table. Clears both `assigned_until` and `claim_expires_at`. */ export declare const RELEASE_EXPIRED_CLAIMS = "UPDATE public.hmsh_escalations\nSET assigned_to = NULL,\n assigned_until = NULL,\n claimed_at = NULL,\n claim_expires_at = NULL,\n updated_at = NOW()\nWHERE status = 'pending'\n AND assigned_to IS NOT NULL\n AND assigned_until <= NOW()"; /** Count matching the search WHERE (params $1–$9). */ export declare const COUNT_SEARCH_ESCALATIONS = "SELECT COUNT(*)::int AS total\n FROM public.lt_escalations\n WHERE ($1::text IS NULL OR status = $1)\n AND ($2::text IS NULL OR role = $2)\n AND ($3::text[] IS NULL OR role = ANY($3))\n AND ($4::text IS NULL OR type = $4)\n AND ($5::text IS NULL OR subtype = $5)\n AND ($6::int IS NULL OR priority = $6)\n AND ($7::text IS NULL OR assigned_to = $7)\n AND ($8::boolean IS NULL OR available = $8)\n AND ($9::text IS NULL OR (\n description ILIKE '%' || $9 || '%'\n OR type ILIKE '%' || $9 || '%'\n OR subtype ILIKE '%' || $9 || '%'\n OR role ILIKE '%' || $9 || '%'\n OR workflow_id ILIKE '%' || $9 || '%'\n OR origin_id ILIKE '%' || $9 || '%'\n OR id::text ILIKE '%' || $9 || '%'\n OR metadata::text ILIKE '%' || $9 || '%'\n ))"; /** * Build the search SELECT. `orderBy` is composed from a whitelist by the caller * (never raw user input), so it is safe to interpolate; everything else is bound. */ export declare function searchEscalationsQuery(orderBy: string): string; /** * Atomic resolve by metadata with signal guard. * * Single query, four outcomes: * 1. No signal backing → claim + resolve atomically. `resolved` is populated. * 2. `metadata.signal_id` present, row unclaimed → claim the row (preventing concurrent * duplicate signals via FOR UPDATE serialization), then return signal info so the * caller can signal the workflow. `signal_already_claimed = false`. * 3. `metadata.signal_id` present, row already claimed and claim not expired → * a concurrent caller is handling the signal. `signal_already_claimed = true`; * caller returns 409 without re-signaling. * 4. `signal_key` present (atomic conditionLT) → `claimed` and `resolved` both skip. * Caller invokes SDK resolve to atomically mark resolved + deliver the signal. * * Signal_id hardening: the `claimed` CTE runs for signal_id rows (previously excluded). * This stamps `assigned_to` on the row inside the FOR UPDATE transaction, so a * concurrent second caller sees `signal_already_claimed = true` and aborts. * The `resolved` CTE still skips signal_id rows — the workflow resolves durably. * * $1 = metadata filter (jsonb), $2 = userId, $3 = resolver_payload (jsonb), * $4 = metadata patch (jsonb, nullable), $5 = allowed roles (text[], null = no filter) */ export declare const RESOLVE_BY_METADATA_ATOMIC = "WITH target AS MATERIALIZED (\n SELECT *\n FROM public.hmsh_escalations\n WHERE metadata @> $1::jsonb\n AND status = 'pending'\n AND ($5::text[] IS NULL OR role = ANY($5))\n ORDER BY priority ASC, created_at ASC\n LIMIT 1\n FOR UPDATE\n),\nclaimed AS (\n UPDATE public.hmsh_escalations e\n SET assigned_to = COALESCE(e.assigned_to, $2),\n claimed_at = COALESCE(e.claimed_at, NOW()),\n assigned_until = CASE\n WHEN e.assigned_to IS NOT NULL AND e.assigned_until > NOW() THEN e.assigned_until\n ELSE NOW() + INTERVAL '5 minutes' END,\n claim_expires_at = CASE\n WHEN e.assigned_to IS NOT NULL AND e.assigned_until > NOW() THEN e.claim_expires_at\n ELSE NOW() + INTERVAL '5 minutes' END,\n metadata = CASE WHEN $4::jsonb IS NOT NULL\n THEN COALESCE(e.metadata, '{}'::jsonb) || $4::jsonb\n ELSE e.metadata END,\n updated_at = NOW()\n FROM target\n WHERE e.id = target.id\n AND target.signal_key IS NULL\n RETURNING e.*\n),\nresolved AS (\n UPDATE public.hmsh_escalations e\n SET status = 'resolved',\n resolved_at = NOW(),\n resolver_payload = $3,\n updated_at = NOW()\n FROM claimed\n WHERE e.id = claimed.id\n AND (claimed.metadata->>'signal_id') IS NULL\n RETURNING e.*\n)\nSELECT\n resolved.*,\n target.id AS target_id,\n target.metadata->>'signal_id' AS signal_id,\n target.signal_key AS signal_key,\n target.workflow_id AS target_workflow_id,\n target.workflow_type AS target_workflow_type,\n target.task_queue AS target_task_queue,\n (target.assigned_to IS NOT NULL\n AND target.assigned_until IS NOT NULL\n AND target.assigned_until > NOW()) AS signal_already_claimed,\n CASE WHEN resolved.id IS NOT NULL THEN 'resolved' ELSE 'signal_required' END AS outcome\nFROM target\nLEFT JOIN resolved ON resolved.id = target.id";