diff --git a/apps/bridge-frontend/app/(main)/[...segment]/@create/page.tsx b/apps/bridge-frontend/app/(main)/[...segment]/@create/page.tsx index 3973926..bc5b6b8 100644 --- a/apps/bridge-frontend/app/(main)/[...segment]/@create/page.tsx +++ b/apps/bridge-frontend/app/(main)/[...segment]/@create/page.tsx @@ -1,10 +1,11 @@ import { Create } from "@link-stack/bridge-ui"; type PageProps = { - params: { segment: string[] }; + params: Promise<{ segment: string[] }>; }; -export default function Page({ params: { segment } }: PageProps) { +export default async function Page({ params }: PageProps) { + const { segment } = await params; const service = segment[0]; return ; diff --git a/apps/bridge-frontend/app/(main)/[...segment]/@detail/page.tsx b/apps/bridge-frontend/app/(main)/[...segment]/@detail/page.tsx index 0b1f49c..e857b7d 100644 --- a/apps/bridge-frontend/app/(main)/[...segment]/@detail/page.tsx +++ b/apps/bridge-frontend/app/(main)/[...segment]/@detail/page.tsx @@ -1,11 +1,12 @@ import { db } from "@link-stack/bridge-common"; import { serviceConfig, Detail } from "@link-stack/bridge-ui"; -type Props = { - params: { segment: string[] }; +type PageProps = { + params: Promise<{ segment: string[] }>; }; -export default async function Page({ params: { segment } }: Props) { +export default async function Page({ params }: PageProps) { + const { segment } = await params; const service = segment[0]; const id = segment?.[1]; diff --git a/apps/bridge-frontend/app/(main)/[...segment]/@edit/page.tsx b/apps/bridge-frontend/app/(main)/[...segment]/@edit/page.tsx index 59977eb..82c8052 100644 --- a/apps/bridge-frontend/app/(main)/[...segment]/@edit/page.tsx +++ b/apps/bridge-frontend/app/(main)/[...segment]/@edit/page.tsx @@ -2,10 +2,11 @@ import { db } from "@link-stack/bridge-common"; import { serviceConfig, Edit } from "@link-stack/bridge-ui"; type PageProps = { - params: { segment: string[] }; + params: Promise<{ segment: string[] }>; }; -export default async function Page({ params: { segment } }: PageProps) { +export default async function Page({ params }: PageProps) { + const { segment } = await params; const service = segment[0]; const id = segment?.[1]; diff --git a/apps/bridge-frontend/app/(main)/[...segment]/page.tsx b/apps/bridge-frontend/app/(main)/[...segment]/page.tsx index e248a86..7b4fc03 100644 --- a/apps/bridge-frontend/app/(main)/[...segment]/page.tsx +++ b/apps/bridge-frontend/app/(main)/[...segment]/page.tsx @@ -2,12 +2,13 @@ import { db } from "@link-stack/bridge-common"; import { serviceConfig, List } from "@link-stack/bridge-ui"; type PageProps = { - params: { + params: Promise<{ segment: string[]; - }; + }>; }; -export default async function Page({ params: { segment } }: PageProps) { +export default async function Page({ params }: PageProps) { + const { segment } = await params; const service = segment[0]; if (!service) return null; diff --git a/apps/bridge-frontend/package.json b/apps/bridge-frontend/package.json index b5797a6..1d7d21e 100644 --- a/apps/bridge-frontend/package.json +++ b/apps/bridge-frontend/package.json @@ -1,6 +1,6 @@ { "name": "@link-stack/bridge-frontend", - "version": "2.2.0", + "version": "3.1.0", "type": "module", "scripts": { "dev": "next dev", @@ -13,28 +13,30 @@ "migrate:down:one": "tsx database/migrate.ts down:one" }, "dependencies": { - "@auth/kysely-adapter": "^1.5.2", + "@auth/kysely-adapter": "^1.7.4", + "@mui/icons-material": "^6", + "@mui/material": "^6", + "@mui/material-nextjs": "^6", + "@mui/x-license": "^7.26.0", "@link-stack/bridge-common": "*", "@link-stack/bridge-ui": "*", - "@link-stack/ui": "*", - "@mui/icons-material": "^5", - "@mui/material": "^5", - "@mui/material-nextjs": "^5", - "@mui/x-license": "^7.18.0", - "next": "^14.2.23", - "next-auth": "^4.24.8", - "react": "18.3.1", - "react-dom": "18.3.1", + "next": "15.1.7", + "next-auth": "^4.24.11", + "react": "19.0.0", + "react-dom": "19.0.0", "sharp": "^0.33.5", - "tsx": "^4.19.1" + "tsx": "^4.19.3", + "@link-stack/ui": "*" }, "devDependencies": { "@link-stack/eslint-config": "*", "@link-stack/typescript-config": "*", "@types/node": "^22", - "@types/pg": "^8.11.10", - "@types/react": "^18", - "@types/react-dom": "^18", + "@types/pg": "^8.11.11", + "@types/react": "^19", + "@types/react-dom": "^19", + "@link-stack/eslint-config": "*", + "@link-stack/typescript-config": "*", "typescript": "^5" } } diff --git a/apps/bridge-frontend/public/robots.txt b/apps/bridge-frontend/public/robots.txt new file mode 100644 index 0000000..1f53798 --- /dev/null +++ b/apps/bridge-frontend/public/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: / diff --git a/apps/bridge-frontend/tsconfig.json b/apps/bridge-frontend/tsconfig.json index e700859..22be23b 100644 --- a/apps/bridge-frontend/tsconfig.json +++ b/apps/bridge-frontend/tsconfig.json @@ -1,6 +1,10 @@ { "compilerOptions": { - "lib": ["dom", "dom.iterable", "esnext"], + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], "allowJs": true, "skipLibCheck": true, "strict": true, @@ -14,14 +18,24 @@ "jsx": "preserve", "incremental": true, "paths": { - "@/*": ["./*"] + "@/*": [ + "./*" + ] }, "plugins": [ { "name": "next" } - ] + ], + "target": "ES2017" }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], - "exclude": ["node_modules"] + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts" + ], + "exclude": [ + "node_modules" + ] } diff --git a/apps/bridge-migrations/migrate.ts b/apps/bridge-migrations/migrate.ts index 2e6281b..d06b606 100644 --- a/apps/bridge-migrations/migrate.ts +++ b/apps/bridge-migrations/migrate.ts @@ -72,7 +72,7 @@ export const migrate = async (arg: string) => { results?.forEach((it) => { if (it.status === "Success") { - console.log( + console.info( `Migration "${it.migrationName} ${it.direction.toLowerCase()}" was executed successfully`, ); } else if (it.status === "Error") { diff --git a/apps/bridge-migrations/package.json b/apps/bridge-migrations/package.json index c3a10b6..369801d 100644 --- a/apps/bridge-migrations/package.json +++ b/apps/bridge-migrations/package.json @@ -1,6 +1,6 @@ { "name": "@link-stack/bridge-migrations", - "version": "2.2.0", + "version": "3.1.0", "type": "module", "scripts": { "migrate:up:all": "tsx migrate.ts up:all", @@ -9,14 +9,14 @@ "migrate:down:one": "tsx migrate.ts down:one" }, "dependencies": { - "dotenv": "^16.4.5", - "kysely": "0.26.1", - "pg": "^8.13.0", - "tsx": "^4.19.1" + "dotenv": "^16.4.7", + "kysely": "0.27.5", + "pg": "^8.13.3", + "tsx": "^4.19.3" }, "devDependencies": { "@types/node": "^22", - "@types/pg": "^8.11.10", + "@types/pg": "^8.11.11", "@link-stack/eslint-config": "*", "@link-stack/typescript-config": "*", "typescript": "^5" diff --git a/apps/bridge-whatsapp/package.json b/apps/bridge-whatsapp/package.json index a998164..0999ce1 100644 --- a/apps/bridge-whatsapp/package.json +++ b/apps/bridge-whatsapp/package.json @@ -1,26 +1,26 @@ { "name": "@link-stack/bridge-whatsapp", - "version": "2.2.0", + "version": "3.1.0", "main": "build/main/index.js", "author": "Darren Clarke ", "license": "AGPL-3.0-or-later", "dependencies": { "@adiwajshing/keyed-db": "0.2.4", - "@hapi/hapi": "^21.3.10", + "@hapi/hapi": "^21.3.12", "@hapipal/schmervice": "^3.0.0", "@hapipal/toys": "^4.0.0", - "@whiskeysockets/baileys": "^6.7.8", + "@whiskeysockets/baileys": "^6.7.13", "hapi-pino": "^12.1.0", - "link-preview-js": "^3.0.5" + "link-preview-js": "^3.0.14" }, "devDependencies": { "@link-stack/eslint-config": "*", "@link-stack/jest-config": "*", "@link-stack/typescript-config": "*", "@types/node": "*", - "dotenv-cli": "^7.4.2", - "tsx": "^4.19.1", - "typescript": "^5.6.2" + "dotenv-cli": "^8.0.0", + "tsx": "^4.19.3", + "typescript": "^5.7.3" }, "scripts": { "build": "tsc -p tsconfig.json", diff --git a/apps/bridge-whatsapp/src/routes.ts b/apps/bridge-whatsapp/src/routes.ts index 10c9757..9219bf0 100644 --- a/apps/bridge-whatsapp/src/routes.ts +++ b/apps/bridge-whatsapp/src/routes.ts @@ -26,7 +26,6 @@ export const SendMessageRoute = withDefaults({ description: "Send a message", async handler(request: Hapi.Request, _h: Hapi.ResponseToolkit) { const { id } = request.params; - console.log({ payload: request.payload }); const { phoneNumber, message } = request.payload as MessageRequest; const whatsappService = getService(request); await whatsappService.send(id, phoneNumber, message as string); diff --git a/apps/bridge-whatsapp/src/service.ts b/apps/bridge-whatsapp/src/service.ts index 4f6eafa..1fcc881 100644 --- a/apps/bridge-whatsapp/src/service.ts +++ b/apps/bridge-whatsapp/src/service.ts @@ -57,7 +57,7 @@ export default class WhatsappService extends Service { try { connection.end(null); } catch (error) { - console.log(error); + console.error(error); } } this.connections = {}; @@ -92,27 +92,27 @@ export default class WhatsappService extends Service { isNewLogin, } = update; if (qr) { - console.log("got qr code"); + console.info("got qr code"); const botDirectory = this.getBotDirectory(botID); const qrPath = `${botDirectory}/qr.txt`; fs.writeFileSync(qrPath, qr, "utf8"); } else if (isNewLogin) { - console.log("got new login"); + console.info("got new login"); const botDirectory = this.getBotDirectory(botID); const verifiedFile = `${botDirectory}/verified`; fs.writeFileSync(verifiedFile, ""); } else if (connectionState === "open") { - console.log("opened connection"); + console.info("opened connection"); } else if (connectionState === "close") { - console.log("connection closed due to ", lastDisconnect?.error); + console.info("connection closed due to ", lastDisconnect?.error); const disconnectStatusCode = (lastDisconnect?.error as any)?.output ?.statusCode; if (disconnectStatusCode === DisconnectReason.restartRequired) { - console.log("reconnecting after got new login"); + console.info("reconnecting after got new login"); await this.createConnection(botID, server, options); authCompleteCallback?.(); } else if (disconnectStatusCode !== DisconnectReason.loggedOut) { - console.log("reconnecting"); + console.info("reconnecting"); await this.sleep(pause); pause *= 2; this.createConnection(botID, server, options); @@ -121,12 +121,12 @@ export default class WhatsappService extends Service { } if (events["creds.update"]) { - console.log("creds update"); + console.info("creds update"); await saveCreds(); } if (events["messages.upsert"]) { - console.log("messages upsert"); + console.info("messages upsert"); const upsert = events["messages.upsert"]; const { messages } = upsert; if (messages) { @@ -143,13 +143,13 @@ export default class WhatsappService extends Service { const baseDirectory = this.getBaseDirectory(); const botIDs = fs.readdirSync(baseDirectory); - console.log({ botIDs }); + for await (const botID of botIDs) { const directory = this.getBotDirectory(botID); const verifiedFile = `${directory}/verified`; if (fs.existsSync(verifiedFile)) { const { version, isLatest } = await fetchLatestBaileysVersion(); - console.log(`using WA v${version.join(".")}, isLatest: ${isLatest}`); + console.info(`using WA v${version.join(".")}, isLatest: ${isLatest}`); await this.createConnection(botID, this.server, { browser: WhatsappService.browserDescription, @@ -169,7 +169,10 @@ export default class WhatsappService extends Service { message, messageTimestamp, } = webMessageInfo; - console.log(webMessageInfo); + console.info("Message type debug"); + for (const key in message) { + console.info(key, !!message[key as keyof proto.IMessage]); + } const isValidMessage = message && remoteJid !== "status@broadcast" && !fromMe; if (isValidMessage) { diff --git a/apps/bridge-worker/graphile.config.ts b/apps/bridge-worker/graphile.config.ts index 8b550c7..9367a65 100644 --- a/apps/bridge-worker/graphile.config.ts +++ b/apps/bridge-worker/graphile.config.ts @@ -4,8 +4,12 @@ import type {} from "graphile-worker"; const preset: GraphileConfig.Preset = { worker: { connectionString: process.env.DATABASE_URL, - maxPoolSize: 10, - pollInterval: 2000, + maxPoolSize: process.env.BRIDGE_WORKER_POOL_SIZE + ? parseInt(process.env.BRIDGE_WORKER_POOL_SIZE, 10) + : 10, + pollInterval: process.env.BRIDGE_WORKER_POLL_INTERVAL + ? parseInt(process.env.BRIDGE_WORKER_POLL_INTERVAL, 10) + : 2000, fileExtensions: [".ts"], }, }; diff --git a/apps/bridge-worker/index.ts b/apps/bridge-worker/index.ts index 5a7dbd5..a0cb1d8 100644 --- a/apps/bridge-worker/index.ts +++ b/apps/bridge-worker/index.ts @@ -6,13 +6,20 @@ const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const startWorker = async () => { - console.log("Starting worker..."); - console.log(process.env); + console.info("Starting worker..."); + await run({ connectionString: process.env.DATABASE_URL, - concurrency: 10, noHandleSignals: false, - pollInterval: 1000, + concurrency: process.env.BRIDGE_WORKER_CONCURRENCY + ? parseInt(process.env.BRIDGE_WORKER_CONCURRENCY, 10) + : 10, + maxPoolSize: process.env.BRIDGE_WORKER_POOL_SIZE + ? parseInt(process.env.BRIDGE_WORKER_POOL_SIZE, 10) + : 10, + pollInterval: process.env.BRIDGE_WORKER_POLL_INTERVAL + ? parseInt(process.env.BRIDGE_WORKER_POLL_INTERVAL, 10) + : 1000, taskDirectory: `${__dirname}/tasks`, crontabFile: `${__dirname}/crontab`, }); diff --git a/apps/bridge-worker/lib/common.ts b/apps/bridge-worker/lib/common.ts index 26e4aeb..ff167b3 100644 --- a/apps/bridge-worker/lib/common.ts +++ b/apps/bridge-worker/lib/common.ts @@ -62,9 +62,8 @@ export const createZammadTicket = async ( }, }); } catch (error: any) { - console.log(Object.keys(error)); if (error.isBoom) { - console.log(error.output); + console.error(error.output); throw new Error("Failed to create zamamd ticket"); } } diff --git a/apps/bridge-worker/lib/media-convert.ts b/apps/bridge-worker/lib/media-convert.ts index bc6a22a..587e893 100644 --- a/apps/bridge-worker/lib/media-convert.ts +++ b/apps/bridge-worker/lib/media-convert.ts @@ -25,7 +25,7 @@ const defaultAudioConvertOpts = { **/ export const convert = ( input: Buffer, - opts?: AudioConvertOpts + opts?: AudioConvertOpts, ): Promise => { const settings = { ...defaultAudioConvertOpts, ...opts }; return new Promise((resolve, reject) => { @@ -35,12 +35,8 @@ export const convert = ( .audioCodec(settings.audioCodec) .audioBitrate(settings.bitrate) .toFormat(settings.format) - .on("error", (err, stdout, stderr) => { + .on("error", (err, _stdout, _stderr) => { console.error(err.message); - console.log("FFMPEG OUTPUT"); - console.log(stdout); - console.log("FFMPEG ERROR"); - console.log(stderr); reject(err); }) .on("end", () => { @@ -66,8 +62,12 @@ export const selfCheck = (): Promise => { resolve(false); } - const preds = R.map(requiredCodecs, (codec) => (available: any) => - available[codec] && available[codec].canDemux && available[codec].canMux + const preds = R.map( + requiredCodecs, + (codec) => (available: any) => + available[codec] && + available[codec].canDemux && + available[codec].canMux, ); resolve(R.allPass(codecs, preds)); @@ -79,6 +79,6 @@ export const assertFfmpegAvailable = async (): Promise => { const r = await selfCheck(); if (!r) throw new Error( - `ffmpeg is not installed, could not be located, or does not support the required codecs: ${requiredCodecs}` + `ffmpeg is not installed, could not be located, or does not support the required codecs: ${requiredCodecs}`, ); }; diff --git a/apps/bridge-worker/package.json b/apps/bridge-worker/package.json index aa162e9..2e09e60 100644 --- a/apps/bridge-worker/package.json +++ b/apps/bridge-worker/package.json @@ -1,6 +1,6 @@ { "name": "@link-stack/bridge-worker", - "version": "2.2.0", + "version": "3.1.0", "type": "module", "main": "build/main/index.js", "author": "Darren Clarke ", @@ -16,14 +16,14 @@ "@link-stack/signal-api": "*", "fluent-ffmpeg": "^2.1.3", "graphile-worker": "^0.16.6", - "remeda": "^2.14.0", - "twilio": "^5.3.2" + "remeda": "^2.20.2", + "twilio": "^5.4.5" }, "devDependencies": { - "@types/fluent-ffmpeg": "^2.1.26", - "dotenv-cli": "^7.4.2", + "@types/fluent-ffmpeg": "^2.1.27", + "dotenv-cli": "^8.0.0", "@link-stack/eslint-config": "*", "@link-stack/typescript-config": "*", - "typescript": "^5.6.2" + "typescript": "^5.7.3" } } diff --git a/apps/bridge-worker/tasks/common/notify-webhooks.ts b/apps/bridge-worker/tasks/common/notify-webhooks.ts index 0ed2c17..3d81f93 100644 --- a/apps/bridge-worker/tasks/common/notify-webhooks.ts +++ b/apps/bridge-worker/tasks/common/notify-webhooks.ts @@ -19,13 +19,11 @@ const notifyWebhooksTask = async ( for (const webhook of webhooks) { const { endpointUrl, httpMethod, headers } = webhook; const finalHeaders = { "Content-Type": "application/json", ...headers }; - console.log({ endpointUrl, httpMethod, headers, finalHeaders }); const result = await fetch(endpointUrl, { method: httpMethod, headers: finalHeaders, body: JSON.stringify(payload), }); - console.log(result); } }; diff --git a/apps/bridge-worker/tasks/facebook/send-facebook-message.ts b/apps/bridge-worker/tasks/facebook/send-facebook-message.ts index 3f28fc8..9190e11 100644 --- a/apps/bridge-worker/tasks/facebook/send-facebook-message.ts +++ b/apps/bridge-worker/tasks/facebook/send-facebook-message.ts @@ -31,7 +31,6 @@ const sendFacebookMessageTask = async ( headers: { "Content-Type": "application/json" }, body: JSON.stringify(outgoingMessage), }); - console.log({ response }); } catch (error) { console.error({ error }); throw error; diff --git a/apps/bridge-worker/tasks/fetch-signal-messages.ts b/apps/bridge-worker/tasks/fetch-signal-messages.ts index 1044107..fd920fb 100644 --- a/apps/bridge-worker/tasks/fetch-signal-messages.ts +++ b/apps/bridge-worker/tasks/fetch-signal-messages.ts @@ -46,7 +46,6 @@ const processMessage = async ({ message: msg, }: ProcessMessageArgs): Promise[]> => { const { envelope } = msg; - console.log(envelope); const { source, sourceUuid, dataMessage } = envelope; if (!dataMessage) return []; @@ -125,7 +124,6 @@ const fetchSignalMessagesTask = async ({ phoneNumber, message, }); - console.log({ formattedMessages }); for (const formattedMessage of formattedMessages) { if (formattedMessage.to !== formattedMessage.from) { await worker.addJob( diff --git a/apps/bridge-worker/tasks/leafcutter/import-label-studio.ts b/apps/bridge-worker/tasks/leafcutter/import-label-studio.ts index cb1857e..4f50066 100644 --- a/apps/bridge-worker/tasks/leafcutter/import-label-studio.ts +++ b/apps/bridge-worker/tasks/leafcutter/import-label-studio.ts @@ -36,7 +36,6 @@ const getZammadTickets = async ( { headers }, ); const tickets: any = await rawTickets.json(); - console.log({ tickets }); if (!tickets || tickets.length === 0) { return [shouldContinue, docs]; } @@ -49,23 +48,9 @@ const getZammadTickets = async ( shouldContinue = true; if (source_closed_at <= minUpdatedTimestamp) { - console.log(`Skipping ticket`, { - source_id, - source_updated_at, - source_closed_at, - minUpdatedTimestamp, - }); continue; } - - console.log(`Processing ticket`, { - source_id, - source_updated_at, - source_closed_at, - minUpdatedTimestamp, - }); - - const rawArticles = await fetch( + const rawArticles = await fetch( `${zammadApiUrl}/ticket_articles/by_ticket/${source_id}`, { headers }, ); @@ -178,8 +163,6 @@ const sendToLabelStudio = async (tickets: FormattedZammadTicket[]) => { body: JSON.stringify([ticket]), }); const importResult = await res.json(); - - console.log(JSON.stringify(importResult, undefined, 2)); } }; */ @@ -201,7 +184,6 @@ const importLabelStudioTask = async (): Promise => { await sendToLabelStudio(tickets); const lastTicket = tickets.pop(); const newLastTimestamp = lastTicket.data.source_closed_at; - console.log({ newLastTimestamp }); await db.settings.upsert(settingName, { minUpdatedTimestamp: newLastTimestamp, }); diff --git a/apps/bridge-worker/tasks/leafcutter/import-leafcutter.ts b/apps/bridge-worker/tasks/leafcutter/import-leafcutter.ts index a3c3e4e..f410ca7 100644 --- a/apps/bridge-worker/tasks/leafcutter/import-leafcutter.ts +++ b/apps/bridge-worker/tasks/leafcutter/import-leafcutter.ts @@ -43,14 +43,11 @@ const getLabelStudioTickets = async ( page_size: "50", page: `${page}`, }); - console.log({ url: `${labelStudioApiUrl}/projects/1/tasks?${ticketsQuery}` }); const res = await fetch( `${labelStudioApiUrl}/projects/1/tasks?${ticketsQuery}`, { headers }, ); - console.log({ res }); const tasksResult: any = await res.json(); - console.log({ tasksResult }); return tasksResult; }; @@ -63,14 +60,11 @@ const fetchFromLabelStudio = async ( for await (const page of pages) { const docs = await getLabelStudioTickets(page + 1); - console.log({ page, docs }); if (docs && docs.length > 0) { for (const doc of docs) { const updatedAt = new Date(doc.updated_at); - console.log({ updatedAt, minUpdatedTimestamp }); if (updatedAt > minUpdatedTimestamp) { - console.log(`Adding doc`, { doc }); allDocs.push(doc); } } @@ -79,7 +73,6 @@ const fetchFromLabelStudio = async ( } } - console.log({ allDocs }); return allDocs; }; @@ -93,9 +86,7 @@ const sendToLeafcutter = async (tickets: LabelStudioTicket[]) => { }, } = config; - console.log({ tickets }); const filteredTickets = tickets.filter((ticket) => ticket.is_labeled); - console.log({ filteredTickets }); const finalTickets: LeafcutterTicket[] = filteredTickets.map((ticket) => { const { id, @@ -131,8 +122,7 @@ const sendToLeafcutter = async (tickets: LabelStudioTicket[]) => { }; }); - console.log("Sending to Leafcutter"); - console.log({ finalTickets }); + console.info("Sending to Leafcutter"); const result = await fetch(opensearchApiUrl, { method: "POST", @@ -157,15 +147,7 @@ const importLeafcutterTask = async (): Promise => { ? new Date(res.value.minUpdatedTimestamp as string) : new Date("2023-03-01"); const newLastTimestamp = new Date(); - console.log({ - contributorName, - settingName, - res, - startTimestamp, - newLastTimestamp, - }); const tickets = await fetchFromLabelStudio(startTimestamp); - console.log({ tickets }); await sendToLeafcutter(tickets); await db.settings.upsert(settingName, { minUpdatedTimestamp: newLastTimestamp, diff --git a/apps/bridge-worker/tasks/signal/receive-signal-message.ts b/apps/bridge-worker/tasks/signal/receive-signal-message.ts index b1688ea..a75b7cb 100644 --- a/apps/bridge-worker/tasks/signal/receive-signal-message.ts +++ b/apps/bridge-worker/tasks/signal/receive-signal-message.ts @@ -23,7 +23,6 @@ const receiveSignalMessageTask = async ({ filename, mimeType, }: ReceiveSignalMessageTaskOptions): Promise => { - console.log({ token, to, from }); const worker = await getWorkerUtils(); const row = await db .selectFrom("SignalBot") diff --git a/apps/bridge-worker/tasks/signal/send-signal-message.ts b/apps/bridge-worker/tasks/signal/send-signal-message.ts index 4150300..8426709 100644 --- a/apps/bridge-worker/tasks/signal/send-signal-message.ts +++ b/apps/bridge-worker/tasks/signal/send-signal-message.ts @@ -13,7 +13,6 @@ const sendSignalMessageTask = async ({ to, message, }: SendSignalMessageTaskOptions): Promise => { - console.log({ token, to }); const bot = await db .selectFrom("SignalBot") .selectAll() @@ -34,7 +33,6 @@ const sendSignalMessageTask = async ({ message, }, }); - console.log({ response }); } catch (error) { console.error({ error }); throw error; diff --git a/apps/bridge-worker/tasks/whatsapp/receive-whatsapp-message.ts b/apps/bridge-worker/tasks/whatsapp/receive-whatsapp-message.ts index 024c70e..48adc6f 100644 --- a/apps/bridge-worker/tasks/whatsapp/receive-whatsapp-message.ts +++ b/apps/bridge-worker/tasks/whatsapp/receive-whatsapp-message.ts @@ -23,8 +23,6 @@ const receiveWhatsappMessageTask = async ({ filename, mimeType, }: ReceiveWhatsappMessageTaskOptions): Promise => { - console.log({ token, to, from }); - const worker = await getWorkerUtils(); const row = await db .selectFrom("WhatsappBot") diff --git a/apps/bridge-worker/tasks/whatsapp/send-whatsapp-message.ts b/apps/bridge-worker/tasks/whatsapp/send-whatsapp-message.ts index 509371f..b04543a 100644 --- a/apps/bridge-worker/tasks/whatsapp/send-whatsapp-message.ts +++ b/apps/bridge-worker/tasks/whatsapp/send-whatsapp-message.ts @@ -25,7 +25,6 @@ const sendWhatsappMessageTask = async ({ headers: { "Content-Type": "application/json" }, body: JSON.stringify(params), }); - console.log({ result }); } catch (error) { console.error({ error }); throw new Error("Failed to send message"); diff --git a/apps/leafcutter/app/(main)/about/page.tsx b/apps/leafcutter/app/(main)/about/page.tsx index b6958b2..1bfad23 100644 --- a/apps/leafcutter/app/(main)/about/page.tsx +++ b/apps/leafcutter/app/(main)/about/page.tsx @@ -1,5 +1,10 @@ +import { Suspense } from "react"; import { About } from "@link-stack/leafcutter-ui"; export default function Page() { - return ; + return ( + + + + ); } diff --git a/apps/leafcutter/app/(main)/faq/page.tsx b/apps/leafcutter/app/(main)/faq/page.tsx index 396a9b5..05b57de 100644 --- a/apps/leafcutter/app/(main)/faq/page.tsx +++ b/apps/leafcutter/app/(main)/faq/page.tsx @@ -1,5 +1,12 @@ +import { Suspense } from "react"; import { FAQ } from "@link-stack/leafcutter-ui"; -export default function Page() { - return ; +export const dynamic = "force-dynamic"; + +export default async function Page() { + return ( + + + + ); } diff --git a/apps/leafcutter/app/(main)/layout.tsx b/apps/leafcutter/app/(main)/layout.tsx index 5b9e9f1..d97fd7b 100644 --- a/apps/leafcutter/app/(main)/layout.tsx +++ b/apps/leafcutter/app/(main)/layout.tsx @@ -2,6 +2,8 @@ import { ReactNode } from "react"; import "app/_styles/global.css"; import { InternalLayout } from "../_components/InternalLayout"; +export const dynamic = "force-dynamic"; + type LayoutProps = { children: ReactNode; }; diff --git a/apps/leafcutter/app/(main)/preview/[...visualizationID]/page.tsx b/apps/leafcutter/app/(main)/preview/[...visualizationID]/page.tsx index 8daaaba..a1a60c6 100644 --- a/apps/leafcutter/app/(main)/preview/[...visualizationID]/page.tsx +++ b/apps/leafcutter/app/(main)/preview/[...visualizationID]/page.tsx @@ -69,19 +69,17 @@ export const getServerSideProps: GetServerSideProps = async ( }); }); } - console.log({ query }); const dataResponse = await client.search({ index: "demo_data", size: 200, body: { query }, }); - console.log({ dataResponse }); res.props.data = dataResponse.body.hits.hits.map((hit) => ({ id: hit._id, ...hit._source, })); - console.log({ data: res.props.data }); - console.log(res.props.data[0]); + + return res; }; diff --git a/apps/leafcutter/app/(main)/setup/_components/Setup.tsx b/apps/leafcutter/app/(main)/setup/_components/Setup.tsx index 1a079ec..7fe08ae 100644 --- a/apps/leafcutter/app/(main)/setup/_components/Setup.tsx +++ b/apps/leafcutter/app/(main)/setup/_components/Setup.tsx @@ -13,7 +13,7 @@ export const Setup: FC = () => { } = useLeafcutterContext(); const router = useRouter(); useLayoutEffect(() => { - setTimeout(() => router.push("/"), 4000); + setTimeout(() => router.push("/"), 2000); }, [router]); return ( diff --git a/apps/leafcutter/app/(main)/setup/page.tsx b/apps/leafcutter/app/(main)/setup/page.tsx index 4e62414..dad2ed0 100644 --- a/apps/leafcutter/app/(main)/setup/page.tsx +++ b/apps/leafcutter/app/(main)/setup/page.tsx @@ -1,5 +1,10 @@ +import { Suspense } from "react"; import { Setup } from "./_components/Setup"; export default function Page() { - return ; + return ( + + + + ); } diff --git a/apps/leafcutter/app/(main)/visualizations/[...visualizationID]/page.tsx b/apps/leafcutter/app/(main)/visualizations/[...visualizationID]/page.tsx index 5ef382b..d840ef4 100644 --- a/apps/leafcutter/app/(main)/visualizations/[...visualizationID]/page.tsx +++ b/apps/leafcutter/app/(main)/visualizations/[...visualizationID]/page.tsx @@ -22,9 +22,9 @@ const getVisualization = async (visualizationID: string) => { ); const hit = hits[0]; const visualization = { - id: hit._id.split(":")[1], - title: hit._source.visualization.title, - description: hit._source.visualization.description, + id: hit?._id.split(":")[1], + title: hit?._source?.visualization.title, + description: hit?._source?.visualization.description, url: `/app/visualize?security_tenant=global#/edit/${ hit._id.split(":")[1] }?embed=true`, @@ -34,12 +34,13 @@ const getVisualization = async (visualizationID: string) => { }; type PageProps = { - params: { + params: Promise<{ visualizationID: string; - }; + }>; }; -export default async function Page({ params: { visualizationID } }: PageProps) { +export default async function Page({ params }: PageProps) { + const { visualizationID } = await params; const visualization = await getVisualization(visualizationID); return ; diff --git a/apps/leafcutter/app/_components/Sidebar.tsx b/apps/leafcutter/app/_components/Sidebar.tsx index acdcef3..b3c0a43 100644 --- a/apps/leafcutter/app/_components/Sidebar.tsx +++ b/apps/leafcutter/app/_components/Sidebar.tsx @@ -48,7 +48,6 @@ const MenuItem = ({ return ( new Client({ - node: baseURL, - auth: { - username: process.env.OPENSEARCH_USERNAME!, - password: process.env.OPENSEARCH_PASSWORD!, - }, - ssl: { - rejectUnauthorized: false, - }, -}); +const createClient = () => + new Client({ + node: baseURL, + auth: { + username: process.env.OPENSEARCH_USERNAME!, + password: process.env.OPENSEARCH_PASSWORD!, + }, + ssl: { + rejectUnauthorized: false, + }, + }); -const createUserClient = (username: string, password: string) => new Client({ - node: baseURL, - auth: { - username, - password, - }, - ssl: { - rejectUnauthorized: false, - }, -}); +const createUserClient = (username: string, password: string) => + new Client({ + node: baseURL, + auth: { + username, + password, + }, + ssl: { + rejectUnauthorized: false, + }, + }); export const checkAuth = async (username: string, password: string) => { const client = createUserClient(username, password); @@ -115,7 +117,7 @@ export const getUserMetadata = async (username: string) => { await client.create({ id: username, index: userMetadataIndexName, - body: { username, savedSearches: [] } + body: { username, savedSearches: [] }, }); res = await client.get({ @@ -132,7 +134,7 @@ export const saveUserMetadata = async (username: string, metadata: any) => { await client.update({ id: username, index: userMetadataIndexName, - body: { doc: { username, ...metadata } } + body: { doc: { username, ...metadata } }, }); }; @@ -181,7 +183,7 @@ const getIndexPattern: any = async (index: string) => { sort: ["updated_at:desc"], }); - if (res.body.hits.total.value === 0) { + if (res?.body?.hits?.total?.valueOf() === 0) { // eslint-disable-next-line no-use-before-define return createCurrentUserIndexPattern(index); } @@ -226,7 +228,7 @@ interface createUserVisualizationProps { } export const createUserVisualization = async ( - props: createUserVisualizationProps + props: createUserVisualizationProps, ) => { const { email, query, visualizationID, title, description } = props; const userIndex = await getCurrentUserIndex(email); @@ -279,7 +281,7 @@ interface updateVisualizationProps { } export const updateUserVisualization = async ( - props: updateVisualizationProps + props: updateVisualizationProps, ) => { const { email, id, query, title, description } = props; const userIndex = await getCurrentUserIndex(email); @@ -300,8 +302,7 @@ export const updateUserVisualization = async ( body, }); } catch (e) { - // eslint-disable-next-line no-console - console.log({ e }); + console.error({ e }); } return id; @@ -469,10 +470,18 @@ export const performQuery = async (searchQuery: any, limit: number) => { const results = hits.map((hit: any) => ({ ...hit._source, id: hit._id, - incident: Array.isArray(hit._source.incident) ? hit._source.incident.join(", ") : hit._source.incident, - technology: Array.isArray(hit._source.technology) ? hit._source.technology.join(", ") : hit._source.technology, - targeted_group: Array.isArray(hit._source.targeted_group) ? hit._source.targeted_group.join(", ") : hit._source.targeted_group, - country: Array.isArray(hit._source.country) ? hit._source.country.join(", ") : hit._source.country, + incident: Array.isArray(hit._source.incident) + ? hit._source.incident.join(", ") + : hit._source.incident, + technology: Array.isArray(hit._source.technology) + ? hit._source.technology.join(", ") + : hit._source.technology, + targeted_group: Array.isArray(hit._source.targeted_group) + ? hit._source.targeted_group.join(", ") + : hit._source.targeted_group, + country: Array.isArray(hit._source.country) + ? hit._source.country.join(", ") + : hit._source.country, })); return results; @@ -570,7 +579,6 @@ export const getTemplates = async (limit: number) => { }, }; - const rawResponse = await client.search({ index: globalIndex, size: limit, diff --git a/apps/leafcutter/app/api/link/auth/route.ts b/apps/leafcutter/app/api/link/auth/route.ts index 37b356e..1960382 100644 --- a/apps/leafcutter/app/api/link/auth/route.ts +++ b/apps/leafcutter/app/api/link/auth/route.ts @@ -1,15 +1,13 @@ import { NextRequest, NextResponse } from "next/server"; export const GET = async (req: NextRequest) => { - const validDomains = "localhost"; - console.log({ req }); + const validDomains = "localhost"; - return NextResponse.json({ response: "ok" }); + return NextResponse.json({ response: "ok" }); }; export const POST = async (req: NextRequest) => { - const validDomains = "localhost"; - console.log({ req }); + const validDomains = "localhost"; - return NextResponse.json({ response: "ok" }); + return NextResponse.json({ response: "ok" }); }; diff --git a/apps/leafcutter/app/api/trends/recent/route.ts b/apps/leafcutter/app/api/trends/recent/route.ts index a635d29..d18b657 100644 --- a/apps/leafcutter/app/api/trends/recent/route.ts +++ b/apps/leafcutter/app/api/trends/recent/route.ts @@ -2,10 +2,9 @@ import { NextResponse } from "next/server"; import { getTrends } from "app/_lib/opensearch"; export const GET = async () => { - const results = await getTrends(5); - console.log({ results }); + const results = await getTrends(5); - NextResponse.json(results); + NextResponse.json(results); }; -export const dynamic = 'force-dynamic'; +export const dynamic = "force-dynamic"; diff --git a/apps/leafcutter/app/api/upload/index.ts b/apps/leafcutter/app/api/upload/index.ts index 4f3223e..afb5298 100644 --- a/apps/leafcutter/app/api/upload/index.ts +++ b/apps/leafcutter/app/api/upload/index.ts @@ -15,8 +15,8 @@ export const POST = async (req: NextRequest) => { rejectUnauthorized: false, }, headers: { - authorization - } + authorization, + }, }); const succeeded = []; @@ -28,11 +28,15 @@ export const POST = async (req: NextRequest) => { const country = ticket.country[0] ?? "none"; // @ts-expect-error const translatedCountry = taxonomy.country[country]?.display ?? "none"; - const countryDetails: any = unRegions.find((c) => c.name === translatedCountry); + const countryDetails: any = unRegions.find( + (c) => c.name === translatedCountry, + ); const augmentedTicket = { ...ticket, - region: countryDetails['sub-region']?.toLowerCase().replace(" ", "-") ?? null, - continent: countryDetails.region?.toLowerCase().replace(" ", "-") ?? null, + region: + countryDetails["sub-region"]?.toLowerCase().replace(" ", "-") ?? null, + continent: + countryDetails.region?.toLowerCase().replace(" ", "-") ?? null, }; const out = await client.create({ id: uuid(), @@ -40,10 +44,9 @@ export const POST = async (req: NextRequest) => { refresh: true, body: augmentedTicket, }); - console.log(out); succeeded.push(id); } catch (e) { - console.log(e); + console.error(e); failed.push(id); } } @@ -52,4 +55,3 @@ export const POST = async (req: NextRequest) => { return NextResponse.json(results); }; - diff --git a/apps/leafcutter/app/api/visualizations/delete/route.ts b/apps/leafcutter/app/api/visualizations/delete/route.ts index 2200ed7..20e10b5 100644 --- a/apps/leafcutter/app/api/visualizations/delete/route.ts +++ b/apps/leafcutter/app/api/visualizations/delete/route.ts @@ -3,13 +3,13 @@ import { getServerSession } from "next-auth"; import { authOptions } from "app/_lib/auth"; import { deleteUserVisualization } from "app/_lib/opensearch"; -export const POST = async (req: NextRequest, res: NextResponse) => { - const session = await getServerSession(authOptions); - const { user: { email } }: any = session; - const { id } = await req.json(); - await deleteUserVisualization(email as string, id); +export const POST = async (req: NextRequest) => { + const session = await getServerSession(authOptions); + const { + user: { email }, + }: any = session; + const { id } = await req.json(); + await deleteUserVisualization(email as string, id); - return NextResponse.json({ id }); + return NextResponse.json({ id }); }; - - diff --git a/apps/leafcutter/next-env.d.ts b/apps/leafcutter/next-env.d.ts index 725dd6f..3cd7048 100644 --- a/apps/leafcutter/next-env.d.ts +++ b/apps/leafcutter/next-env.d.ts @@ -3,4 +3,4 @@ /// // NOTE: This file should not be edited -// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information. +// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/apps/leafcutter/next.config.js b/apps/leafcutter/next.config.js index e8cb203..a57f18f 100644 --- a/apps/leafcutter/next.config.js +++ b/apps/leafcutter/next.config.js @@ -1,8 +1,5 @@ module.exports = { transpilePackages: ["@link-stack/leafcutter-ui", "@link-stack/opensearch-common"], - experimental: { - missingSuspenseWithCSRBailout: false, - }, poweredByHeader: false, rewrites: async () => ({ fallback: [ diff --git a/apps/leafcutter/package.json b/apps/leafcutter/package.json index 9c3e062..8905e40 100644 --- a/apps/leafcutter/package.json +++ b/apps/leafcutter/package.json @@ -1,6 +1,6 @@ { "name": "@link-stack/leafcutter", - "version": "2.2.0", + "version": "3.1.0", "scripts": { "dev": "next dev -p 3001", "login": "aws sso login --sso-session cdr", @@ -13,37 +13,37 @@ "lint": "next lint" }, "dependencies": { - "@emotion/cache": "^11.13.1", - "@emotion/react": "^11.13.3", + "@emotion/cache": "^11.14.0", + "@emotion/react": "^11.14.0", "@emotion/server": "^11.11.0", - "@emotion/styled": "^11.13.0", + "@emotion/styled": "^11.14.0", "@link-stack/leafcutter-ui": "*", "@link-stack/opensearch-common": "*", - "@mui/icons-material": "^5", - "@mui/material": "^5", - "@mui/material-nextjs": "^5", - "@mui/x-date-pickers-pro": "^7.18.0", - "@opensearch-project/opensearch": "^2.12.0", + "@mui/icons-material": "^6", + "@mui/material": "^6", + "@mui/material-nextjs": "^6", + "@mui/x-date-pickers-pro": "^7.27.1", + "@opensearch-project/opensearch": "^3.4.0", "date-fns": "^4.1.0", - "http-proxy-middleware": "^3.0.2", - "material-ui-popup-state": "^5.3.1", - "next": "^14.2.23", - "next-auth": "^4.24.8", - "react": "18.3.1", - "react-cookie": "^7.2.0", + "http-proxy-middleware": "^3.0.3", + "material-ui-popup-state": "^5.3.3", + "next": "15.1.7", + "next-auth": "^4.24.11", + "react": "19.0.0", + "react-cookie": "^7.2.2", "react-cookie-consent": "^9.0.0", - "react-dom": "18.3.1", + "react-dom": "19.0.0", "react-iframe": "^1.8.5", "react-polyglot": "^0.7.2", "sharp": "^0.33.5", - "uuid": "^10.0.0" + "uuid": "^11.1.0" }, "devDependencies": { + "@types/node": "^22.13.5", + "@types/react": "19.0.10", + "@types/uuid": "^10.0.0", "@link-stack/eslint-config": "*", "@link-stack/typescript-config": "*", - "@types/node": "^22.7.3", - "@types/react": "18.3.9", - "@types/uuid": "^10.0.0", - "typescript": "5.6.2" + "typescript": "5.7.3" } } diff --git a/apps/leafcutter/pages/api/proxy/[[...path]].ts b/apps/leafcutter/pages/api/proxy/[[...path]].ts index 913b7cb..a4c2f38 100644 --- a/apps/leafcutter/pages/api/proxy/[[...path]].ts +++ b/apps/leafcutter/pages/api/proxy/[[...path]].ts @@ -24,17 +24,17 @@ const withAuthInfo = const requestSignature = req.query.signature; const url = new URL(req.headers.referer as string); const referrerSignature = url.searchParams.get("signature"); - - console.log({ requestSignature, referrerSignature }); const isAppPath = !!req.url?.startsWith("/app"); - const isResourcePath = !!req.url?.match(/\/(api|app|bootstrap|3961|ui|translations|internal|login|node_modules)/); + const isResourcePath = !!req.url?.match( + /\/(api|app|bootstrap|3961|ui|translations|internal|login|node_modules)/, + ); if (requestSignature && isAppPath) { - console.log("Has Signature"); + console.info("Has Signature"); } if (referrerSignature && isResourcePath) { - console.log("Has Signature"); + console.info("Has Signature"); } if (!email) { diff --git a/apps/leafcutter/public/robots.txt b/apps/leafcutter/public/robots.txt new file mode 100644 index 0000000..1f53798 --- /dev/null +++ b/apps/leafcutter/public/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: / diff --git a/apps/link/app/(login)/login/_components/Login.tsx b/apps/link/app/(login)/login/_components/Login.tsx index 0cc1234..5faf515 100644 --- a/apps/link/app/(login)/login/_components/Login.tsx +++ b/apps/link/app/(login)/login/_components/Login.tsx @@ -23,13 +23,12 @@ import { useSearchParams } from "next/navigation"; type LoginProps = { session: any; + baseURL: string; }; -export const Login: FC = ({ session }) => { - const origin = - typeof window !== "undefined" && window.location.origin - ? window.location.origin - : ""; +export const Login: FC = ({ session, baseURL }) => { + const origin = baseURL; + const callbackUrl = `${origin}/setup`; const [provider, setProvider] = useState(undefined); const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); @@ -158,7 +157,7 @@ export const Login: FC = ({ session }) => { sx={buttonStyles} onClick={() => signIn("google", { - callbackUrl: `${origin}`, + callbackUrl, }) } > @@ -174,7 +173,7 @@ export const Login: FC = ({ session }) => { sx={buttonStyles} onClick={() => signIn("apple", { - callbackUrl: `${window.location.origin}`, + callbackUrl, }) } > @@ -230,7 +229,7 @@ export const Login: FC = ({ session }) => { signIn("credentials", { email, password, - callbackUrl: `${origin}/setup`, + callbackUrl, }) } > diff --git a/apps/link/app/(login)/login/page.tsx b/apps/link/app/(login)/login/page.tsx index 7bafdbb..ea944ba 100644 --- a/apps/link/app/(login)/login/page.tsx +++ b/apps/link/app/(login)/login/page.tsx @@ -9,10 +9,11 @@ export const metadata: Metadata = { export default async function Page() { const session = await getSession(); + const baseURL = process.env.LINK_URL; return ( Loading...}> - + ); } diff --git a/apps/link/app/(main)/_components/ClientOnly.tsx b/apps/link/app/(main)/_components/ClientOnly.tsx index 46e79e8..b669b4f 100644 --- a/apps/link/app/(main)/_components/ClientOnly.tsx +++ b/apps/link/app/(main)/_components/ClientOnly.tsx @@ -1,8 +1,9 @@ "use client"; +import { ReactNode } from "react"; import dynamic from "next/dynamic"; -type ClientOnlyProps = { children: JSX.Element }; +type ClientOnlyProps = { children: ReactNode }; const ClientOnly = (props: ClientOnlyProps) => { const { children } = props; diff --git a/apps/link/app/(main)/_components/Home.tsx b/apps/link/app/(main)/_components/Home.tsx index 1a404ae..44332f1 100644 --- a/apps/link/app/(main)/_components/Home.tsx +++ b/apps/link/app/(main)/_components/Home.tsx @@ -3,9 +3,10 @@ import { FC } from "react"; import { OpenSearchWrapper } from "@link-stack/leafcutter-ui"; -export const Home: FC = () => ( - +type HomeProps = { + url: string; +}; + +export const Home: FC = ({ url }) => ( + ); diff --git a/apps/link/app/(main)/_components/Sidebar.tsx b/apps/link/app/(main)/_components/Sidebar.tsx index c099c42..333cfb6 100644 --- a/apps/link/app/(main)/_components/Sidebar.tsx +++ b/apps/link/app/(main)/_components/Sidebar.tsx @@ -485,7 +485,25 @@ export const Sidebar: FC = ({ selected={pathname.endsWith("/docs")} open={open} /> - {leafcutterEnabled && ( + + {roles.includes("admin") && leafcutterEnabled && ( + + )} + {false && leafcutterEnabled && ( = ({ method: "GET", redirect: "manual", }); - console.log({ res }); if (res.type === "opaqueredirect") { setAuthenticated(true); } else { @@ -69,7 +68,6 @@ export const ZammadWrapper: FC = ({ }, [session]); if (!session || !authenticated) { - console.log("Not authenticated"); return ( = ({ } if (session && authenticated) { - console.log("Session and authenticated"); return (