You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

131 lines
4.8 KiB

/**
* Page metadata and OpenGraph tags for repository pages
*/
import type { PageLoad } from './$types';
import { NostrClient } from '$lib/services/nostr/nostr-client.js';
import { MaintainerService } from '$lib/services/nostr/maintainer-service.js';
import { DEFAULT_NOSTR_RELAYS } from '$lib/config.js';
import { KIND } from '$lib/types/nostr.js';
import { nip19 } from 'nostr-tools';
import { extractRequestContext } from '$lib/utils/api-context.js';
export const load: PageLoad = async ({ params, url, parent }) => {
const { npub, repo } = params;
if (!npub || !repo) {
return {
title: 'Repository Not Found',
description: 'Repository not found'
};
}
try {
// Decode npub to get pubkey
const decoded = nip19.decode(npub);
if (decoded.type !== 'npub') {
return {
title: 'Invalid Repository',
description: 'Invalid repository identifier'
};
}
const repoOwnerPubkey = decoded.data as string;
// Fetch repository announcement
const nostrClient = new NostrClient(DEFAULT_NOSTR_RELAYS);
const events = await nostrClient.fetchEvents([
{
kinds: [KIND.REPO_ANNOUNCEMENT],
authors: [repoOwnerPubkey],
'#d': [repo],
limit: 1
}
]);
if (events.length === 0) {
return {
title: `${repo} - Repository Not Found`,
description: 'Repository announcement not found'
};
}
const announcement = events[0];
// Check privacy - for private repos, we'll let the API endpoints handle access control
// The page load function runs server-side but doesn't have access to client auth headers
// So we'll mark it as private and let the frontend handle access denial
const maintainerService = new MaintainerService(DEFAULT_NOSTR_RELAYS);
const isPrivate = announcement.tags.some(t =>
(t[0] === 'private' && t[1] === 'true') ||
(t[0] === 't' && t[1] === 'private')
);
// For private repos, we can't check access here (no user context in page load)
// The frontend will need to check access via API and show appropriate error
// We still expose basic metadata (name) but the API will enforce access
const name = announcement.tags.find(t => t[0] === 'name')?.[1] || repo;
const description = announcement.tags.find(t => t[0] === 'description')?.[1] || '';
const image = announcement.tags.find(t => t[0] === 'image')?.[1];
const banner = announcement.tags.find(t => t[0] === 'banner')?.[1];
// Debug: log image and banner tags if found
if (image) console.log('[Page Load] Found image tag:', image);
if (banner) console.log('[Page Load] Found banner tag:', banner);
if (!image && !banner) {
console.log('[Page Load] No image or banner tags found. Available tags:',
announcement.tags.filter(t => t[0] === 'image' || t[0] === 'banner').map(t => t[0]));
}
const cloneUrls = announcement.tags
.filter(t => t[0] === 'clone')
.flatMap(t => t.slice(1))
.filter(url => url && typeof url === 'string') as string[];
const maintainers = announcement.tags
.filter(t => t[0] === 'maintainers')
.flatMap(t => t.slice(1))
.filter(m => m && typeof m === 'string') as string[];
// Owner is the author of the announcement event
const ownerPubkey = announcement.pubkey;
const language = announcement.tags.find(t => t[0] === 'language')?.[1];
const topics = announcement.tags
.filter(t => t[0] === 't' && t[1] !== 'private')
.map(t => t[1])
.filter(t => t && typeof t === 'string') as string[];
const website = announcement.tags.find(t => t[0] === 'website')?.[1];
const isPrivate = announcement.tags.some(t =>
(t[0] === 'private' && t[1] === 'true') ||
(t[0] === 't' && t[1] === 'private')
);
// Get git domain for constructing URLs
const layoutData = await parent();
const gitDomain = (layoutData as { gitDomain?: string }).gitDomain || url.host || 'localhost:6543';
const protocol = gitDomain.startsWith('localhost') ? 'http' : 'https';
const repoUrl = `${protocol}://${gitDomain}/repos/${npub}/${repo}`;
return {
title: `${name} - ${repo}`,
description: description || `Repository: ${name}`,
image: image || banner || undefined,
banner: banner || image || undefined,
repoName: name,
repoDescription: description,
repoUrl,
repoCloneUrls: cloneUrls,
repoMaintainers: maintainers,
repoOwnerPubkey: ownerPubkey,
repoLanguage: language,
repoTopics: topics,
repoWebsite: website,
repoIsPrivate: isPrivate,
ogType: 'website'
};
} catch (error) {
console.error('Error loading repository metadata:', error);
return {
title: `${repo} - Repository`,
description: 'Repository'
};
}
};