# Referrers Pagination Design OSS
- Sorting by `io.cncf.oras.artifact.created` annotation is required when returning referrers list, as defined in the [spec](https://github.com/oras-project/artifacts-spec/blob/main/manifest-referrers-api.md#paging-results). As a result, all the referrers manifests must be sorted first to identify the correct referrer descriptors to return in a page.
- This requires that all manifests be read from blob files for each pagination request. Then they are sorted before finding the correct subset of referrers in a page to return from the sorted list.
## Inspiration from Other Projects
- distribution/distribution: [Catalog Repositories](https://github.com/distribution/distribution/blob/6affafd1f030087d88f88841bf66a8abe2bf4d24/registry/handlers/catalog.go#L36)
- uses `last` repository name to determine which repository directory to [walk](https://github.com/distribution/distribution/blob/6affafd1f030087d88f88841bf66a8abe2bf4d24/registry/storage/catalog.go#L135)
- project-zot/zot: [Tag List](https://github.com/project-zot/zot/blob/d19a4bf2a1c69d9f2c7c2476197d0aaf654e6747/pkg/api/routes.go#L162)
- [sorts](https://github.com/project-zot/zot/blob/d19a4bf2a1c69d9f2c7c2476197d0aaf654e6747/pkg/api/routes.go#L222) all the tags every time
- uses `last=<last tag>` to determine [starting point](https://github.com/project-zot/zot/blob/d19a4bf2a1c69d9f2c7c2476197d0aaf654e6747/pkg/api/routes.go#L234)
## Proposed Design
- Request to `v2/<repository>/_oras/artifacts/referrers?digest=<subject-digest>&artifacType=<artifact-type>&n=<page-size>`
- `n` is the max number of referrers returned in the response page returned. If `n` not specified, default value of 50 used. N page size: 3 <= n <= 50, otherwise it uses default value of 50
- Generate the root path to the directory where subject referrer link files reside:
- example: `<root-dir>/docker/registry/v2/repositories/<repository-name>/_refs/subjects/sha256/<subject-digest>`
- Walk all subdirectories under the root-path searching for the link file for each referrer manifest directory
- Using digest in the link file for the referrer manifest, read corresponding manifest blob and descriptor using storage driver
- Filter by `artifactType` specified. If artifact type is not specified, do not filter and consider all referrers.
- Sort final list of referrer artifact descriptors by `io.cncf.oras.artifact.created` annotation
- use `nextToken` query parameter to find next page starting point. `nextToken` contains the digests of the last 3 referrers returned in the previous page (the first digest in `nextToken` contains the last page entry and subsequent digests increase in recency).
- `nextToken` is base64 encoded and must be decoded before use
- Search the sorted referrers list for the oldest existing digest in the `nextToken` digest list. If not provided (or no matching digest found), assume to start at first page. Extract the slice of the next `n` items in the sorted list
- if `n` <= the # of items left in the sorted list, do not return a Link header
- if `n` > the # of items left in the sorted list, append Link Header `Link: <url>; rel="next"`
- sample `url`: `</v2/<repository>/_oras/artifacts/referrers?digest=<subject-digest>&n=<page-size>&nextToken=<last-referrer-digest>>`
- generate
- return the response with header, if needed, with the subset list of referrers