4.6 KiB
TRUEREF-0014 — Repository Version Management
Priority: P1 Status: Pending Depends On: TRUEREF-0003 Blocks: —
Overview
Support indexing specific git tags and branches as distinct versioned snapshots of a repository. Users can query documentation for a specific version using the /owner/repo/version library ID format. Versions are registered via trueref.json's previousVersions field or manually via the API.
Acceptance Criteria
GET /api/v1/libs/:id/versions— list all indexed versions for a repositoryPOST /api/v1/libs/:id/versions— add a new version (tag or branch)DELETE /api/v1/libs/:id/versions/:versionTag— remove a version and its snippetsPOST /api/v1/libs/:id/versions/:versionTag/index— trigger indexing for a specific version- Version-specific queries:
/api/v1/context?libraryId=/facebook/react/v18.3.0 - Default branch queries:
/api/v1/context?libraryId=/facebook/react(no version suffix) previousVersionsfromtrueref.jsonautomatically registered during indexing (state:pending)- GitHub tag list endpoint used to validate tag existence before indexing
- Version snippets stored with
versionIdFK; default branch snippets haveversionId = NULL
Version ID Convention
Version ID format: {repositoryId}/{tag}
Examples:
/facebook/react/v18.3.0
/facebook/react/v17.0.2
/vercel/next.js/v14.3.0-canary.1
API Endpoints
GET /api/v1/libs/:id/versions
Response 200:
{
"versions": [
{
"id": "/facebook/react/v18.3.0",
"repositoryId": "/facebook/react",
"tag": "v18.3.0",
"title": "React v18.3.0",
"state": "indexed",
"totalSnippets": 892,
"indexedAt": "2026-03-22T10:00:00Z"
}
]
}
POST /api/v1/libs/:id/versions
Request body:
{
"tag": "v18.3.0",
"title": "React v18.3.0",
"autoIndex": true
}
Response 201:
{
"version": { ...RepositoryVersion },
"job": { "id": "uuid", "status": "queued" }
}
DELETE /api/v1/libs/:id/versions/:tag
Deletes the version record and all associated documents/snippets via cascade.
Response 204.
POST /api/v1/libs/:id/versions/:tag/index
Queues an indexing job for this specific version tag.
Response 202 with job details.
GitHub Tag Discovery
async function listGitHubTags(
owner: string,
repo: string,
token?: string
): Promise<Array<{ name: string; commit: { sha: string } }>> {
const headers: Record<string, string> = {
Accept: 'application/vnd.github.v3+json',
'User-Agent': 'TrueRef/1.0'
};
if (token) headers['Authorization'] = `Bearer ${token}`;
const response = await fetch(`https://api.github.com/repos/${owner}/${repo}/tags?per_page=100`, {
headers
});
if (!response.ok) throw new GitHubApiError(response.status);
return response.json();
}
Query Routing
In the search/context endpoints, the libraryId is parsed to extract the optional version:
function resolveSearchTarget(libraryId: string): {
repositoryId: string;
versionId?: string;
} {
const { repositoryId, version } = parseLibraryId(libraryId);
if (!version) {
// Query default branch: versionId = NULL
return { repositoryId };
}
// Look up versionId from tag
const versionRecord = db
.prepare(`SELECT id FROM repository_versions WHERE repository_id = ? AND tag = ?`)
.get(repositoryId, version) as { id: string } | undefined;
if (!versionRecord) {
throw new NotFoundError(`Version "${version}" not found for library "${repositoryId}"`);
}
return { repositoryId, versionId: versionRecord.id };
}
Snippets with version_id IS NULL belong to the default branch; snippets with a version_id belong to that specific version. Search queries filter by version_id = ? or version_id IS NULL accordingly.
Version Service
export class VersionService {
constructor(private db: BetterSQLite3.Database) {}
list(repositoryId: string): RepositoryVersion[];
add(repositoryId: string, tag: string, title?: string): RepositoryVersion;
remove(repositoryId: string, tag: string): void;
getByTag(repositoryId: string, tag: string): RepositoryVersion | null;
registerFromConfig(
repositoryId: string,
previousVersions: { tag: string; title: string }[]
): RepositoryVersion[];
}
Files to Create
src/lib/server/services/version.service.tssrc/routes/api/v1/libs/[id]/versions/+server.ts— GET, POSTsrc/routes/api/v1/libs/[id]/versions/[tag]/+server.ts— DELETEsrc/routes/api/v1/libs/[id]/versions/[tag]/index/+server.ts— POSTsrc/lib/server/crawler/github-tags.ts