A decentralized File Discovery and Verification library built on Ergo blockchain. This library provides both Svelte components and TypeScript functions for building file source applications with reputation-based trust mechanisms.
npm install source-application- Decentralized File Discovery: Find and share download sources for files by hash
- Reputation System: Trust-based verification using Ergo blockchain reputation proofs
- Opinion Mechanisms: Confirm, invalidate, or mark sources as unavailable
- Profile Management: Create and manage user reputation profiles
- Island Components: Three ready-to-use Svelte components that work standalone
- TypeScript SDK: Full API for custom integrations
Profile creation and basic information display.
Props:
profile: ReputationProof | null- Current user's profileexplorerUri: string- Ergo Explorer API endpointsource_explorer_url: string- Base URL for the source explorer (used for deep links)onProfileCreated?: (txId: string) => void- Callback when profile is created
Usage:
<script>
import { ProfileCard } from 'source-application';
let profile = null;
let explorerUri = "https://api.ergoplatform.com";
let source_explorer_url = "https://source-explorer.io";
</script>
<ProfileCard
{profile}
{explorerUri}
{source_explorer_url}
onProfileCreated={(tx) => console.log('Profile created:', tx)}
/>Form for adding new file sources to the network. It supports two modes: a "free" mode where the user provides the hash, and a "fixed" mode where the hash is pre-defined and the component validates the provided URL.
Props:
profile: ReputationProof | null- Current user's profile (required to enable adding).explorerUri: string- Ergo Explorer API endpoint.source_explorer_url: string- Base URL for the source explorer (used for deep links).fixed_hash_id?: string- Optional. Fixed file hash. When provided, the component enters fixed mode and the user cannot edit the anchor hash.hash?: Writable<string>- Optional. A Svelte writable store for the file hash.fixedHashFunctionId?: string- Optional. Hash algorithm ID for the fixed anchor hash. Use the canonicalHASH("")value. In fixed mode the default is Blake2b-256:0e5751c026e543b2e8ab2eb06099daa1d1e5df47778f7787faab45cdf12fe3a8.title?: string- Optional. Custom title for the component (default: "Add New File Source").onSourceAdded?: (txId: string) => void- Callback when source is added.
Behavior:
- Always Visible: The current hash is always displayed at the top of the component.
- Fixed Hash Mode (when
fixed_hash_idis provided, or when thehashstore has a value):- Manual hash input and file upload fields are hidden.
fixed_hash_idtakes precedence over thehashstore if both are provided.- The anchor hash function comes from
fixedHashFunctionIdinstead of the form UI. - The "Compute hash from URL" button is hidden.
- When clicking "Add Source", the component automatically downloads the file from the URL, calculates its hash, and verifies it matches the fixed hash before proceeding.
- If the source-entry hash function id is omitted, the component stores the same canonical algorithm id used by the fixed anchor hash.
- Source-entry metadata such as content hash and formats remain optional.
- Free Mode (when
hashstore is empty or undefined):- User can provide the hash manually.
- User can upload a local file to calculate its hash.
- User can provide a URL and click the download icon to calculate the hash from the remote file.
Usage:
<script>
import { FileSourceCreation } from 'source-application';
import { writable } from 'svelte/store';
let profile = { ... }; // Load from fetchProfile
let explorerUri = "https://api.ergoplatform.com";
let source_explorer_url = "https://source-explorer.io";
// Fixed mode
let fileHashStore = writable("abc123...");
// Free mode
// let fileHashStore = writable("");
</script>
<FileSourceCreation
{profile}
{explorerUri}
{source_explorer_url}
fixed_hash_id="abc123..."
hash={fileHashStore}
fixedHashFunctionId="0e5751c026e543b2e8ab2eb06099daa1d1e5df47778f7787faab45cdf12fe3a8"
title="Add Download Link"
onSourceAdded={(tx) => console.log('Source added:', tx)}
/>Complete file source display for a specific file hash, including tabs for sources, profile views, and timeline.
Props:
fileHash: string- The Blake2b256 hash of the file to display (required)profile: ReputationProof | null- The current user's profile (optional, for enabling actions)sources: FileSource[]- List of sources for this hashinvalidFileSources: CachedData<InvalidFileSource[]>- Map of invalidationsunavailableSources: CachedData<UnavailableSource[]>- Map of unavailabilitiesisLoading: boolean- Loading stateexplorerUri: string- Ergo Explorer API endpointsource_explorer_url: string- Base URL for the source explorer (used for deep links)webExplorerUriTkn: string- Web explorer token link templateclass?: string- CSS class for the container (optional)
Usage:
<script>
import { FileCard } from 'source-application';
let fileHash = "abc123...";
let profile = null;
let explorerUri = "https://api.ergoplatform.com";
let source_explorer_url = "https://source-explorer.io";
let webExplorerUriTkn = "https://sigmaspace.io/en/token/";
</script>
<FileCard
{fileHash}
{profile}
{explorerUri}
{source_explorer_url}
{webExplorerUriTkn}
sources={[]}
invalidFileSources={{}}
unavailableSources={{}}
isLoading={false}
/>Display a single file source with voting and editing actions.
Props:
source: FileSource- The file source to displayprofile: ReputationProof | null- The current user's profileinvalidations: InvalidFileSource[]- List of invalidations for this sourceunavailabilities: UnavailableSource[]- List of unavailabilities for this sourceexplorerUri: string- Ergo Explorer API endpointsource_explorer_url: string- Base URL for the source explorer (used for deep links)webExplorerUriTx: string- Web explorer transaction link templatewebExplorerUriTkn: string- Web explorer token link template
Usage:
<script>
import { FileSourceCard } from 'source-application';
let source = { ... };
let profile = null;
let explorerUri = "https://api.ergoplatform.com";
let source_explorer_url = "https://source-explorer.io";
let webExplorerUriTx = "https://sigmaspace.io/en/tx/";
let webExplorerUriTkn = "https://sigmaspace.io/en/token/";
</script>
<FileSourceCard
{source}
{profile}
{explorerUri}
{source_explorer_url}
{webExplorerUriTx}
{webExplorerUriTkn}
invalidations={[]}
unavailabilities={[]}
/>Create a new reputation profile for the user.
import { createProfileBox } from 'source-application';
const txId = await createProfileBox(explorerUri);
// Returns: string (transaction ID)Fetch all FILE_SOURCE boxes for a specific file hash.
import { fetchFileSourcesByHash } from 'source-application';
const sources = await fetchFileSourcesByHash("abc123...", explorerUri);
// Returns: FileSource[]Fetch all file sources created by a specific profile.
import { fetchFileSourcesByProfile } from 'source-application';
const sources = await fetchFileSourcesByProfile(profileTokenId, limit, explorerUri);
// Returns: FileSource[]fetchInvalidFileSources(sourceBoxId, explorerUri)- Get invalidations for a sourcefetchUnavailableSources(sourceUrl, explorerUri)- Get unavailability reports for a URLfetchProfileOpinions(profileTokenId, explorerUri)- Get trust/distrust opinions for a profilefetchInvalidFileSourcesByProfile(profileTokenId, limit, explorerUri)- Get invalidations by profilefetchUnavailableSourcesByProfile(profileTokenId, limit, explorerUri)- Get unavailabilities by profilefetchProfileOpinionsByAuthor(authorTokenId, explorerUri)- Get opinions given by a profilesearchByHash(fileHash, explorerUri)- Load file sources, invalidations, and unavailabilitiesloadProfileData(profileTokenId, explorerUri)- Load all data related to a profile
Add a new file source to the network.
import { addFileSource } from 'source-application';
const txId = await addFileSource(
"abc123...", // file hash
"https://example.com/file.zip", // source URL
profile, // ReputationProof
explorerUri
);Confirm an existing file source (create duplicate FILE_SOURCE).
import { confirmSource } from 'source-application';
const txId = await confirmSource(
"abc123...", // file hash
"https://example.com/file.zip", // source URL
profile, // ReputationProof
currentSources, // FileSource[]
explorerUri
);Mark a file source as fake or incorrect.
import { markInvalidSource } from 'source-application';
const txId = await markInvalidSource(sourceBoxId, profile, explorerUri);Mark a source URL as no longer available.
import { markUnavailableSource } from 'source-application';
const txId = await markUnavailableSource(sourceUrl, profile, explorerUri);Update an existing file source with a new URL.
import { updateFileSource } from 'source-application';
const txId = await updateFileSource(
oldBoxId,
fileHash,
newSourceUrl,
profile,
explorerUri
);Express trust or distrust for a profile.
import { trustProfile } from 'source-application';
const txId = await trustProfile(profileTokenId, isTrusted, profile, explorerUri);Group file sources by their download URL.
import { groupByDownloadSource } from 'source-application';
const groups = groupByDownloadSource(
sources,
invalidationsMap,
unavailabilitiesMap
);
// Returns: DownloadSourceGroup[]Group file sources by the profile that submitted them.
import { groupByProfile } from 'source-application';
const groups = groupByProfile(sources);
// Returns: ProfileSourceGroup[]Calculate trust score for a profile based on opinions.
import { calculateProfileTrust } from 'source-application';
const trustScore = calculateProfileTrust(profileTokenId, opinions);
// Returns: numberAggregate all opinion data for a file source.
import { aggregateSourceScore } from 'source-application';
const scoreData = aggregateSourceScore(
source,
allSources,
invalidations,
unavailabilities,
profileOpinions
);
// Returns: FileSourceWithScoreimport type {
FileSource,
InvalidFileSource,
UnavailableSource,
ProfileOpinion,
ReputationProof,
RPBox,
CachedData,
SearchResult,
ProfileData
} from 'source-application';import {
PROFILE_TYPE_NFT_ID,
FILE_SOURCE_TYPE_NFT_ID,
INVALID_FILE_SOURCE_TYPE_NFT_ID,
UNAVAILABLE_SOURCE_TYPE_NFT_ID,
PROFILE_OPINION_TYPE_NFT_ID,
PROFILE_TOTAL_SUPPLY
} from 'source-application';- All blockchain interactions require an Ergo wallet connection.
- The library does not include internal stores; state management should be handled by the consuming application.
- Components are self-contained and receive data via props.
- All URLs are sanitized for security.
MIT