Skip to content

Events

Events in @media-sdk/core represent user actions in your application — opening a preview, starting a download — not API traffic. Search and fetch methods do not emit events; you call trackView and trackDownload explicitly from your UI layer.

Installation

bash
pnpm add @media-sdk/core@^0.3.0

User-action model

API methodEmits events?
searchPhotos / searchVideosNo — fetch only
getPhoto / getVideoNo — fetch only
getCuratedPhotosNo — fetch only
trackViewYes — emits "media:view"
trackDownloadYes — emits "media:download"

Wire analytics, logging, or provider attribution in event listeners — not inside search hooks.

Event types

ts
type MediaType = "photo" | "video";

interface MediaViewEvent {
  mediaId: number;
  mediaType: MediaType;
}

interface MediaDownloadEvent {
  mediaId: number;
  mediaType: MediaType;
}

interface MediaEventMap {
  "media:view": MediaViewEvent;
  "media:download": MediaDownloadEvent;
}

Subscribing with on()

on(eventName, listener) returns an unsubscribe function. Multiple listeners per event are supported:

ts
import { ApiKeyProvider, PexelsMediaClient } from "@media-sdk/core";

const client = new PexelsMediaClient(
  new ApiKeyProvider(process.env.PEXELS_API_KEY!),
);

const unsubscribeView = client.on("media:view", (event) => {
  console.log("Viewed", event.mediaType, event.mediaId);
});

const unsubscribeDownload = client.on("media:download", (event) => {
  console.log("Downloaded", event.mediaType, event.mediaId);
});

// Later — remove listeners
unsubscribeView();
unsubscribeDownload();

trackView and trackDownload

Call these from UI handlers when the user performs the action:

ts
import type { MediaClient } from "@media-sdk/core";

async function openPhotoPreview(
  client: MediaClient,
  photoId: number,
) {
  const photo = await client.getPhoto(photoId);

  client.trackView({
    mediaId: photo.id,
    mediaType: "photo",
  });

  return photo;
}
ts
import type { MediaClient } from "@media-sdk/core";

function handleDownload(
  client: MediaClient,
  videoId: number,
) {
  client.trackDownload({
    mediaId: videoId,
    mediaType: "video",
  });

  // then trigger your download UI / link
}

trackView and trackDownload are synchronous — they emit to local listeners only. They do not call provider analytics endpoints unless you add that in a listener.

Analytics example

Forward events to your analytics pipeline:

ts
import type { MediaClient } from "@media-sdk/core";

function attachAnalytics(client: MediaClient) {
  const offView = client.on("media:view", (event) => {
    analytics.track("media_view", {
      media_id: event.mediaId,
      media_type: event.mediaType,
    });
  });

  const offDownload = client.on("media:download", (event) => {
    analytics.track("media_download", {
      media_id: event.mediaId,
      media_type: event.mediaType,
    });
  });

  return () => {
    offView();
    offDownload();
  };
}

const detach = attachAnalytics(client);
// detach() on cleanup

Preview-open flow (end-to-end)

ts
import {
  ApiKeyProvider,
  PexelsMediaClient,
  type Photo,
} from "@media-sdk/core";

const client = new PexelsMediaClient(
  new ApiKeyProvider(process.env.PEXELS_API_KEY!),
);

client.on("media:view", ({ mediaId, mediaType }) => {
  console.log(`[analytics] ${mediaType} ${mediaId} opened`);
});

async function showPreview(photoId: number): Promise<Photo> {
  const photo = await client.getPhoto(photoId);

  client.trackView({
    mediaId: photo.id,
    mediaType: "photo",
  });

  return photo;
}

const preview = await showPreview(12345);
console.log(preview.src.medium);

Capabilities

Both built-in providers support event tracking:

ts
import { getCapabilities } from "@media-sdk/core";

const caps = getCapabilities(client);
// caps.operations.trackView === true
// caps.operations.trackDownload === true

Future metadata (not shipped)

Event payloads today carry only mediaId and mediaType. A proposed v2 schema (provider, optional metadata bag) is documented in Analytics designdesign only; no breaking changes in 0.3.x.