Skip to content

Using Callbacks

Feedcanon provides callbacks to track progress and hook into the resolution flow:

CallbackFires whenData
onFetchAfter each HTTP request{ url, response }
onMatchURL matches initial response{ url, response, feed }
onExistsexistsFn finds URL in database{ url, data }

onFetch

Fires after every HTTP request, whether successful or not.

typescript
import { findCanonical } from 'feedcanon'

const url = await findCanonical('https://example.com/feed', {
  onFetch: ({ url, response }) => {
    console.log(`${response.status} ${url}`)
  },
})

The response object contains:

PropertyTypeDescription
statusnumberHTTP status code
urlstringFinal URL after redirects
bodystringResponse body
headersHeadersResponse headers

Use Cases

  • Logging HTTP requests for debugging
  • Tracking redirect chains
  • Monitoring request counts

onMatch

Fires when a URL candidate produces content matching the initial response. It also fires once for the input URL, right after the feed is parsed and before any candidate is tested. If rewrites are configured, the URL reported is the rewritten one.

typescript
import { findCanonical } from 'feedcanon'

const aliases = []

const url = await findCanonical('https://example.com/feed', {
  onMatch: ({ url, feed }) => {
    console.log(`Match: ${url}`)
    aliases.push(url)
  },
})

// aliases contains all URLs that serve the same feed

The callback receives:

PropertyTypeDescription
urlstringThe matching URL
responseFetchFnResponseThe HTTP response
feedTFeedParsed feed object

Use Cases

  • Collecting URL aliases for the same feed
  • Logging which candidates work
  • Building redirect maps

onExists

Use existsFn to check if URLs already exist in your database. When found, that URL is returned immediately without further testing.

typescript
import { findCanonical } from 'feedcanon'

const url = await findCanonical('https://example.com/feed', {
  existsFn: async (url) => {
    return await db.feeds.findByUrl(url)
  },
  onExists: ({ url, data }) => {
    console.log('Found existing:', url, data.id)
  },
})

The existsFn function:

  • Receives each URL candidate being tested
  • Returns your data if URL exists, undefined otherwise
  • Triggers early termination when a match is found

The onExists callback fires when existsFn returns data, giving you access to both the URL and your database record.

Examples

Logging

typescript
const url = await findCanonical('https://example.com/feed', {
  onFetch: ({ url, response }) => {
    console.log(`[${response.status}] ${url}`)
  },
  onMatch: ({ url }) => {
    console.log(`[MATCH] ${url}`)
  },
})

Collecting Aliases

typescript
const aliases = []

const url = await findCanonical('http://www.example.com/feed/', {
  onMatch: ({ url }) => {
    aliases.push(url)
  },
})

// url: 'https://example.com/feed'
// aliases: [
//   'http://www.example.com/feed/',
//   'https://www.example.com/feed/',
//   'https://example.com/feed',
// ]

Database Lookup

typescript
const url = await findCanonical('https://example.com/feed', {
  existsFn: async (url) => {
    const [feed] = await db
      .select()
      .from(feeds)
      .where(eq(feeds.url, url))
      .limit(1)

    return feed
  },
  onExists: ({ url, data }) => {
    console.log('Using existing feed:', data.id)
  },
})

Full Tracing

typescript
const url = await findCanonical('https://example.com/feed', {
  existsFn: async (url) => db.feeds.findByUrl(url),

  onFetch: ({ url, response }) => {
    console.log(`Fetch: ${response.status} ${url}`)
  },

  onMatch: ({ url, feed }) => {
    console.log(`Match: ${url}`)
  },

  onExists: ({ url, data }) => {
    console.log(`Exists: ${url} (id: ${data.id})`)
  },
})