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.
370 lines
13 KiB
370 lines
13 KiB
/** |
|
* API helper functions for ORLY relay management endpoints |
|
*/ |
|
|
|
/** |
|
* Create NIP-98 authentication header |
|
* @param {object} signer - The signer instance |
|
* @param {string} pubkey - User's pubkey |
|
* @param {string} method - HTTP method |
|
* @param {string} url - Request URL |
|
* @returns {Promise<string|null>} Base64 encoded auth header or null |
|
*/ |
|
export async function createNIP98Auth(signer, pubkey, method, url) { |
|
if (!signer || !pubkey) { |
|
console.log("No signer or pubkey available"); |
|
return null; |
|
} |
|
|
|
try { |
|
// Create unsigned auth event |
|
const authEvent = { |
|
kind: 27235, |
|
created_at: Math.floor(Date.now() / 1000), |
|
tags: [ |
|
["u", url], |
|
["method", method], |
|
], |
|
content: "", |
|
}; |
|
|
|
// Sign using the signer |
|
const signedEvent = await signer.signEvent(authEvent); |
|
return btoa(JSON.stringify(signedEvent)); |
|
} catch (error) { |
|
console.error("Error creating NIP-98 auth:", error); |
|
return null; |
|
} |
|
} |
|
|
|
/** |
|
* Fetch user role from the relay |
|
* @param {object} signer - The signer instance |
|
* @param {string} pubkey - User's pubkey |
|
* @returns {Promise<string>} User role |
|
*/ |
|
export async function fetchUserRole(signer, pubkey) { |
|
try { |
|
const url = `${window.location.origin}/api/role`; |
|
const authHeader = await createNIP98Auth(signer, pubkey, "GET", url); |
|
const response = await fetch(url, { |
|
headers: authHeader ? { Authorization: `Nostr ${authHeader}` } : {}, |
|
}); |
|
if (response.ok) { |
|
const data = await response.json(); |
|
return data.role || ""; |
|
} |
|
} catch (error) { |
|
console.error("Error fetching user role:", error); |
|
} |
|
return ""; |
|
} |
|
|
|
/** |
|
* Fetch ACL mode from the relay |
|
* @returns {Promise<string>} ACL mode |
|
*/ |
|
export async function fetchACLMode() { |
|
try { |
|
const response = await fetch(`${window.location.origin}/api/acl-mode`); |
|
if (response.ok) { |
|
const data = await response.json(); |
|
return data.mode || ""; |
|
} |
|
} catch (error) { |
|
console.error("Error fetching ACL mode:", error); |
|
} |
|
return ""; |
|
} |
|
|
|
// ==================== Sprocket API ==================== |
|
|
|
/** |
|
* Load sprocket configuration |
|
* @param {object} signer - The signer instance |
|
* @param {string} pubkey - User's pubkey |
|
* @returns {Promise<object>} Sprocket config data |
|
*/ |
|
export async function loadSprocketConfig(signer, pubkey) { |
|
const url = `${window.location.origin}/api/sprocket/config`; |
|
const authHeader = await createNIP98Auth(signer, pubkey, "GET", url); |
|
const response = await fetch(url, { |
|
headers: authHeader ? { Authorization: `Nostr ${authHeader}` } : {}, |
|
}); |
|
if (!response.ok) throw new Error(`Failed to load config: ${response.statusText}`); |
|
return await response.json(); |
|
} |
|
|
|
/** |
|
* Load sprocket status |
|
* @param {object} signer - The signer instance |
|
* @param {string} pubkey - User's pubkey |
|
* @returns {Promise<object>} Sprocket status data |
|
*/ |
|
export async function loadSprocketStatus(signer, pubkey) { |
|
const url = `${window.location.origin}/api/sprocket/status`; |
|
const authHeader = await createNIP98Auth(signer, pubkey, "GET", url); |
|
const response = await fetch(url, { |
|
headers: authHeader ? { Authorization: `Nostr ${authHeader}` } : {}, |
|
}); |
|
if (!response.ok) throw new Error(`Failed to load status: ${response.statusText}`); |
|
return await response.json(); |
|
} |
|
|
|
/** |
|
* Load sprocket script |
|
* @param {object} signer - The signer instance |
|
* @param {string} pubkey - User's pubkey |
|
* @returns {Promise<string>} Sprocket script content |
|
*/ |
|
export async function loadSprocketScript(signer, pubkey) { |
|
const url = `${window.location.origin}/api/sprocket`; |
|
const authHeader = await createNIP98Auth(signer, pubkey, "GET", url); |
|
const response = await fetch(url, { |
|
headers: authHeader ? { Authorization: `Nostr ${authHeader}` } : {}, |
|
}); |
|
if (response.status === 404) return ""; |
|
if (!response.ok) throw new Error(`Failed to load sprocket: ${response.statusText}`); |
|
return await response.text(); |
|
} |
|
|
|
/** |
|
* Save sprocket script |
|
* @param {object} signer - The signer instance |
|
* @param {string} pubkey - User's pubkey |
|
* @param {string} script - Script content |
|
* @returns {Promise<object>} Save result |
|
*/ |
|
export async function saveSprocketScript(signer, pubkey, script) { |
|
const url = `${window.location.origin}/api/sprocket`; |
|
const authHeader = await createNIP98Auth(signer, pubkey, "PUT", url); |
|
const response = await fetch(url, { |
|
method: "PUT", |
|
headers: { |
|
"Content-Type": "text/plain", |
|
...(authHeader ? { Authorization: `Nostr ${authHeader}` } : {}), |
|
}, |
|
body: script, |
|
}); |
|
if (!response.ok) throw new Error(`Failed to save: ${response.statusText}`); |
|
return await response.json(); |
|
} |
|
|
|
/** |
|
* Restart sprocket |
|
* @param {object} signer - The signer instance |
|
* @param {string} pubkey - User's pubkey |
|
* @returns {Promise<object>} Restart result |
|
*/ |
|
export async function restartSprocket(signer, pubkey) { |
|
const url = `${window.location.origin}/api/sprocket/restart`; |
|
const authHeader = await createNIP98Auth(signer, pubkey, "POST", url); |
|
const response = await fetch(url, { |
|
method: "POST", |
|
headers: authHeader ? { Authorization: `Nostr ${authHeader}` } : {}, |
|
}); |
|
if (!response.ok) throw new Error(`Failed to restart: ${response.statusText}`); |
|
return await response.json(); |
|
} |
|
|
|
/** |
|
* Delete sprocket |
|
* @param {object} signer - The signer instance |
|
* @param {string} pubkey - User's pubkey |
|
* @returns {Promise<object>} Delete result |
|
*/ |
|
export async function deleteSprocket(signer, pubkey) { |
|
const url = `${window.location.origin}/api/sprocket`; |
|
const authHeader = await createNIP98Auth(signer, pubkey, "DELETE", url); |
|
const response = await fetch(url, { |
|
method: "DELETE", |
|
headers: authHeader ? { Authorization: `Nostr ${authHeader}` } : {}, |
|
}); |
|
if (!response.ok) throw new Error(`Failed to delete: ${response.statusText}`); |
|
return await response.json(); |
|
} |
|
|
|
/** |
|
* Load sprocket versions |
|
* @param {object} signer - The signer instance |
|
* @param {string} pubkey - User's pubkey |
|
* @returns {Promise<Array>} Version list |
|
*/ |
|
export async function loadSprocketVersions(signer, pubkey) { |
|
const url = `${window.location.origin}/api/sprocket/versions`; |
|
const authHeader = await createNIP98Auth(signer, pubkey, "GET", url); |
|
const response = await fetch(url, { |
|
headers: authHeader ? { Authorization: `Nostr ${authHeader}` } : {}, |
|
}); |
|
if (!response.ok) throw new Error(`Failed to load versions: ${response.statusText}`); |
|
return await response.json(); |
|
} |
|
|
|
/** |
|
* Load specific sprocket version |
|
* @param {object} signer - The signer instance |
|
* @param {string} pubkey - User's pubkey |
|
* @param {string} version - Version filename |
|
* @returns {Promise<string>} Version content |
|
*/ |
|
export async function loadSprocketVersion(signer, pubkey, version) { |
|
const url = `${window.location.origin}/api/sprocket/versions/${encodeURIComponent(version)}`; |
|
const authHeader = await createNIP98Auth(signer, pubkey, "GET", url); |
|
const response = await fetch(url, { |
|
headers: authHeader ? { Authorization: `Nostr ${authHeader}` } : {}, |
|
}); |
|
if (!response.ok) throw new Error(`Failed to load version: ${response.statusText}`); |
|
return await response.text(); |
|
} |
|
|
|
/** |
|
* Delete sprocket version |
|
* @param {object} signer - The signer instance |
|
* @param {string} pubkey - User's pubkey |
|
* @param {string} filename - Version filename |
|
* @returns {Promise<object>} Delete result |
|
*/ |
|
export async function deleteSprocketVersion(signer, pubkey, filename) { |
|
const url = `${window.location.origin}/api/sprocket/versions/${encodeURIComponent(filename)}`; |
|
const authHeader = await createNIP98Auth(signer, pubkey, "DELETE", url); |
|
const response = await fetch(url, { |
|
method: "DELETE", |
|
headers: authHeader ? { Authorization: `Nostr ${authHeader}` } : {}, |
|
}); |
|
if (!response.ok) throw new Error(`Failed to delete version: ${response.statusText}`); |
|
return await response.json(); |
|
} |
|
|
|
/** |
|
* Upload sprocket script file |
|
* @param {object} signer - The signer instance |
|
* @param {string} pubkey - User's pubkey |
|
* @param {File} file - File to upload |
|
* @returns {Promise<object>} Upload result |
|
*/ |
|
export async function uploadSprocketScript(signer, pubkey, file) { |
|
const content = await file.text(); |
|
return await saveSprocketScript(signer, pubkey, content); |
|
} |
|
|
|
// ==================== Policy API ==================== |
|
|
|
/** |
|
* Load policy configuration |
|
* @param {object} signer - The signer instance |
|
* @param {string} pubkey - User's pubkey |
|
* @returns {Promise<object>} Policy config |
|
*/ |
|
export async function loadPolicyConfig(signer, pubkey) { |
|
const url = `${window.location.origin}/api/policy/config`; |
|
const authHeader = await createNIP98Auth(signer, pubkey, "GET", url); |
|
const response = await fetch(url, { |
|
headers: authHeader ? { Authorization: `Nostr ${authHeader}` } : {}, |
|
}); |
|
if (!response.ok) throw new Error(`Failed to load policy config: ${response.statusText}`); |
|
return await response.json(); |
|
} |
|
|
|
/** |
|
* Load policy JSON |
|
* @param {object} signer - The signer instance |
|
* @param {string} pubkey - User's pubkey |
|
* @returns {Promise<object>} Policy JSON |
|
*/ |
|
export async function loadPolicy(signer, pubkey) { |
|
const url = `${window.location.origin}/api/policy`; |
|
const authHeader = await createNIP98Auth(signer, pubkey, "GET", url); |
|
const response = await fetch(url, { |
|
headers: authHeader ? { Authorization: `Nostr ${authHeader}` } : {}, |
|
}); |
|
if (!response.ok) throw new Error(`Failed to load policy: ${response.statusText}`); |
|
return await response.json(); |
|
} |
|
|
|
/** |
|
* Validate policy JSON |
|
* @param {object} signer - The signer instance |
|
* @param {string} pubkey - User's pubkey |
|
* @param {string} policyJson - Policy JSON string |
|
* @returns {Promise<object>} Validation result |
|
*/ |
|
export async function validatePolicy(signer, pubkey, policyJson) { |
|
const url = `${window.location.origin}/api/policy/validate`; |
|
const authHeader = await createNIP98Auth(signer, pubkey, "POST", url); |
|
const response = await fetch(url, { |
|
method: "POST", |
|
headers: { |
|
"Content-Type": "application/json", |
|
...(authHeader ? { Authorization: `Nostr ${authHeader}` } : {}), |
|
}, |
|
body: policyJson, |
|
}); |
|
return await response.json(); |
|
} |
|
|
|
/** |
|
* Fetch policy follows whitelist |
|
* @param {object} signer - The signer instance |
|
* @param {string} pubkey - User's pubkey |
|
* @returns {Promise<Array>} List of followed pubkeys |
|
*/ |
|
export async function fetchPolicyFollows(signer, pubkey) { |
|
const url = `${window.location.origin}/api/policy/follows`; |
|
const authHeader = await createNIP98Auth(signer, pubkey, "GET", url); |
|
const response = await fetch(url, { |
|
headers: authHeader ? { Authorization: `Nostr ${authHeader}` } : {}, |
|
}); |
|
if (!response.ok) throw new Error(`Failed to fetch follows: ${response.statusText}`); |
|
const data = await response.json(); |
|
return data.follows || []; |
|
} |
|
|
|
// ==================== Export/Import API ==================== |
|
|
|
/** |
|
* Export events |
|
* @param {object} signer - The signer instance |
|
* @param {string} pubkey - User's pubkey |
|
* @param {Array} authorPubkeys - Filter by authors (empty for all) |
|
* @returns {Promise<Blob>} JSONL blob |
|
*/ |
|
export async function exportEvents(signer, pubkey, authorPubkeys = []) { |
|
const url = `${window.location.origin}/api/export`; |
|
const authHeader = await createNIP98Auth(signer, pubkey, "POST", url); |
|
|
|
const response = await fetch(url, { |
|
method: "POST", |
|
headers: { |
|
"Content-Type": "application/json", |
|
...(authHeader ? { Authorization: `Nostr ${authHeader}` } : {}), |
|
}, |
|
body: JSON.stringify({ pubkeys: authorPubkeys }), |
|
}); |
|
|
|
if (!response.ok) throw new Error(`Export failed: ${response.statusText}`); |
|
return await response.blob(); |
|
} |
|
|
|
/** |
|
* Import events from file |
|
* @param {object} signer - The signer instance |
|
* @param {string} pubkey - User's pubkey |
|
* @param {File} file - JSONL file to import |
|
* @returns {Promise<object>} Import result |
|
*/ |
|
export async function importEvents(signer, pubkey, file) { |
|
const url = `${window.location.origin}/api/import`; |
|
const authHeader = await createNIP98Auth(signer, pubkey, "POST", url); |
|
|
|
const formData = new FormData(); |
|
formData.append("file", file); |
|
|
|
const response = await fetch(url, { |
|
method: "POST", |
|
headers: authHeader ? { Authorization: `Nostr ${authHeader}` } : {}, |
|
body: formData, |
|
}); |
|
|
|
if (!response.ok) throw new Error(`Import failed: ${response.statusText}`); |
|
return await response.json(); |
|
}
|
|
|