History

Streams export history from a repository source.

Basic Usage

Pass a repository as the source prop:

import { Directory, Repository } from 'renoun'
import { History } from 'renoun/components'

const directory = new Directory({
  path: 'packages/renoun',
  repository: Repository.remote({
    path: 'https://github.com/souporserious/renoun',
    ref: 'main',
  }),
})

export default async function Page() {
  const repo = directory.getRepository()

  return <History source={repo} />
}

Passing a repository is the recommended form because React server rendering can replay renders. History will create a fresh generator internally for each render attempt. A source factory works too. A pre-created async generator still works, but it is a one-shot object and is easier to misuse.

History handles streaming + data projection. You provide UI via component slots.

Slots

SlotPurpose
RootOptional wrapper around all output
ProgressRendered while streaming
CompleteRendered once report is complete
ExportsWraps final export entries
ExportRenders a single export entry
ChangesWraps changes for an export
ChangeRenders an individual change

Custom Rendering

import { Directory, Repository } from 'renoun'
import { History, type HistoryComponents } from 'renoun/components'

const directory = new Directory({
  path: 'packages/renoun',
  repository: Repository.remote({
    path: 'https://github.com/souporserious/renoun',
    ref: 'main',
  }),
})
const repo = directory.getRepository()

const components: Partial<HistoryComponents> = {
  Progress: ({ phase, commitsProcessed, totalCommits }) => (
    <p>
      {phase} ({commitsProcessed}/{totalCommits})
    </p>
  ),
  Complete: ({ exportCount, changeCount, children }) => (
    <section>
      <h2>
        {exportCount} exports, {changeCount} changes
      </h2>
      {children}
    </section>
  ),
  Exports: ({ children }) => <ul>{children}</ul>,
  Export: ({ entry, children }) => (
    <li>
      <strong>{entry.name}</strong>
      {children}
    </li>
  ),
  Changes: ({ children }) => <ol>{children}</ol>,
  Change: ({ change }) => <li>{change.kind}</li>,
}

export default async function Page() {
  return (
    <History
      source={repo}
      sourceOptions={{ entry: 'src/index.ts' }}
      components={components}
    />
  )
}

Entry Selection

Use selectEntries to project the final report before rendering:

import { Directory, Repository } from 'renoun'
import {
  History,
  getRecentlyAddedHistoryEntries,
  type HistorySelectEntriesContext,
} from 'renoun/components'

const directory = new Directory({
  path: 'packages/renoun',
  repository: Repository.remote({
    path: 'https://github.com/souporserious/renoun',
    ref: 'main',
  }),
})
const repo = directory.getRepository()

const selectRecent = ({ report }: HistorySelectEntriesContext) =>
  getRecentlyAddedHistoryEntries(report, { release: 'latest' })

export default async function Page() {
  return (
    <History
      source={repo}
      sourceOptions={{ entry: 'src/index.ts' }}
      selectEntries={selectRecent}
    />
  )
}

Helpers

  • getHistoryEntries(report) returns default sorted entries.
  • getLatestHistoryRelease(report) returns the most recent release label found.
  • getRecentlyAddedHistoryEntries(report, { release }) filters to Added changes for a release ( 'latest' by default).

Streaming Model

History consumes export history one event at a time with recursive Suspense boundaries. Each progress yield is rendered via Progress; when complete, Complete receives the final report and projected entries.

API Reference

efined\"}]]}]],\"\\n\"]}]\n1ca:[\"$\",\"$1\",\"44\",{\"children\":[[\" )\"],\"\\n\"]}]\n1cb:[\"$\",\"$1\",\"45\",{\"children\":[[\"}\"],null]}]\n"])