link-stack/apps/bridge-worker/lib/common.ts
Darren Clarke c1feaa4cb1 feat: Add centralized logging system with @link-stack/logger package
- Create new @link-stack/logger package wrapping Pino for structured logging
- Replace all console.log/error/warn statements across the monorepo
- Configure environment-aware logging (pretty-print in dev, JSON in prod)
- Add automatic redaction of sensitive fields (passwords, tokens, etc.)
- Remove dead commented-out logger file from bridge-worker
- Follow Pino's standard argument order (context object first, message second)
- Support log levels via LOG_LEVEL environment variable
- Export TypeScript types for better IDE support

This provides consistent, structured logging across all applications
and packages, making debugging easier and production logs more parseable.
2025-08-20 11:37:39 +02:00

73 lines
2.2 KiB
TypeScript

/* eslint-disable camelcase */
// import { SavedVoiceProvider } from "@digiresilience/bridge-db";
import Twilio from "twilio";
import { CallInstance } from "twilio/lib/rest/api/v2010/account/call";
import { Zammad, getOrCreateUser } from "./zammad.js";
import { createLogger } from "@link-stack/logger";
const logger = createLogger('bridge-worker-common');
type SavedVoiceProvider = any;
export const twilioClientFor = (
provider: SavedVoiceProvider,
): Twilio.Twilio => {
const { accountSid, apiKeySid, apiKeySecret } = provider.credentials;
if (!accountSid || !apiKeySid || !apiKeySecret)
throw new Error(
`twilio provider ${provider.name} does not have credentials`,
);
return Twilio(apiKeySid, apiKeySecret, {
accountSid,
});
};
export const createZammadTicket = async (
call: CallInstance,
mp3: Buffer,
): Promise<void> => {
const title = `Call from ${call.fromFormatted} at ${call.startTime}`;
const body = `<ul>
<li>Caller: ${call.fromFormatted}</li>
<li>Service Number: ${call.toFormatted}</li>
<li>Call Duration: ${call.duration} seconds</li>
<li>Start Time: ${call.startTime}</li>
<li>End Time: ${call.endTime}</li>
</ul>
<p>See the attached recording.</p>`;
const filename = `${call.sid}-${call.startTime}.mp3`;
const zammad = Zammad(
{
token: "EviH_WL0p6YUlCoIER7noAZEAPsYA_fVU4FZCKdpq525Vmzzvl8d7dNuP_8d-Amb",
},
"https://demo.digiresilience.org",
);
try {
const customer = await getOrCreateUser(zammad, call.fromFormatted);
await zammad.ticket.create({
title,
group: "Finances",
note: "This ticket was created automaticaly from a recorded phone call.",
customer_id: customer.id,
article: {
body,
subject: title,
content_type: "text/html",
type: "note",
attachments: [
{
filename,
data: mp3.toString("base64"),
"mime-type": "audio/mpeg",
},
],
},
});
} catch (error: any) {
if (error.isBoom) {
logger.error({ output: error.output }, 'Zammad ticket creation failed');
throw new Error("Failed to create zamamd ticket");
}
}
};