Browse Source

bug-fixes

Nostr-Signature: 3618c494d594408165ebf461e290676817ab6cc8b0b076ccc02b35a487ae8da1 573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc d9106ce1318e703df1c366835be69c0cab12fba3a9be0fed944b17e55fd3b44f3fc9d45b32366d1d237452f099ab3b07f8ad6199660972ce571ec23ae264e873
main
Silberengel 2 weeks ago
parent
commit
e8e14ede79
  1. 1
      nostr/commit-signatures.jsonl
  2. 20
      src/routes/api/repos/[npub]/[repo]/clone/+server.ts
  3. 14
      src/routes/api/repos/list/+server.ts
  4. 18
      src/routes/repos/[npub]/[repo]/+page.svelte
  5. 77
      src/routes/repos/[npub]/[repo]/services/repo-operations.ts

1
nostr/commit-signatures.jsonl

@ -125,3 +125,4 @@ @@ -125,3 +125,4 @@
{"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1772296288,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","administer the repos"]],"content":"Signed commit: administer the repos","id":"8825fb9bd01e099c1369f0c9ea1429dedd0a0116d103b4a640752c0a830fbc61","sig":"676f0817f817204ad910a70540399f71743a54453ae209535dcb30356d042b049138d9cfdeec08c4b7da03bb6bb51c71477bbf8d2f58bd4b602b9f69af4b3405"}
{"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1772298906,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","bug-fixes"]],"content":"Signed commit: bug-fixes","id":"6aa4dcd1b3d8a933710a6eb43321aa4faaba56598c735a634069c882c83b4f03","sig":"80ce253e890e8e84c8138e004bc2aaea402379d9aa67f62793ac7a4b344de6a7223f46fc733b240215a983a3a9b574ea8d0858a184f06df58ee66212ba58ee53"}
{"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1772299137,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","more-muted replyt-to"]],"content":"Signed commit: more-muted replyt-to","id":"fc0a91b526083b640d8116592fcac064fcf3cec9625b48dbd41c3877b2fe5444","sig":"998273d70d827ffbb939b4c149ff88e11c9f3aae3c5ddee78d860710f7fbff42c5ceed9433367b530bdc2869f9d382eb449537f813cf745c49f1a87a36926502"}
{"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1772299733,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","make relay timeouts more efficient\nsuppress diff on initial commit"]],"content":"Signed commit: make relay timeouts more efficient\nsuppress diff on initial commit","id":"5fbc2dfb13acab011df5a394a022267e69bbe908e696c4389e0c07ba83d58a0d","sig":"daf46d563c413e2481be2cbd2b00d3015cf601e19fe0a191ffbb18c2c07508b17e34ebda5c903a1391914f991cecd7a7a4e809fcba45e1f14ebab674117eb53c"}

20
src/routes/api/repos/[npub]/[repo]/clone/+server.ts

@ -303,10 +303,22 @@ export const POST: RequestHandler = async (event) => { @@ -303,10 +303,22 @@ export const POST: RequestHandler = async (event) => {
}, 'Repository announcement clone URLs');
// Attempt to clone the repository
logger.debug({ npub, repo, preferredDefaultBranch, hasAnnouncement: !!announcementEvent }, 'Calling fetchRepoOnDemand');
const result = await repoManager.fetchRepoOnDemand(npub, repo, announcementEvent, preferredDefaultBranch);
logger.debug({
npub,
repo,
success: result.success,
error: result.error,
needsAnnouncement: result.needsAnnouncement,
cloneUrls: result.cloneUrls?.length || 0,
remoteUrls: result.remoteUrls?.length || 0
}, 'fetchRepoOnDemand result');
if (!result.success) {
if (result.needsAnnouncement) {
logger.error({ npub, repo }, 'Clone failed: Repository announcement is required');
throw handleValidationError(
'Repository announcement is required. Please provide an announcement event or create one.',
{ operation: 'cloneRepo', npub, repo }
@ -323,16 +335,18 @@ export const POST: RequestHandler = async (event) => { @@ -323,16 +335,18 @@ export const POST: RequestHandler = async (event) => {
} else if (result.remoteUrls && result.remoteUrls.length === 0) {
errorMessage += ' No accessible remote clone URLs found.';
} else if (result.cloneUrls && result.cloneUrls.length > 0) {
errorMessage += ` Attempted to clone from: ${result.cloneUrls.join(', ')}`;
errorMessage += ` Attempted to clone from: ${result.cloneUrls.slice(0, 3).join(', ')}${result.cloneUrls.length > 3 ? '...' : ''}`;
}
logger.error({
npub,
repo,
error: result.error,
errorMessage,
cloneUrls: result.cloneUrls,
remoteUrls: result.remoteUrls
}, 'Failed to clone repository');
remoteUrls: result.remoteUrls,
needsAnnouncement: result.needsAnnouncement
}, 'Failed to clone repository - fetchRepoOnDemand returned success: false');
throw handleApiError(
new Error(result.error || 'Failed to clone repository from remote URLs'),

14
src/routes/api/repos/list/+server.ts

@ -15,10 +15,16 @@ import { extractRequestContext } from '$lib/utils/api-context.js'; @@ -15,10 +15,16 @@ import { extractRequestContext } from '$lib/utils/api-context.js';
import logger from '$lib/services/logger.js';
import type { NostrEvent } from '$lib/types/nostr.js';
import type { RequestEvent } from '@sveltejs/kit';
import { existsSync } from 'fs';
import { join, resolve } from 'path';
const nostrClient = new NostrClient(DEFAULT_NOSTR_RELAYS);
const maintainerService = new MaintainerService(DEFAULT_NOSTR_RELAYS);
const repoRoot = typeof process !== 'undefined' && process.env?.GIT_REPO_ROOT
? resolve(process.env.GIT_REPO_ROOT)
: resolve('/repos');
interface RepoListItem {
event: NostrEvent;
npub: string;
@ -90,6 +96,14 @@ export const GET: RequestHandler = async (event) => { @@ -90,6 +96,14 @@ export const GET: RequestHandler = async (event) => {
npub = nip19.npubEncode(event.pubkey);
}
// Only include repos that actually exist locally on the server
// This ensures deleted repos don't show up in the list
const repoPath = join(repoRoot, npub, `${dTag}.git`);
if (!existsSync(repoPath)) {
logger.debug({ npub, repoName: dTag, repoPath }, 'Skipping repo - does not exist locally');
continue;
}
repos.push({
event,
npub,

18
src/routes/repos/[npub]/[repo]/+page.svelte

@ -1410,24 +1410,6 @@ @@ -1410,24 +1410,6 @@
</div>
</div>
{/if}
{#if state.error}
<div class="state.error">
<div class="state.error-message">
<strong>Error:</strong> {state.error}
</div>
{#if state.error.includes('not cloned locally') && hasUnlimitedAccess($userStore.userLevel)}
<div class="state.error-actions">
<button
class="clone-button-inline"
onclick={cloneRepository}
disabled={state.clone.cloning || state.clone.checking}
>
{state.clone.cloning ? 'Cloning...' : (state.clone.checking ? 'Checking...' : 'Clone to Server')}
</button>
</div>
{/if}
</div>
{/if}
<!-- Tabs - only show if we have repo data (header/clone section would be visible) -->
{#if repoOwnerPubkeyDerived}

77
src/routes/repos/[npub]/[repo]/services/repo-operations.ts

@ -225,20 +225,51 @@ export async function cloneRepository( @@ -225,20 +225,51 @@ export async function cloneRepository(
const cloneUrl = `/api/repos/${state.npub}/${state.repo}/clone`;
logger.debug({ url: cloneUrl }, '[Clone] POST request URL');
const data = await apiPost<{ alreadyExists?: boolean }>(cloneUrl, requestBody);
const data = await apiPost<{ alreadyExists?: boolean; success?: boolean; message?: string }>(cloneUrl, requestBody);
logger.debug({ data }, '[Clone] Clone request successful');
// Check if the response indicates success
if (data.success === false) {
const errorMsg = data.message || 'Failed to clone repository';
logger.error({ npub: state.npub, repo: state.repo, data }, '[Clone] Clone endpoint returned success: false');
alert(`Error: ${errorMsg}`);
throw new Error(errorMsg);
}
if (data.alreadyExists) {
alert('Repository already exists locally.');
// Force refresh clone status
await callbacks.checkCloneStatus(true);
} else {
alert('Repository cloned successfully! The repository is now available on this server.');
// Force refresh clone status
alert('Repository clone initiated. Waiting for clone to complete...');
// Start polling for clone status with a delay
// Clone operation may take time, so we poll every 2 seconds
const pollInterval = 2000; // 2 seconds
const maxAttempts = 30; // Maximum 60 seconds (30 * 2s)
let attempts = 0;
let pollTimer: ReturnType<typeof setInterval> | null = null;
const pollCloneStatus = async () => {
attempts++;
logger.debug({ attempts, maxAttempts }, '[Clone] Polling clone status');
// Check clone status
await callbacks.checkCloneStatus(true);
// If repo is now cloned, stop polling and reload data
if (state.clone.isCloned === true) {
if (pollTimer) {
clearInterval(pollTimer);
pollTimer = null;
}
logger.info({ attempts }, '[Clone] Repository confirmed cloned, reloading data');
// Reset API fallback status since repo is now cloned
state.clone.apiFallbackAvailable = false;
// Reload data to use the cloned repo instead of API
await Promise.all([
callbacks.loadBranches(),
@ -247,6 +278,25 @@ export async function cloneRepository( @@ -247,6 +278,25 @@ export async function cloneRepository(
callbacks.loadTags(),
callbacks.loadCommitHistory()
]);
logger.info('[Clone] Repository data reloaded successfully');
} else if (attempts >= maxAttempts) {
// Stop polling after max attempts
if (pollTimer) {
clearInterval(pollTimer);
pollTimer = null;
}
logger.warn({ attempts }, '[Clone] Polling timeout - clone may still be in progress');
alert('Clone operation is taking longer than expected. The repository may still be cloning in the background. Please refresh the page in a moment.');
}
};
// Start polling after initial delay of 2 seconds
setTimeout(() => {
pollCloneStatus(); // First check immediately after delay
pollTimer = setInterval(pollCloneStatus, pollInterval);
}, pollInterval);
}
} catch (err) {
const errorMessage = err instanceof Error ? err.message : 'Failed to clone repository';
@ -254,9 +304,26 @@ export async function cloneRepository( @@ -254,9 +304,26 @@ export async function cloneRepository(
error: err,
npub: state.npub,
repo: state.repo,
errorMessage
errorMessage,
errorStack: err instanceof Error ? err.stack : undefined
}, '[Clone] Clone request failed');
alert(`Error: ${errorMessage}`);
// Extract more detailed error message if available
let userFriendlyMessage = errorMessage;
if (err instanceof Error) {
// Check if it's a network error
if (errorMessage.includes('fetch') || errorMessage.includes('network') || errorMessage.includes('Failed to fetch')) {
userFriendlyMessage = 'Network error: Unable to connect to the server. Please check your connection and try again.';
} else if (errorMessage.includes('403') || errorMessage.includes('Forbidden')) {
userFriendlyMessage = 'Access denied: You do not have permission to clone this repository. Please verify you have unlimited access.';
} else if (errorMessage.includes('404') || errorMessage.includes('Not found')) {
userFriendlyMessage = 'Repository not found: The repository announcement may not exist or the repository name may be incorrect.';
} else if (errorMessage.includes('timeout') || errorMessage.includes('timed out')) {
userFriendlyMessage = 'Clone operation timed out. The repository may be too large or the remote server may be slow. Please try again.';
}
}
alert(`Error cloning repository: ${userFriendlyMessage}`);
console.error('Error cloning repository:', err);
} finally {
state.clone.cloning = false;

Loading…
Cancel
Save