{"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1771829031,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","fix file management and refactor"]],"content":"Signed commit: fix file management and refactor","id":"626196cdbf9eab28b44990706281878083d66983b503e8a81df7421054ed6caf","sig":"516c0001a800083411a1e04340e82116a82c975f38b984e92ebe021b61271ba7d6f645466ddba3594320c228193e708675a5d7a144b2f3d5e9bfbc65c4c7372b"}
{"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1771829031,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","fix file management and refactor"]],"content":"Signed commit: fix file management and refactor","id":"626196cdbf9eab28b44990706281878083d66983b503e8a81df7421054ed6caf","sig":"516c0001a800083411a1e04340e82116a82c975f38b984e92ebe021b61271ba7d6f645466ddba3594320c228193e708675a5d7a144b2f3d5e9bfbc65c4c7372b"}
{"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1771836045,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","fix repo management and refactor\nimplement more GRASP support"]],"content":"Signed commit: fix repo management and refactor\nimplement more GRASP support","id":"6ae016621b13e22809e7bcebe34e5250fd6e0767d2b12ca634104def4ca78a29","sig":"99c34f66a8a67d352622621536545b7dee11cfd9d14a007ec0550d138109116a2f24483c6836fea59b94b9e96066fba548bcb7600bc55adbe0562d999c3c651d"}
{"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1771836045,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","fix repo management and refactor\nimplement more GRASP support"]],"content":"Signed commit: fix repo management and refactor\nimplement more GRASP support","id":"6ae016621b13e22809e7bcebe34e5250fd6e0767d2b12ca634104def4ca78a29","sig":"99c34f66a8a67d352622621536545b7dee11cfd9d14a007ec0550d138109116a2f24483c6836fea59b94b9e96066fba548bcb7600bc55adbe0562d999c3c651d"}
async function deleteLocalRepo(npub: string, repo: string) {
async function deleteLocalRepo(npub: string, repo: string) {
if (!confirm(`⚠️Are you sure you want to delete the local clone of "${repo}"?\n\nThis will permanently remove the repository from this server. The announcement on Nostr will NOT be deleted.\n\nThis action cannot be undone.\n\nClick OK to delete, or Cancel to abort.`)) {
if (!confirm(`Are you sure you want to delete the local clone of "${repo}"?\n\nThis will permanently remove the repository from this server. The announcement on Nostr will NOT be deleted.\n\nThis action cannot be undone.\n\nClick OK to delete, or Cancel to abort.`)) {
if (!confirm('⚠️WARNING: Are you sure you want to delete this repository announcement?\n\nThis will permanently delete the repository announcement from Nostr relays. This action CANNOT be undone.\n\nClick OK to continue, or Cancel to abort.')) {
if (!confirm('WARNING: Are you sure you want to delete this repository announcement?\n\nThis will permanently delete the repository announcement from Nostr relays. This action CANNOT be undone.\n\nClick OK to continue, or Cancel to abort.')) {
return;
return;
}
}
// Second confirmation for critical operation
// Second confirmation for critical operation
if (!confirm('⚠️FINAL CONFIRMATION: This will permanently delete the repository announcement.\n\nAre you absolutely certain you want to proceed?\n\nThis action CANNOT be undone.')) {
if (!confirm('FINAL CONFIRMATION: This will permanently delete the repository announcement.\n\nAre you absolutely certain you want to proceed?\n\nThis action CANNOT be undone.')) {
return;
return;
}
}
@ -2714,6 +2761,11 @@
});
});
if (response.ok) {
if (response.ok) {
branches = await response.json();
branches = await response.json();
// If repo is not cloned but we got branches, API fallback is available
if (isRepoCloned === false && branches.length > 0) {
apiFallbackAvailable = true;
}
if (branches.length > 0) {
if (branches.length > 0) {
// Branches can be an array of objects with .name property or array of strings
// Branches can be an array of objects with .name property or array of strings
const branchNames = branches.map((b: any) => typeof b === 'string' ? b : b.name);
const branchNames = branches.map((b: any) => typeof b === 'string' ? b : b.name);
@ -2762,9 +2814,24 @@
}
}
}
}
} else if (response.status === 404) {
} else if (response.status === 404) {
// Check if this is a "not cloned" error with API fallback suggestion
if (errorText.includes('not cloned locally') && errorText.includes('API')) {
// API fallback might be available, but this specific request failed
// Try to detect if API fallback works by checking if we have clone URLs
if (pageData.repoCloneUrls && pageData.repoCloneUrls.length > 0) {
// We have clone URLs, so API fallback might work - mark as unknown for now
// It will be set to true if a subsequent request succeeds
apiFallbackAvailable = null;
} else {
apiFallbackAvailable = false;
}
} else {
// Repository not provisioned yet - set error message and flag
// Repository not provisioned yet - set error message and flag
repoNotFound = true;
repoNotFound = true;
error = `Repository not found. This repository exists in Nostr but hasn't been provisioned on this server yet. The server will automatically provision it soon, or you can contact the server administrator.`;
error = `Repository not found. This repository exists in Nostr but hasn't been provisioned on this server yet. The server will automatically provision it soon, or you can contact the server administrator.`;
apiFallbackAvailable = false;
}
} else if (response.status === 403) {
} else if (response.status === 403) {
// Access denied - don't set repoNotFound, allow retry after login
// Access denied - don't set repoNotFound, allow retry after login
if (errorText.includes('not cloned locally') && errorText.includes('API')) {
// API fallback might be available, but this specific request failed
if (pageData.repoCloneUrls && pageData.repoCloneUrls.length > 0) {
apiFallbackAvailable = null; // Unknown, will be set if a request succeeds
} else {
apiFallbackAvailable = false;
}
} else {
repoNotFound = true;
repoNotFound = true;
apiFallbackAvailable = false;
}
throw new Error(`Repository not found. This repository exists in Nostr but hasn't been provisioned on this server yet. The server will automatically provision it soon, or you can contact the server administrator.`);
throw new Error(`Repository not found. This repository exists in Nostr but hasn't been provisioned on this server yet. The server will automatically provision it soon, or you can contact the server administrator.`);
} else if (response.status === 403) {
} else if (response.status === 403) {
// 403 means access denied - don't set repoNotFound, just show error
// 403 means access denied - don't set repoNotFound, just show error
@ -2823,6 +2902,11 @@
files = await response.json();
files = await response.json();
currentPath = path;
currentPath = path;
// If repo is not cloned but we got files, API fallback is available
if (isRepoCloned === false && files.length > 0) {
apiFallbackAvailable = true;
}
// Auto-load README if we're in the root directory and no file is currently selected
// Auto-load README if we're in the root directory and no file is currently selected
// Only attempt once per path to prevent loops
// Only attempt once per path to prevent loops
if (path === '' && !currentFile && !readmeAutoLoadAttempted) {
if (path === '' && !currentFile && !readmeAutoLoadAttempted) {
@ -3613,7 +3697,7 @@
}
}
async function deleteFile(filePath: string) {
async function deleteFile(filePath: string) {
if (!confirm(`⚠️Are you sure you want to delete "${filePath}"?\n\nThis will permanently delete the file from the repository. This action cannot be undone.\n\nClick OK to delete, or Cancel to abort.`)) {
if (!confirm(`Are you sure you want to delete "${filePath}"?\n\nThis will permanently delete the file from the repository. This action cannot be undone.\n\nClick OK to delete, or Cancel to abort.`)) {
return;
return;
}
}
@ -3741,7 +3825,7 @@
}
}
async function deleteBranch(branchName: string) {
async function deleteBranch(branchName: string) {
if (!confirm(`⚠️Are you sure you want to delete the branch "${branchName}"?\n\nThis will permanently delete the branch from the repository. This action CANNOT be undone.\n\nClick OK to delete, or Cancel to abort.`)) {
if (!confirm(`Are you sure you want to delete the branch "${branchName}"?\n\nThis will permanently delete the branch from the repository. This action CANNOT be undone.\n\nClick OK to delete, or Cancel to abort.`)) {
<span>This repository is displayed in <strong>read-only mode</strong> using data from external clone URLs. To enable editing and full features, clone this repository to the server.</span>
{#ifhasUnlimitedAccess($userStore.userLevel)}
<button
class="clone-button-banner"
onclick={cloneRepository}
disabled={cloning||checkingCloneStatus}
>
{cloning?'Cloning...':(checkingCloneStatus?'Checking...':'Clone to Server')}