Files
outline/plugins/iframely/server/iframely.ts
T
Tom Moor 1f097b0fdd chore: resolve no-explicit-any lint warnings in plugins (#12237)
* chore: resolve no-explicit-any lint warnings in plugins

Replaces uses of `any` in the plugins directory with concrete types,
`unknown`, or structured type assertions, addressing the remaining
typescript-eslint(no-explicit-any) warnings flagged by oxlint.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* chore: address review feedback in GitLabIssueProvider

Drop trailing semicolon from log string and add early return in
`destroyNamespace` when neither `user_id` nor `full_path` is present
to avoid an unnecessary full-scan transaction.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-01 08:29:58 -04:00

74 lines
2.2 KiB
TypeScript

import type { JSONObject } from "@shared/types";
import { UnfurlResourceType } from "@shared/types";
import Logger from "@server/logging/Logger";
import type { UnfurlError, UnfurlSignature } from "@server/types";
import fetch from "@server/utils/fetch";
import env from "./env";
import { cdnPath } from "@shared/utils/urls";
class Iframely {
public static defaultUrl = "https://iframe.ly";
public static async requestResource(
url: string,
type = "iframely"
): Promise<JSONObject | UnfurlError> {
const isDefaultHost = env.IFRAMELY_URL === this.defaultUrl;
// Cloud Iframely requires /api path, while self-hosted does not.
const apiUrl = isDefaultHost ? `${env.IFRAMELY_URL}/api` : env.IFRAMELY_URL;
try {
const res = await fetch(
`${apiUrl}/${type}?url=${encodeURIComponent(url)}&api_key=${
env.IFRAMELY_API_KEY
}`,
{
timeout: 10000, // 10 second timeout
}
);
return await res.json();
} catch (err) {
Logger.error(`Error fetching data from Iframely for url: ${url}`, err);
return { error: err.message || "Unknown error" };
}
}
/**
*
* @param url Resource url
* @returns An object containing resource details e.g, resource title, description etc.
*/
public static unfurl: UnfurlSignature = async (url: string) => {
const data = await Iframely.requestResource(url);
if ("error" in data) {
return { error: data.error } as UnfurlError; // In addition to our custom UnfurlError, sometimes iframely returns error in the response body.
}
const parsedData = data as {
url: string;
meta: { title: string; description: string; site: string };
links: {
thumbnail?: { href: string }[];
icon?: { href: string }[];
};
};
return {
type: UnfurlResourceType.URL,
url: parsedData.url,
title: parsedData.meta.title,
description: parsedData.meta.description,
thumbnailUrl: (parsedData.links.thumbnail ?? [])[0]?.href ?? "",
faviconUrl:
parsedData.meta.site === "Figma"
? cdnPath("/images/figma.png")
: ((parsedData.links.icon ?? [])[0]?.href ?? ""),
transformedUnfurl: true,
};
};
}
export default Iframely;