From 76fe6a0111d0b653d11ec065c849723a0b016da7 Mon Sep 17 00:00:00 2001 From: shanoysinc Date: Thu, 13 Aug 2026 12:38:25 -0500 Subject: [PATCH 1/2] fix: getting linkedin logo --- .../use-cases/fetch-company-from-linkedin.ts | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/packages/core/src/modules/employment/use-cases/fetch-company-from-linkedin.ts b/packages/core/src/modules/employment/use-cases/fetch-company-from-linkedin.ts index ac476a28d..0ebe6dfe7 100644 --- a/packages/core/src/modules/employment/use-cases/fetch-company-from-linkedin.ts +++ b/packages/core/src/modules/employment/use-cases/fetch-company-from-linkedin.ts @@ -4,17 +4,45 @@ import { withCache } from '@/infrastructure/redis'; import { runActor } from '@/modules/apify'; import { ColorStackError } from '@/shared/errors'; -const LinkedInCompany = z.object({ +const LinkedInLogo = z.object({ + height: z.number().optional(), + url: z.string().url(), + width: z.number().optional(), +}); + +const LinkedInCompanyResponse = z.object({ description: z.string().nullish(), id: z.string(), logo: z.string().url().optional(), + logos: LinkedInLogo.array().optional(), name: z.string(), universalName: z.string(), website: z.string().url().nullish(), }); +const LinkedInCompany = LinkedInCompanyResponse.transform((company) => { + return { + description: company.description, + id: company.id, + logo: company.logo ?? getBestLogoUrl(company.logos), + name: company.name, + universalName: company.universalName, + website: company.website, + }; +}); + export type LinkedInCompany = z.infer; +function getBestLogoUrl(logos: z.infer[] | undefined) { + if (!logos?.length) { + return undefined; + } + + return logos.reduce((best, current) => { + return (current.width ?? 0) > (best.width ?? 0) ? current : best; + }).url; +} + export function parseLinkedInCompanySlug(input: string) { const trimmed = input.trim(); From 45258320a5385c12fae4730cf9167b19aa15d342 Mon Sep 17 00:00:00 2001 From: shanoysinc Date: Thu, 13 Aug 2026 12:43:00 -0500 Subject: [PATCH 2/2] fix: getting linkedin logo --- .../modules/employment/employment.types.ts | 2 +- .../modules/employment/employment.utils.ts | 25 +++++++++++++++++++ .../use-cases/fetch-company-from-linkedin.ts | 13 +--------- 3 files changed, 27 insertions(+), 13 deletions(-) create mode 100644 packages/core/src/modules/employment/employment.utils.ts diff --git a/packages/core/src/modules/employment/employment.types.ts b/packages/core/src/modules/employment/employment.types.ts index b89873293..9e0df8363 100644 --- a/packages/core/src/modules/employment/employment.types.ts +++ b/packages/core/src/modules/employment/employment.types.ts @@ -10,7 +10,7 @@ import { Student, } from '@oyster/types'; -import { parseLinkedInCompanySlug } from '@/modules/employment/use-cases/fetch-company-from-linkedin'; +import { parseLinkedInCompanySlug } from '@/modules/employment/employment.utils'; import { ListSearchParams } from '@/shared/types'; // Enums diff --git a/packages/core/src/modules/employment/employment.utils.ts b/packages/core/src/modules/employment/employment.utils.ts new file mode 100644 index 000000000..d6584f14a --- /dev/null +++ b/packages/core/src/modules/employment/employment.utils.ts @@ -0,0 +1,25 @@ +/** + * Normalizes user input into a LinkedIn company slug. + * + * Accepts either a full LinkedIn company URL or a bare slug, so forms can be + * lenient about what they accept. + * + * This lives apart from the use cases that fetch from LinkedIn because it is + * also needed by `employment.types.ts`, which is bundled for the browser. Any + * import of a use case from there pulls Redis and the Sentry Node SDK into the + * client build. + * + * @example parseLinkedInCompanySlug('https://www.linkedin.com/company/google') // 'google' + * @example parseLinkedInCompanySlug('@google') // 'google' + */ +export function parseLinkedInCompanySlug(input: string) { + const trimmed = input.trim(); + + const match = trimmed.match(/linkedin\.com\/company\/([^/?#]+)/i); + + if (match?.[1]) { + return match[1]; + } + + return trimmed.replace(/^@/, ''); +} diff --git a/packages/core/src/modules/employment/use-cases/fetch-company-from-linkedin.ts b/packages/core/src/modules/employment/use-cases/fetch-company-from-linkedin.ts index 0ebe6dfe7..555380ed3 100644 --- a/packages/core/src/modules/employment/use-cases/fetch-company-from-linkedin.ts +++ b/packages/core/src/modules/employment/use-cases/fetch-company-from-linkedin.ts @@ -2,6 +2,7 @@ import { z } from 'zod'; import { withCache } from '@/infrastructure/redis'; import { runActor } from '@/modules/apify'; +import { parseLinkedInCompanySlug } from '@/modules/employment/employment.utils'; import { ColorStackError } from '@/shared/errors'; const LinkedInLogo = z.object({ @@ -43,18 +44,6 @@ function getBestLogoUrl(logos: z.infer[] | undefined) { }).url; } -export function parseLinkedInCompanySlug(input: string) { - const trimmed = input.trim(); - - const match = trimmed.match(/linkedin\.com\/company\/([^/?#]+)/i); - - if (match?.[1]) { - return match[1]; - } - - return trimmed.replace(/^@/, ''); -} - export async function fetchCompanyFromLinkedIn( companyNameOrLinkedInSlug: string ): Promise {