import type { ConnectorConnection } from "@tactical-media-broadcast-hub/core"; /** * Provider publishing policies, declared at the composition boundary so the * SDK publish/deletePublication signatures stay unchanged. */ export interface PublishingPolicy { /** * "token": the provider dedupes repeated sends carrying the same * idempotency key, so an ambiguous send may be replayed with that key. * "none": no key and no lookup — an ambiguous send is never replayed. */ idempotency: "token" | "none"; /** * How long after the attempt's first dispatch a same-key replay is trusted. * Applies only to "token" policies and only on deployment-verified origins. */ dedupeWindowMs?: number; } /** * Mastodon documents Idempotency-Key retention of up to one hour; 30 minutes * from first dispatch is the deployment cutoff (forks may keep less). */ export const MASTODON_DEDUPE_WINDOW_MS = 30 * 60 * 1000; export const PUBLISHING_POLICIES: Readonly> = { mastodon: { idempotency: "token", dedupeWindowMs: MASTODON_DEDUPE_WINDOW_MS }, telegram: { idempotency: "none" }, // Graph media_publish takes no idempotency key: an ambiguous send is never replayed. instagram: { idempotency: "none" }, }; /** Unknown providers get the safe default: never replay an ambiguous send. */ export function publishingPolicyFor(provider: string): PublishingPolicy { return PUBLISHING_POLICIES[provider] ?? { idempotency: "none" }; } export function verifiedDedupeOrigin(origin: string, configured = process.env.MASTODON_PUBLISH_DEDUPE_ORIGINS ?? ""): boolean { return configured.split(",").map((value) => value.trim()).filter(Boolean).some((value) => { try { const url = new URL(value); return url.protocol === "https:" && url.origin === value && url.origin === origin; } catch { return false; } }); } export function isPublishingProvider(provider: string): boolean { return Object.hasOwn(PUBLISHING_POLICIES, provider); } export function publishingDispatchPolicy(connection: ConnectorConnection): { policy: PublishingPolicy; origin: string; dedupeVerified: boolean } { const policy = publishingPolicyFor(connection.provider); let origin = ""; try { origin = new URL(connection.fields.instanceUrl ?? "").origin; } catch { /* invalid origins never authorize dedupe */ } return { policy, origin, dedupeVerified: policy.idempotency === "token" && verifiedDedupeOrigin(origin) }; }