atagen

malice

public
Star0
Watch0
fddb0bcaabebd4f669567dc3d730d03d91d3ed65
2
ssh://brewery@pls.lobotomise.me:33/atagen/malice.git

Blame: web/src/lib/link-previews.ts

ecb8598b38afatagen2026-10-22 09:19 UTC1
import { get, writable } from 'svelte/store';
ecb8598b38afatagen2026-10-22 09:19 UTC2
import { ApiError, getAccountData, getUrlPreview, setAccountData } from './api';
ecb8598b38afatagen2026-10-22 09:19 UTC3
import { parseLinkPreview } from './types';
ecb8598b38afatagen2026-10-22 09:19 UTC4
import type { LinkPreview } from './types';
ecb8598b38afatagen2026-10-22 09:19 UTC5
ecb8598b38afatagen2026-10-22 09:19 UTC6
const EVENT_TYPE = 'dev.malice.url_previews';
ecb8598b38afatagen2026-10-22 09:19 UTC7
const BACKOFF_MS = 30_000;
ecb8598b38afatagen2026-10-22 09:19 UTC8
ecb8598b38afatagen2026-10-22 09:19 UTC9
export interface UrlPreviewSettings {
ecb8598b38afatagen2026-10-22 09:19 UTC10
  encrypted_rooms: boolean;
ecb8598b38afatagen2026-10-22 09:19 UTC11
}
ecb8598b38afatagen2026-10-22 09:19 UTC12
ecb8598b38afatagen2026-10-22 09:19 UTC13
const DEFAULT_SETTINGS: UrlPreviewSettings = { encrypted_rooms: false };
ecb8598b38afatagen2026-10-22 09:19 UTC14
ecb8598b38afatagen2026-10-22 09:19 UTC15
export const linkPreviews = writable<Record<string, LinkPreview | null>>({});
ecb8598b38afatagen2026-10-22 09:19 UTC16
export const urlPreviewSettings = writable<UrlPreviewSettings>(DEFAULT_SETTINGS);
ecb8598b38afatagen2026-10-22 09:19 UTC17
ecb8598b38afatagen2026-10-22 09:19 UTC18
const inFlight = new Set<string>();
ecb8598b38afatagen2026-10-22 09:19 UTC19
let backoffUntil = 0;
ecb8598b38afatagen2026-10-22 09:19 UTC20
ecb8598b38afatagen2026-10-22 09:19 UTC21
export function requestLinkPreview(roomId: string, url: string): void {
ecb8598b38afatagen2026-10-22 09:19 UTC22
  if (inFlight.has(url) || url in get(linkPreviews) || Date.now() < backoffUntil) return;
ecb8598b38afatagen2026-10-22 09:19 UTC23
  inFlight.add(url);
ecb8598b38afatagen2026-10-22 09:19 UTC24
  getUrlPreview(roomId, url)
ecb8598b38afatagen2026-10-22 09:19 UTC25
    .then((raw) => linkPreviews.update((all) => ({ ...all, [url]: parseLinkPreview(raw) })))
ecb8598b38afatagen2026-10-22 09:19 UTC26
    .catch((e) => {
ecb8598b38afatagen2026-10-22 09:19 UTC27
      if (e instanceof ApiError && e.status === 429) backoffUntil = Date.now() + BACKOFF_MS;
ecb8598b38afatagen2026-10-22 09:19 UTC28
    })
ecb8598b38afatagen2026-10-22 09:19 UTC29
    .finally(() => inFlight.delete(url));
ecb8598b38afatagen2026-10-22 09:19 UTC30
}
ecb8598b38afatagen2026-10-22 09:19 UTC31
ecb8598b38afatagen2026-10-22 09:19 UTC32
function parseSettings(raw: unknown): UrlPreviewSettings {
ecb8598b38afatagen2026-10-22 09:19 UTC33
  if (typeof raw !== 'object' || raw === null) return DEFAULT_SETTINGS;
ecb8598b38afatagen2026-10-22 09:19 UTC34
  return { encrypted_rooms: (raw as Record<string, unknown>)['encrypted_rooms'] === true };
ecb8598b38afatagen2026-10-22 09:19 UTC35
}
ecb8598b38afatagen2026-10-22 09:19 UTC36
ecb8598b38afatagen2026-10-22 09:19 UTC37
export async function loadUrlPreviewSettings(): Promise<void> {
ecb8598b38afatagen2026-10-22 09:19 UTC38
  try {
ecb8598b38afatagen2026-10-22 09:19 UTC39
    urlPreviewSettings.set(parseSettings(await getAccountData(EVENT_TYPE)));
ecb8598b38afatagen2026-10-22 09:19 UTC40
  } catch {
ecb8598b38afatagen2026-10-22 09:19 UTC41
    urlPreviewSettings.set(DEFAULT_SETTINGS);
ecb8598b38afatagen2026-10-22 09:19 UTC42
  }
ecb8598b38afatagen2026-10-22 09:19 UTC43
}
ecb8598b38afatagen2026-10-22 09:19 UTC44
ecb8598b38afatagen2026-10-22 09:19 UTC45
export async function saveUrlPreviewSettings(settings: UrlPreviewSettings): Promise<void> {
ecb8598b38afatagen2026-10-22 09:19 UTC46
  await setAccountData(EVENT_TYPE, { encrypted_rooms: settings.encrypted_rooms });
ecb8598b38afatagen2026-10-22 09:19 UTC47
  urlPreviewSettings.set(settings);
ecb8598b38afatagen2026-10-22 09:19 UTC48
}
ecb8598b38afatagen2026-10-22 09:19 UTC49
ecb8598b38afatagen2026-10-22 09:19 UTC50
export function resetLinkPreviews(): void {
ecb8598b38afatagen2026-10-22 09:19 UTC51
  linkPreviews.set({});
ecb8598b38afatagen2026-10-22 09:19 UTC52
  urlPreviewSettings.set(DEFAULT_SETTINGS);
ecb8598b38afatagen2026-10-22 09:19 UTC53
  inFlight.clear();
ecb8598b38afatagen2026-10-22 09:19 UTC54
  backoffUntil = 0;
ecb8598b38afatagen2026-10-22 09:19 UTC55
}