import { p as ExternalAccount, Q as SkillSuggestion } from './index-CTzpbW81.js'; import { y as FollowFeedPage, B as FollowProfileItem, q as FeatureAllowlistEntry, s as FeatureFlag } from './feed-BMm9Pkew.js'; import { b as ActivityLabel, t as RepoDeleteResult, w as RepoInventory } from './types-zjv3qDWz.js'; import { z } from 'zod'; import { d as OrgNotificationEmailRequestInput, b as OrgDomainChallengeRequestInput, O as OrgClaimRequestInput, a as OrgProfileUpdateRequestInput, c as OrgDomainVerifyRequestInput } from './org-settings-CZ_tmAYl.js'; /** * Foundation HTTP client for talking to the Sifa AppView. * * Stateless. Consumers supply a {@link SifaApiConfig} per call (the React * hooks read it from context; non-React consumers pass it explicitly). No * singletons, no module-level state. */ /** Configuration passed to every fetcher. */ interface SifaApiConfig { /** Base URL of the sifa-api AppView, e.g. `https://api.sifa.id`. No trailing slash. */ baseUrl: string; /** * Optional fetch implementation. Defaults to {@link globalThis.fetch}. * Lets Next.js consumers pass their cache-enhanced fetch; node/Expo * consumers can leave this unset. */ fetch?: typeof fetch; } /** Options accepted by {@link apiFetch}. */ interface ApiFetchOptions { method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'; /** Request body. Serialized to JSON automatically. */ body?: unknown; /** AbortSignal. Defaults to `AbortSignal.timeout(timeoutMs)` if `timeoutMs` is set. */ signal?: AbortSignal; /** Per-call timeout in milliseconds. Default: 10_000. Ignored if `signal` is provided. */ timeoutMs?: number; /** Retry on HTTP 429 up to 3 times with the server's `Retry-After` delay (capped at 3s). */ retryOn429?: boolean; /** Additional headers. `Content-Type: application/json` is set automatically when `body` is present. */ headers?: Record; credentials?: RequestCredentials; cache?: RequestCache; /** * Next.js-specific cache hints. Ignored on non-Next runtimes. Passed * through transparently as part of {@link RequestInit}. */ next?: { revalidate?: number | false; tags?: string[]; }; } /** Error thrown by {@link apiFetch} on non-2xx responses. */ declare class ApiError extends Error { readonly status: number; readonly body: unknown; constructor(message: string, status: number, body?: unknown); } /** * Generic fetcher used by all SDK query and mutation functions. * * Returns parsed JSON typed as `T`. Throws {@link ApiError} on non-2xx * responses. Use {@link apiFetchOrNull} when 404 should resolve to `null` * instead. */ declare function apiFetch(config: SifaApiConfig, path: string, options?: ApiFetchOptions): Promise; /** * Variant of {@link apiFetch} that resolves to `null` on HTTP 404 instead * of throwing. Useful for "fetch by handle" reads where missing is * expected (e.g. unknown profile). */ declare function apiFetchOrNull(config: SifaApiConfig, path: string, options?: ApiFetchOptions): Promise; /** * Result returned by record-write mutations (create / update / delete). * * Never throws -- writes against the user's PDS can fail in many ways * (network, PDS unreachable, rate limit) and the UI needs structured * results to render appropriate messages. */ interface WriteResult { success: boolean; error?: string; /** * PDS hostname returned by sifa-api when a write failed at the user's * Personal Data Server (issue #167). Lets the UI render * "Your data server (eurosky.social) isn't responding" instead of a * generic "Request failed (500)". */ pdsHost?: string; } /** Result returned by create mutations. Includes the newly created `rkey`. */ interface CreateResult extends WriteResult { rkey?: string; } /** * Write mutation against the Sifa AppView. Wraps {@link apiFetch} with the * never-throws contract used by all sifa-web mutations: returns a * structured {@link WriteResult} on both success and failure, and * preserves the `pdsHost` field when the AppView reports a PDS-side * failure (issue #167). * * On success: returns `{ success: true, ...payload }` where `payload` is * whatever the server returned in JSON (or `{}` for 204). * * On failure: returns `{ success: false, error, pdsHost? }`. Never throws. * * Use {@link apiWriteCreate} when you specifically need the `rkey` from a * create response folded into the result shape. */ declare function apiWrite>(config: SifaApiConfig, path: string, method: 'POST' | 'PUT' | 'DELETE' | 'PATCH', options?: Omit): Promise; /** * Write mutation that expects the server to return a record key (`rkey`) * in its response body. Wraps {@link apiWrite} and folds the `rkey` into * the result shape so consumers get `{ success, rkey?, error?, pdsHost? }`. * * If the server returns additional fields (e.g. `feedUrl` from external * account creation), pass them via the `TExtra` generic to keep them * typed. */ declare function apiWriteCreate>(config: SifaApiConfig, path: string, body: unknown, options?: Omit): Promise; /** Industry/domain entry on the profile self record. */ interface ProfileIndustryInput { industry: string; domain?: string; } /** * Location payload accepted by `updateProfileSelf`. * * Accepts both shapes during the community.lexicon.location.address * migration. Prefer `locality` (new) over `city` (legacy) when sending. * The API's locationSchema is a Zod union that resolves either input. */ interface ProfileSelfLocation { country: string; countryCode?: string; region?: string; city?: string; locality?: string; } /** Body accepted by {@link updateProfileSelf}. */ interface UpdateProfileSelfInput { headline?: string; about?: string; /** Schema.org Person.givenName from id.sifa.profile.self.givenName. */ givenName?: string; /** Schema.org Person.familyName from id.sifa.profile.self.familyName. */ familyName?: string; /** Free-form phonetic respelling of the name from id.sifa.profile.self.namePronunciation. */ namePronunciation?: string; industries?: ProfileIndustryInput[]; location?: ProfileSelfLocation; website?: string; openTo?: string[]; preferredWorkplace?: string[]; availableFromUtc?: number; availableToUtc?: number; } /** Update the authenticated user's `id.sifa.profile.self` record. */ declare function updateProfileSelf(config: SifaApiConfig, data: UpdateProfileSelfInput, options?: ApiFetchOptions): Promise; /** Body accepted by {@link updateProfileOverride}. */ interface UpdateProfileOverrideInput { headline?: string | null; about?: string | null; displayName?: string | null; pronouns?: string | null; } /** * Override aggregated profile fields with sifa-specific values. `null` * clears the override and falls back to the upstream PDS value. */ declare function updateProfileOverride(config: SifaApiConfig, data: UpdateProfileOverrideInput, options?: ApiFetchOptions): Promise; /** Extended result for {@link refreshPds}. */ interface RefreshPdsResult extends WriteResult { displayName?: string | null; avatar?: string | null; } /** * Re-pull the authenticated user's `app.bsky.actor.profile` from their * PDS. Returns the freshly resolved `displayName` and `avatar` on * success so the UI can update without a full profile refetch. */ declare function refreshPds(config: SifaApiConfig, options?: ApiFetchOptions): Promise; /** Extended result for {@link uploadAvatar}. */ interface UploadAvatarResult extends WriteResult { /** Publicly accessible URL of the newly uploaded avatar. */ url?: string; } /** * Upload a new avatar via `multipart/form-data`. Pass either a `File` * (browser) or any `Blob` (Expo, node). The SDK leaves `Content-Type` * unset so the runtime can set the multipart boundary automatically. * * Never throws -- inspect `result.success` and `result.url`. */ declare function uploadAvatar(config: SifaApiConfig, file: Blob, options?: ApiFetchOptions): Promise; /** Delete the authenticated user's avatar override (revert to PDS avatar). */ declare function deleteAvatarOverride(config: SifaApiConfig, options?: ApiFetchOptions): Promise; /** Extended result for {@link uploadNamePronunciationAudio}. */ interface UploadPronunciationAudioResult extends WriteResult { /** Publicly accessible URL of the newly uploaded audio clip. */ url?: string; } /** * Upload a name-pronunciation audio clip via `multipart/form-data`. Pass a * `File` (browser) or any `Blob` (Expo, node). The SDK leaves `Content-Type` * unset so the runtime sets the multipart boundary automatically. * * Never throws -- inspect `result.success` and `result.url`. */ declare function uploadNamePronunciationAudio(config: SifaApiConfig, file: Blob, options?: ApiFetchOptions): Promise; /** Delete the name-pronunciation audio clip from the user's profile. */ declare function deleteNamePronunciationAudio(config: SifaApiConfig, options?: ApiFetchOptions): Promise; /** * Create a new `id.sifa.profile.skill` record on the authenticated * user's PDS. */ declare function createSkill(config: SifaApiConfig, data: Record, options?: ApiFetchOptions): Promise; /** Update an existing skill record by `rkey`. */ declare function updateSkill(config: SifaApiConfig, rkey: string, data: Record, options?: ApiFetchOptions): Promise; /** Outcome of a bulk sub-category assign. */ interface SubCategoryBulkResult { /** Records written. */ updated: number; /** Records that already carried the label, so no write was needed. */ unchanged: number; /** Requested rkeys with no matching record on the PDS. */ skipped: string[]; } /** * Set (or clear) the sub-category on many skills in one request. * * A single call replaces one PUT per skill, which tripped the AppView's * per-IP rate limit on any sizeable profile (#324). An empty `subCategory` * clears the field. */ declare function updateSkillSubCategories(config: SifaApiConfig, rkeys: string[], subCategory: string, options?: ApiFetchOptions): Promise; /** Delete a skill record by `rkey`. */ declare function deleteSkill(config: SifaApiConfig, rkey: string, options?: ApiFetchOptions): Promise; /** * Address payload accepted by `/api/profile/location` endpoints. * * Accepts both shapes during the community.lexicon.location.address * migration. Prefer `country` + `locality` (new) over `countryCode` + * `city` (legacy). The API's `locationSchema` is a Zod union that * accepts either pair. */ interface ProfileLocationAddress { /** Legacy alias for `country` (alpha-2). */ countryCode?: string; /** community.lexicon.location.address field -- prefer over `countryCode`. */ country?: string; region?: string; /** Legacy alias for `locality`. */ city?: string; /** community.lexicon.location.address field -- prefer over `city`. */ locality?: string; } /** Body accepted by {@link createProfileLocation} / {@link updateProfileLocation}. */ interface ProfileLocationInput { address: ProfileLocationAddress; type: string; label?: string; isPrimary?: boolean; } /** Create a new profile location entry. */ declare function createProfileLocation(config: SifaApiConfig, data: ProfileLocationInput, options?: ApiFetchOptions): Promise; /** Update an existing profile location by `rkey`. */ declare function updateProfileLocation(config: SifaApiConfig, rkey: string, data: ProfileLocationInput, options?: ApiFetchOptions): Promise; /** Delete a profile location by `rkey`. */ declare function deleteProfileLocation(config: SifaApiConfig, rkey: string, options?: ApiFetchOptions): Promise; /** Body accepted by {@link createExternalAccount} / {@link updateExternalAccount}. */ interface ExternalAccountInput { platform: string; url: string; label?: string; feedUrl?: string; } /** Extended create result for {@link createExternalAccount}. */ interface CreateExternalAccountResult extends WriteResult { rkey?: string; feedUrl?: string | null; } /** Extended write result for {@link verifyExternalAccount}. */ interface VerifyExternalAccountResult extends WriteResult { verified?: boolean; verifiedVia?: string; } /** List external accounts attached to a profile. Returns `[]` on error. */ declare function fetchExternalAccounts(config: SifaApiConfig, handleOrDid: string, options?: ApiFetchOptions): Promise; /** * Create a new external account record. Returns the newly-created `rkey` * and the server-resolved `feedUrl` (sifa-api inspects the target for * RSS feeds on platforms that publish them). */ declare function createExternalAccount(config: SifaApiConfig, data: ExternalAccountInput, options?: ApiFetchOptions): Promise; /** Update an existing external account by `rkey`. */ declare function updateExternalAccount(config: SifaApiConfig, rkey: string, data: ExternalAccountInput, options?: ApiFetchOptions): Promise; /** Delete an external account by `rkey`. */ declare function deleteExternalAccount(config: SifaApiConfig, rkey: string, options?: ApiFetchOptions): Promise; /** Mark an external account as the user's primary. */ declare function setExternalAccountPrimary(config: SifaApiConfig, rkey: string, options?: ApiFetchOptions): Promise; /** Clear the "primary" flag on an external account. */ declare function unsetExternalAccountPrimary(config: SifaApiConfig, rkey: string, options?: ApiFetchOptions): Promise; /** * Run server-side verification on an external account (e.g. inspect * the target for a keytrace claim). Returns `{ verified, verifiedVia }` * on success. */ declare function verifyExternalAccount(config: SifaApiConfig, rkey: string, options?: ApiFetchOptions): Promise; /** Body accepted by {@link createEndorsement}. */ interface EndorsementInput { /** DID of the person being endorsed. */ subjectDid: string; /** * AT-URI of the subject's `id.sifa.profile.skill` record. Omit to propose a * skill they have not listed; `skillName` then names what is proposed, and * the record is created when they accept. */ skillUri?: string; /** * CID of that skill record, pinning the endorsement to the version endorsed. * Optional: the AppView resolves it when omitted, which is the common case * since only the firehose carries a CID. Never substitute another record's. */ skillCid?: string; /** * Snapshot of the skill's name at endorsement time. Acts as the validity * anchor: if the subject later renames the skill, the mismatch is detectable. */ skillName: string; comment?: string; } /** Body accepted by {@link confirmEndorsement}. */ interface ConfirmEndorsementResult { /** Skill the endorsement resolved to, created if it was a proposal. */ skillUri?: string; /** True when accepting added a new skill to the profile. */ skillCreated?: boolean; } interface ConfirmEndorsementInput { endorsementUri: string; /** * Optional. When omitted the AppView resolves the CID itself, reading the * record from the endorser's PDS if it has none stored. Callers working from * the pending inbox should pass `cid` through when it is there and leave it * out when it is not, rather than substituting another record's CID. */ endorsementCid?: string; } /** * Create an endorsement of another user's skill. The endorsed user * must confirm before the endorsement appears on their profile (the * endorsement record is on the endorser's PDS; a separate confirmation * record on the endorsed user's PDS gates display). */ declare function createEndorsement(config: SifaApiConfig, data: EndorsementInput, options?: ApiFetchOptions): Promise; /** * Confirm a received endorsement, writing a confirmation record to the * signed-in user's PDS. This is what makes the endorsement public: until the * confirmation exists, the endorsement is indexed but displays nowhere. */ declare function confirmEndorsement(config: SifaApiConfig, data: ConfirmEndorsementInput, options?: ApiFetchOptions): Promise; /** A claim naming the signed-in user that they have neither confirmed nor dismissed. */ interface PendingConfirmation { /** DID of the person who wrote the claim. */ claimerDid: string; /** * Claimer's handle, when the AppView has resolved one. Absent when they have * no Sifa profile: a claim can be written by any AT Protocol app, so the UI * needs a fallback for having no name to show. */ claimerHandle?: string; claimerDisplayName?: string; claimerAvatar?: string; /** AT-URI of the record that names you. The confirm mutation needs a strongRef. */ subjectUri: string; /** * CID of that record, when the AppView has it. Often absent, since a record * indexed from another app can arrive without one. Pass it through when * present; the AppView resolves it from the claimer's PDS when it is not. * Never substitute a different record's CID. */ subjectCid?: string; relation: string; /** Name or title the subject record carries right now, for display and snapshotting. */ subjectName: string; /** Role the claimer assigned you, for `projectMember`. Display only. */ role?: string; title?: string; createdAt: string; } interface PendingConfirmationsPage { confirmations: PendingConfirmation[]; cursor?: string; } /** A confirmation the signed-in user has already given. */ interface GivenConfirmation { subjectUri: string; claimerDid: string; claimerHandle?: string; relation: string; /** The name as it stood when confirmed, so a rename shows as a difference. */ subjectName: string; /** The name the record carries now. Absent when the claim no longer exists. */ currentName?: string; /** The record changed materially after it was confirmed. */ confirmedStale: boolean; /** They removed you from the record, or deleted it. Nothing left to withdraw. */ claimWithdrawn: boolean; createdAt: string; } /** Body accepted by {@link createConfirmation}. */ interface ConfirmationInput { subjectUri: string; subjectCid?: string; relation: string; /** * Snapshot of the subject's name at confirmation time. Stored in your own * repo, out of the claimer's reach, so a later rename is detectable. */ subjectName?: string; } /** Body accepted by {@link dismissConfirmation} and {@link revokeConfirmation}. */ interface ConfirmationSubjectInput { subjectUri: string; } /** * Claims awaiting the signed-in user's decision. Requires credentials -- the * AppView reads the subject DID from the session, not from a parameter, so * there is no way to read someone else's inbox. * * Returns an empty page on failure so a broken inbox degrades to "nothing * pending" rather than breaking the surface hosting it. */ declare function fetchPendingConfirmations(config: SifaApiConfig, options?: ApiFetchOptions): Promise; /** * Confirmations the signed-in user has already given. * * The surface for changing your mind. Without it a confirmation is one-way in * practice: the inbox lists only claims you have not answered, so once answered * there is nowhere to see it, let alone withdraw it. * * Returns an empty list on failure, matching the pending inbox: a broken list * should not break the page hosting it. */ declare function fetchGivenConfirmations(config: SifaApiConfig, options?: ApiFetchOptions): Promise<{ confirmations: GivenConfirmation[]; }>; /** * Affirm that a record naming you is accurate, writing an `id.sifa.confirmation` * to your own PDS. Until this exists the claim renders as a bare handle with no * display name, avatar, or link back to you. * * Confirming does not put the claimer's record on your profile. That record * lives in their repository and they can rename it at will; keeping your own * entry is a separate, deliberate step. */ declare function createConfirmation(config: SifaApiConfig, data: ConfirmationInput, options?: ApiFetchOptions): Promise; /** * Take a claim out of the inbox without confirming it. * * This writes nothing to any PDS. A claim only gains your identity once you * have confirmed it, so declining is already the default state -- the dismissal * is a local flag that stops it reappearing, not a published rejection the * claimer can read. */ declare function dismissConfirmation(config: SifaApiConfig, data: ConfirmationSubjectInput, options?: ApiFetchOptions): Promise; /** * Withdraw a confirmation you previously gave, deleting the record from your * PDS. The claim reverts to rendering as a bare handle. * * The usual reason is drift: the claimer renamed the project or changed the * role after you confirmed, so what you affirmed is no longer what is shown. * Also writes a dismissal, or the still-live claim returns to your inbox. */ declare function revokeConfirmation(config: SifaApiConfig, data: ConfirmationSubjectInput, options?: ApiFetchOptions): Promise; /** Extended result for {@link refreshOrcidPublications}. */ interface RefreshOrcidPublicationsResult extends WriteResult { added?: number; removed?: number; } /** * Hide an ORCID-imported publication from the user's profile. The * `putCode` is the ORCID-side identifier; the underlying record stays * in the index, only its display is suppressed. */ declare function hideOrcidPublication(config: SifaApiConfig, putCode: number, options?: ApiFetchOptions): Promise; /** Restore a previously-hidden ORCID publication. */ declare function unhideOrcidPublication(config: SifaApiConfig, putCode: number, options?: ApiFetchOptions): Promise; /** Hide a standard (auto-imported) publication by its AT URI. */ declare function hideStandardPublication(config: SifaApiConfig, uri: string, options?: ApiFetchOptions): Promise; /** Restore a previously-hidden standard publication. */ declare function unhideStandardPublication(config: SifaApiConfig, uri: string, options?: ApiFetchOptions): Promise; /** Bulk-hide standard publications by AT URI list. */ declare function bulkHideStandardPublications(config: SifaApiConfig, uris: string[], options?: ApiFetchOptions): Promise; /** Bulk-unhide standard publications by AT URI list. */ declare function bulkUnhideStandardPublications(config: SifaApiConfig, uris: string[], options?: ApiFetchOptions): Promise; /** Hide an `id.sifa.profile.publication` (user-authored publication record). */ declare function hideSifaPublication(config: SifaApiConfig, rkey: string, options?: ApiFetchOptions): Promise; /** Restore a previously-hidden Sifa publication. */ declare function unhideSifaPublication(config: SifaApiConfig, rkey: string, options?: ApiFetchOptions): Promise; /** * Re-pull the authenticated user's ORCID publications. Returns counts * of added and removed records. The server returns `{ error: '...' }` * inline (not via HTTP status) on quota / linkage failures; the SDK * folds that into `{ success: false, error }` to keep the contract * consistent with other mutations. */ declare function refreshOrcidPublications(config: SifaApiConfig, options?: ApiFetchOptions): Promise; /** Item types that can be hidden on the authenticated user's profile. */ declare const HIDDEN_ITEM_TYPES: readonly ["position", "education", "certification", "project", "volunteering", "publication", "course", "honor", "language", "externalAccount"]; type HiddenItemType = (typeof HIDDEN_ITEM_TYPES)[number]; /** Source from which an item originates; disambiguates `item_id`. */ declare const HIDDEN_ITEM_SOURCES: readonly ["pds", "standard", "orcid"]; type HiddenItemSource = (typeof HIDDEN_ITEM_SOURCES)[number]; interface HideProfileItemInput { itemType: HiddenItemType; source: HiddenItemSource; /** rkey for `pds`, AT-URI for `standard`, ORCID putCode as text for `orcid`. */ itemId: string; } interface BulkHideProfileItemInput { itemType: HiddenItemType; source: HiddenItemSource; itemIds: string[]; } /** * Hide one profile item. The underlying record stays on the user's PDS; * only its display on sifa.id is suppressed. */ declare function hideProfileItem(config: SifaApiConfig, input: HideProfileItemInput, options?: ApiFetchOptions): Promise; /** Restore a previously-hidden profile item. */ declare function unhideProfileItem(config: SifaApiConfig, input: HideProfileItemInput, options?: ApiFetchOptions): Promise; /** Bulk-hide profile items sharing the same `itemType` + `source`. */ declare function bulkHideProfileItems(config: SifaApiConfig, input: BulkHideProfileItemInput, options?: ApiFetchOptions): Promise; /** Bulk-unhide profile items sharing the same `itemType` + `source`. */ declare function bulkUnhideProfileItems(config: SifaApiConfig, input: BulkHideProfileItemInput, options?: ApiFetchOptions): Promise; /** Public, aggregate stats shown on the homepage and similar surfaces. */ interface StatsResponse { profileCount: number; avatars: string[]; atproto: { userCount: number; growthPerSecond: number; timestamp: number; } | null; } /** * Homepage stats (profile count, avatar samples, ATproto growth). Public * endpoint -- safe to cache. Returns `null` on any error so callers can * render a graceful empty state. */ declare function fetchStats(config: SifaApiConfig, options?: ApiFetchOptions): Promise; /** Catalog entry describing an ATproto app that Sifa surfaces activity for. */ interface AppRegistryEntry { id: string; name: string; category: string; collectionPrefixes: string[]; scanCollections: string[]; urlPattern?: string; color: string; } /** Compact app representation returned by the hidden-apps endpoint. */ interface HiddenApp { id: string; name: string; category: string; } interface FetchHiddenAppsOptions extends ApiFetchOptions { /** * Pass the caller's `Cookie` header on Next.js RSC server-side calls. * `credentials: 'include'` does NOT propagate browser cookies in RSC, * so authenticated server fetches must forward the header explicitly. */ cookieHeader?: string; } /** * Public app registry shown across discovery surfaces. Heavily cached. * Returns `[]` on any error. */ declare function fetchAppsRegistry(config: SifaApiConfig, options?: ApiFetchOptions): Promise; /** * Apps the authenticated user has chosen to hide from their activity feed. * Requires an authenticated session. Returns `[]` on any error (including * the unauthenticated case). */ declare function fetchHiddenApps(config: SifaApiConfig, options?: FetchHiddenAppsOptions): Promise; /** One account attached to the current browser, for the account switcher. */ interface AccountSummary { did: string; handle: string | null; displayName: string | null; avatarUrl: string | null; /** * The org's uploaded logo blob CID, for a company account that set one on its * `/c/` page; null otherwise. The switcher resolves it to the same logo `/c/` * shows (via the shared company-logo resolution), so an uploaded logo appears * in the menu rather than the atproto avatar. Omitted by older api responses. */ orgLogoBlob?: string | null; /** Whether this is the currently-active account. */ active: boolean; } interface FetchAccountsOptions extends ApiFetchOptions { /** * Pass the caller's `Cookie` header on Next.js RSC server-side calls. * `credentials: 'include'` does NOT propagate browser cookies in RSC, * so authenticated server fetches must forward the header explicitly. */ cookieHeader?: string; } /** * Accounts attached to this browser (the account switcher). Requires an * authenticated session. Returns `[]` on any error, including the * unauthenticated case. */ declare function fetchAccounts(config: SifaApiConfig, options?: FetchAccountsOptions): Promise; /** * Make an already-attached account the active one. Keyed by DID (public); the * server maps it to the browser's session id. Browser-only: the endpoint * requires an Origin header, which browsers set automatically on POST. Callers * typically reload the app afterwards to reset session-seeded state. */ declare function switchAccount(config: SifaApiConfig, did: string, options?: ApiFetchOptions): Promise; /** Profile entry returned by the search endpoint. */ interface ProfileSearchResult { did?: string; handle: string; displayName?: string; headline?: string; avatar?: string; about?: string; currentRole?: string; currentCompany?: string; industry?: string; domain?: string; countryCode?: string; locationCountry?: string; preferredWorkplace?: string[]; claimed?: boolean; blueskyVerified?: boolean; blueskyVerifiedAt?: string | null; } interface SearchFilters { q?: string; skill?: string; country?: string; industry?: string; domain?: string; workplace?: string; app?: string; /** * Open-to filter. Values are short tokens (e.g. "fullTime", "mentor", * "collab") matching `OPEN_TO_OPTIONS[].token` from the taxonomy. The * API expands tokens to lex values server-side. Multiple tokens are * OR-combined (profile matches if any selected token is set). */ openTo?: string[]; limit?: number; } interface SearchResponse { profiles: ProfileSearchResult[]; total: number; limit: number; offset: number; } /** Skill typeahead suggestion. */ interface SkillSearchResult { name: string; slug: string; category: string; userCount: number; } interface FilterOptions { countries: { countryCode: string; country: string; count: number; }[]; industries: { industry: string; count: number; }[]; apps: { appId: string; count: number; }[]; /** * Distribution of openTo selections across indexed profiles. Each entry * maps a short token (see {@link SearchFilters.openTo}) to the number of * profiles that have it set. Omitted from older API responses; treat * absence as "no data" rather than "all zero". */ openTo?: { token: string; count: number; }[]; } /** Company entry returned by company search (workspace#299). */ interface CompanySearchResult { /** Immutable catalogue id; the durable `/c/{publicId}` link. */ publicId: string; name: string; domain: string | null; country: string | null; industry: string | null; logoUrl: string | null; employeeCount: number | null; } interface CompanySearchFilters { q?: string; /** ISO 3166-1 alpha-2. */ country?: string; industry?: string; limit?: number; } interface CompanySearchResponse { results: CompanySearchResult[]; hasMore: boolean; } /** * Search profiles by free-text query and optional filters. Returns an * empty result set when no filters are provided (matching sifa-web's * "no input, no fetch" behavior). */ declare function fetchSearchProfiles(config: SifaApiConfig, filters: SearchFilters, options?: ApiFetchOptions): Promise; /** * Company search over the entity catalogue (workspace#299). * * A category of its own rather than part of profile search: the two rank * differently and carry different filters, and a slow category should not hold * up the rest of a blended results page. * * An empty query returns nothing without a network call. The API rejects a * blank `q` rather than scanning ~200k rows, so asking would only spend a round * trip to be told no. */ declare function fetchSearchCompanies(config: SifaApiConfig, filters: CompanySearchFilters, options?: ApiFetchOptions): Promise; /** * Skill typeahead. Returns up to 8 matches for the given prefix. Empty * input returns an empty array without hitting the server. */ declare function fetchSkillSuggestions(config: SifaApiConfig, query: string, options?: ApiFetchOptions): Promise; /** Available filter facets (countries, industries, apps) for search UI. */ declare function fetchSearchFilters(config: SifaApiConfig, options?: ApiFetchOptions): Promise; /** * Canonical-skill search backing the position-editor and similar * skill-pickers. Hits `/api/skills/search` (the canonical-skills DB * lookup) which is distinct from {@link fetchSkillSuggestions}'s * `/api/search/skills` (the profile-skill typeahead). * * Returns `[]` on empty input (no network call) or any error. */ declare function searchSkills(config: SifaApiConfig, query: string, limit?: number, options?: ApiFetchOptions): Promise; /** Lightweight profile representation used by discovery endpoints. */ interface SimilarProfile { did: string; handle: string; displayName?: string | null; avatar?: string | null; headline?: string | null; currentRole?: string | null; currentCompany?: string | null; industry?: string | null; domain?: string | null; } interface SuggestionProfile { did: string; handle: string; displayName?: string; headline?: string; avatarUrl?: string; source: string; dismissed: boolean; blueskyVerified?: boolean; } interface SuggestionsResponse { onSifa: SuggestionProfile[]; notOnSifa: SuggestionProfile[]; cursor?: string; } interface FeaturedProfile { did: string; handle: string; displayName?: string; avatar?: string; pronouns?: string; headline?: string; about?: string; currentRole?: string; currentCompany?: string; locationCountry?: string; locationRegion?: string; /** Legacy alias for `locationLocality`; emitted by sifa-api during the additive response window. */ locationCity?: string; /** community.lexicon.location.address field name -- prefer over `locationCity`. */ locationLocality?: string; countryCode?: string; location?: string; website?: string; openTo?: string[]; preferredWorkplace?: string[]; availableFromUtc?: number; availableToUtc?: number; followersCount?: number; atprotoFollowersCount?: number; pdsProvider?: { name: string; host: string; } | null; claimed: boolean; featuredDate: string; } /** Profiles similar to the given DID (matchmaking). Returns `[]` on error. */ declare function fetchSimilarProfiles(config: SifaApiConfig, did: string, opts?: { limit?: number; } & ApiFetchOptions): Promise; interface FetchSuggestionsOptions extends ApiFetchOptions { source?: string; includeDismissed?: boolean; cursor?: string; limit?: number; /** * Pass the caller's `Cookie` header on Next.js RSC server-side calls. * `credentials: 'include'` does NOT propagate browser cookies in RSC, * so authenticated server fetches must forward the header explicitly. */ cookieHeader?: string; } /** Discovery suggestions feed. Resolves to empty arrays on error. */ declare function fetchSuggestions(config: SifaApiConfig, opts?: FetchSuggestionsOptions): Promise; /** Count of pending suggestions since an optional timestamp. */ declare function fetchSuggestionCount(config: SifaApiConfig, since?: string, options?: ApiFetchOptions): Promise; /** Featured profile (rotated by sifa-api). Returns `null` when none. */ declare function fetchFeaturedProfile(config: SifaApiConfig, options?: ApiFetchOptions): Promise; interface FollowProfile { did: string; handle: string; displayName?: string; headline?: string; avatarUrl?: string; source: string; claimed: boolean; followedAt: string; blueskyVerified?: boolean; blueskyVerifiedAt?: string | null; } interface FollowingResponse { follows: FollowProfile[]; cursor?: string; } /** People the authenticated user follows. Empty on error. */ declare function fetchFollowing(config: SifaApiConfig, opts?: { source?: string; cursor?: string; limit?: number; } & ApiFetchOptions): Promise; /** * Result of {@link followUser}. Extends {@link WriteResult} with the * follow `rkey` returned by sifa-api on success. Self-follow + invalid * handle surface as `success: false` with the server-provided message; * dup-follow is idempotent (sifa-api E7) and resolves as `success: true`. */ interface FollowUserResult extends WriteResult { rkey?: string; /** DID of the followed subject (server-resolved from the handle). */ subjectDid?: string; } /** * Create an `id.sifa.graph.follow` record on the caller's PDS via the * AppView. Idempotent on duplicate (server catches the unique-violation * and returns 200, per sifa-api#673 E7). */ declare function followUser(config: SifaApiConfig, handle: string, opts?: { note?: string; } & Omit): Promise; /** Delete the authenticated viewer's `id.sifa.graph.follow` for `handle`. */ declare function unfollowUser(config: SifaApiConfig, handle: string, opts?: Omit): Promise; interface FollowListPage { follows: FollowProfile[]; cursor: string | null; } interface FetchFollowListOptions extends ApiFetchOptions { cursor?: string; limit?: number; /** * Pass the caller's `Cookie` header on Next.js RSC server-side calls * (mirrors {@link FetchActivityFeedOptions}; required for authenticated * server fetches because `credentials: 'include'` does not propagate * cookies from RSC). */ cookieHeader?: string; } /** * Paginated list of `handle`'s followers. Returns an empty page on error * so the UI can render a graceful "no followers yet" state. */ declare function getFollowers(config: SifaApiConfig, handle: string, opts?: FetchFollowListOptions): Promise; /** Paginated list of who `handle` follows. */ declare function getFollowing(config: SifaApiConfig, handle: string, opts?: FetchFollowListOptions): Promise; /** * @deprecated The `/api/following/feed` surface was reverted (sifa-api#674). * Per `decisions/activity-data-strategy.md` the Sifa Timeline + ATmosphere * Stream are two distinct surfaces with different data paths (Barazo API * for Timeline, live PDS reads + Valkey for Stream). These collapsed feed * types are no longer consumed. Scheduled for removal in next major bump. */ interface FetchFollowingFeedOptions extends ApiFetchOptions { cursor?: string; limit?: number; /** * Comma-separated category filter (per sifa-api#673 TR10). Forwarded * as-is; the server validates allowed values. */ categories?: string[]; cookieHeader?: string; } /** * V5 home feed: Sifa events + curated ATmosphere creation events filtered * by the authenticated viewer's followees. Composite cursor (per E5/TR4). * Returns an empty page on error. * * @deprecated The `/api/following/feed` surface was reverted (sifa-api#674). * Per `decisions/activity-data-strategy.md` the Sifa Timeline + ATmosphere * Stream are two distinct surfaces with different data paths (Barazo API * for Timeline, live PDS reads + Valkey for Stream). This fetcher is no * longer consumed. Scheduled for removal in next major bump. */ declare function getFollowingFeed(config: SifaApiConfig, opts?: FetchFollowingFeedOptions): Promise; /** * Options shared by the cursor-paginated follow-graph endpoints introduced in * `sifa-api#674` (mutuals + bluesky-suggestions). Mirrors * `FetchFollowListOptions` in `./follow.ts` but the response wrapper here uses * the `{ items, cursor }` shape (not `{ follows, cursor }`). */ interface FetchFollowProfilePageOptions extends ApiFetchOptions { cursor?: string; limit?: number; /** * Pass the caller's `Cookie` header on Next.js RSC server-side calls * (mirrors `FetchFollowListOptions`; required for authenticated server * fetches because `credentials: 'include'` does not propagate cookies from * RSC). */ cookieHeader?: string; } /** Page of {@link FollowProfileItem} rows with an opaque next-page cursor. */ interface FollowProfilePageResponse { items: FollowProfileItem[]; cursor: string | null; } /** * Cursor-paginated list of mutual sifa-source follows for `handleOrDid` * (X↔Y both follow each other on Sifa). Backed by * `GET /api/profile/{handleOrDid}/mutuals` from `sifa-api#674`. Public — * does not require auth. Returns an empty page on error. */ declare function getMutuals(config: SifaApiConfig, handleOrDid: string, opts?: FetchFollowProfilePageOptions): Promise; /** * Cursor-paginated list of Sifa users the viewer follows on Bluesky but NOT * on Sifa, filtered to people active on Sifa. Backed by * `GET /api/me/bluesky-suggestions` from `sifa-api#674`. Auth-required. * Returns an empty page on error. */ declare function getBlueskySuggestions(config: SifaApiConfig, opts?: FetchFollowProfilePageOptions): Promise; /** * Options for {@link listFeatureAllowlist}. Supports the same `cookieHeader` * passthrough as the other admin reads for RSC contexts. */ interface ListFeatureAllowlistOptions extends ApiFetchOptions { cookieHeader?: string; } /** Response shape of `GET /api/admin/feature-allowlists/:flag`. */ interface FeatureAllowlistResponse { items: FeatureAllowlistEntry[]; } /** * List all DIDs on the given feature flag's allowlist. Admin-gated server- * side (caller must be an admin). Returns an empty list on error so the UI * can render a graceful empty state. */ declare function listFeatureAllowlist(config: SifaApiConfig, flag: FeatureFlag, opts?: ListFeatureAllowlistOptions): Promise; /** * Add (or upsert the note for) a DID on the given flag's allowlist. Maps to * `POST /api/admin/feature-allowlists/{flag}`. Returns a {@link WriteResult}; * never throws. */ declare function addFeatureAllowlist(config: SifaApiConfig, flag: FeatureFlag, did: string, opts?: { note?: string; } & Omit): Promise; /** * Remove a DID from the given flag's allowlist. Maps to * `DELETE /api/admin/feature-allowlists/{flag}/{did}`. Returns a * {@link WriteResult}; never throws. */ declare function removeFeatureAllowlist(config: SifaApiConfig, flag: FeatureFlag, did: string, opts?: Omit): Promise; /** * Options for {@link getAdminReviewQueues}. Supports the same `cookieHeader` * passthrough as the other admin reads for RSC contexts. */ interface GetAdminReviewQueuesOptions extends ApiFetchOptions { cookieHeader?: string; } /** Response shape of `GET /api/admin/stats/review-queues`. */ interface AdminReviewQueues { ideas: number; nameCorrections: number; pendingCompanies: number; /** Sum of the three queues. */ total: number; generatedAt: string; } /** * Open counts for the three admin review queues (ideas, pending companies, * name corrections) plus their total. * * Unlike {@link listFeatureAllowlist} this does NOT swallow errors: a zeroed * payload would render as "all queues clear" in the admin nav, which is worse * than rendering nothing. Callers decide how to degrade. */ declare function getAdminReviewQueues(config: SifaApiConfig, opts?: GetAdminReviewQueuesOptions): Promise; interface QuotedPostAuthor { did: string; handle: string; displayName?: string; avatar?: string; } interface QuotedPostImage { thumb: string; fullsize: string; alt?: string; } interface QuotedPostView { uri: string; cid: string; author: QuotedPostAuthor; text: string; createdAt: string; images?: QuotedPostImage[]; } type QuotedPostResult = { status: 'ok'; record: QuotedPostView; } | { status: 'deleted'; uri: string; } | { status: 'unavailable'; uri: string; }; /** Max URIs per request to `POST /api/quoted-posts/resolve` (mirrors server cap). */ declare const QUOTED_POSTS_BATCH_MAX = 20; interface ResolveQuotedPostsOptions extends ApiFetchOptions { /** Cookie header for Next.js RSC server-side calls; ignored in browsers. */ cookieHeader?: string; } /** * Resolve a batch of AT-URIs to their quoted-post snapshots via the Sifa AppView. * * Auto-deduplicates input URIs and splits requests into chunks of * {@link QUOTED_POSTS_BATCH_MAX} so callers can pass an arbitrary-length array. * Each chunk is fired in parallel. The server caches results in Valkey, so * repeated calls for the same URI are cheap. * * Returns a map of `uri -> QuotedPostResult`. URIs that fail (network error, * non-2xx, or the server omitting them) are absent from the map; the caller * should render a skeleton or tombstone for those. */ declare function resolveQuotedPosts(config: SifaApiConfig, uris: string[], options?: ResolveQuotedPostsOptions): Promise>; /** * Liveness of an activity card's destination, as reported by sifa-api's * `/api/activity` enrichment (see sifa-api `url-health-checker`). How liveness * is measured depends on the card's health strategy (see `resolveCardHealth`): * first-party permalinks (`record`) are checked by record existence on the PDS; * foreign/derived targets (`url`) by HTTP reachability (HEAD, then GET). * * ok -- record exists, or the URL returned 2xx/3xx * broken -- confirmed dead (record deleted, or >=2 consecutive 4xx / >=5 consecutive 5xx) * unverifiable -- 403/429, PDS unreachable, or network error; NOT dead * unknown -- newly seen, not yet checked * * Consumers should only suppress UI on `'broken'`. All other values * (including missing) mean "render normally". */ type ActivityItemLinkHealth = 'ok' | 'broken' | 'unverifiable' | 'unknown'; interface HeatmapDay { date: string; total: number; apps: { appId: string; count: number; }[]; } interface HeatmapResponse { days: HeatmapDay[]; appTotals: { appId: string; appName: string; total: number; }[]; thresholds: [number, number, number, number]; } interface ActivityItem { uri: string; cid: string; collection: string; rkey: string; record: Record; appId: string; appName: string; category: string; indexedAt: string; /** * Set by the server when an `app.bsky.embed.record` quote was already * resolved upstream (AppView path). Mutually exclusive with `quotedPostUri`. */ quotedPost?: QuotedPostResult; /** * Set by the server when an `app.bsky.embed.record` quote needs client-side * resolution (PDS path). Pass batches to {@link resolveQuotedPosts}. * Mutually exclusive with `quotedPost`. */ quotedPostUri?: string; /** * Reachability of the card's external destination as last checked by * sifa-api. Undefined for legacy responses; treat as 'unknown'. * See {@link ActivityItemLinkHealth}. */ linkHealth?: ActivityItemLinkHealth; /** * Content labels from `app.bsky.feed.defs#postView.labels`. Set by * sifa-api for Bluesky posts; undefined for other sources and legacy * responses. Pass items to {@link hasAdultContent} to decide whether to * gate media. See {@link ActivityLabel}. */ labels?: ActivityLabel[]; } interface ActivityTeaserResponse { items: ActivityItem[]; blueskyGated?: boolean; backfillPending?: boolean; failedApps?: string[]; } interface ActivityFeedResponse { items: ActivityItem[]; cursor: string | null; hasMore: boolean; availableCategories?: string[]; blueskyGated?: boolean; failedApps?: string[]; } /** * Per-day activity counts for a profile across all ATproto apps. Returns * `null` on any error so callers can render a graceful empty state. */ declare function fetchHeatmapData(config: SifaApiConfig, handleOrDid: string, days: number, options?: ApiFetchOptions): Promise; interface FetchActivityTeaserOptions extends ApiFetchOptions { /** * Pass the caller's `Cookie` header on Next.js RSC server-side calls. * Required for authenticated server fetches because `credentials: 'include'` * does not propagate browser cookies in RSC. */ cookieHeader?: string; } /** * Recent activity teaser for a profile (homepage-sized slice). Caps the * upstream wait so the SSR path cannot hang. Returns `null` on any error. */ declare function fetchActivityTeaser(config: SifaApiConfig, handleOrDid: string, options?: FetchActivityTeaserOptions): Promise; interface FetchActivityFeedOptions extends ApiFetchOptions { category?: string; limit?: number; cursor?: string; cookieHeader?: string; } /** * Paginated activity feed for a profile. Always fresh (`cache: 'no-store'`). * Returns `null` on any error. */ declare function fetchActivityFeed(config: SifaApiConfig, handleOrDid: string, options?: FetchActivityFeedOptions): Promise; /** * A single merged pull request ingested from GitHub, as served by sifa-api's * `GET /api/me/github/pull-requests`. Mirrors the `github_contributions` row. */ declare const GithubPullRequestSchema: z.ZodObject<{ prNumber: z.ZodNumber; repoOwner: z.ZodString; repoName: z.ZodString; title: z.ZodString; url: z.ZodString; language: z.ZodNullable; additions: z.ZodNumber; deletions: z.ZodNumber; mergedAt: z.ZodString; }, z.core.$strip>; type GithubPullRequest = z.infer; declare const MyGithubPullRequestsResponseSchema: z.ZodObject<{ items: z.ZodArray; additions: z.ZodNumber; deletions: z.ZodNumber; mergedAt: z.ZodString; }, z.core.$strip>>; hasMore: z.ZodBoolean; }, z.core.$strip>; type MyGithubPullRequestsResponse = z.infer; interface FetchMyGithubPullRequestsOptions extends ApiFetchOptions { limit?: number; offset?: number; /** Forwarded as the `cookie` header for server-side (SSR) calls. */ cookieHeader?: string; } /** * Fetch the authenticated viewer's own ingested merged PRs (newest first). * Auth-scoped: relies on the session cookie (`credentials: 'include'`), so it * returns the caller's PRs, not a public handle's. Backs the GitHub importer. */ declare function fetchMyGithubPullRequests(config: SifaApiConfig, options?: FetchMyGithubPullRequestsOptions): Promise; /** Per-URI reaction state for the authenticated viewer. */ interface ReactionStatus { reacted: boolean; rkey?: string; collection?: string; } /** Result of checking whether the authenticated viewer has an account on a given app. */ interface AccountCheckResult { hasAccount: boolean; appName: string; appUrl: string; } interface FetchReactionStatusOptions extends ApiFetchOptions { /** * Pass the caller's `Cookie` header on Next.js RSC server-side calls. * Required for authenticated server fetches because `credentials: 'include'` * does not propagate browser cookies in RSC. */ cookieHeader?: string; } /** * Batch-look up reaction status for multiple URIs. Returns `{}` for an * empty input list (no network call) and `null` on any error. */ declare function fetchReactionStatus(config: SifaApiConfig, uris: string[], options?: FetchReactionStatusOptions): Promise | null>; interface CheckAppAccountOptions extends ApiFetchOptions { cookieHeader?: string; } /** * Check whether the authenticated viewer has an account on a given app. * Returns `null` on any error. */ declare function checkAppAccount(config: SifaApiConfig, appId: string, options?: CheckAppAccountOptions): Promise; /** Result of a successful {@link createReaction}. */ interface ReactionResult { uri: string; rkey: string; } /** Structured error returned by {@link createReaction} on failure. */ interface ReactionError { type: 'scope_insufficient' | 'error'; /** When `type === 'scope_insufficient'`, the lexicon scope the user must re-authorize for. */ requiredScope?: string; } /** * Create a reaction (like / star) on a target ATproto record. * * Returns a discriminated-union result instead of the generic * {@link WriteResult} shape because reactions have a distinct * "scope insufficient" failure that callers handle differently from * other errors (it triggers an OAuth scope-upgrade flow rather than * an error toast). * * Never throws. */ declare function createReaction(config: SifaApiConfig, targetUri: string, appId: string, targetCid?: string, options?: ApiFetchOptions): Promise<{ ok: true; data: ReactionResult; } | { ok: false; error: ReactionError; }>; /** * Delete a reaction (like / star) on a target ATproto record. Returns * `{ success: true }` on 2xx, `{ success: false, error }` on failure. */ declare function deleteReaction(config: SifaApiConfig, targetUri: string, appId: string, options?: ApiFetchOptions): Promise; /** Voter on a roadmap item. */ interface RoadmapVoter { did: string; avatarUrl?: string; } /** Map of item key -> vote tally and voter list. */ type RoadmapVotesResponse = Record; /** * Public roadmap vote tallies, keyed by item. Returns `{}` on any error. */ declare function fetchRoadmapVotes(config: SifaApiConfig, options?: ApiFetchOptions): Promise; interface FetchMyRoadmapVotesOptions extends ApiFetchOptions { /** * Pass the caller's `Cookie` header on Next.js RSC server-side calls. * Required for authenticated server fetches because `credentials: 'include'` * does not propagate browser cookies in RSC. */ cookieHeader?: string; } /** * Roadmap items the authenticated user has voted on. Returns `[]` on any * error or when the response payload is shaped unexpectedly. */ declare function fetchMyRoadmapVotes(config: SifaApiConfig, options?: FetchMyRoadmapVotesOptions): Promise; /** Result of a successful {@link castRoadmapVote} -- the created upvote record. */ interface RoadmapVoteResult { uri: string; rkey: string; } /** Structured error returned by {@link castRoadmapVote} on failure. */ interface RoadmapVoteError { type: 'scope_insufficient' | 'error'; /** * When `type === 'scope_insufficient'`, the lexicon collection the user must * re-authorize for (e.g. `app.userinput.upvote`). sifa-web maps this to an * OAuth scope-upgrade flow (`/oauth/reauth?scope=repo:`). */ requiredScope?: string; } /** * Discriminated-union result of {@link castRoadmapVote}. Exported so the * `useCastRoadmapVote` hook and SDK consumers can type mutation handlers * against a single source of truth. */ type CastRoadmapVoteResult = { ok: true; data: RoadmapVoteResult; } | { ok: false; error: RoadmapVoteError; }; /** * Cast a vote on a roadmap item by its key. * * Writes an `app.userinput.upvote` record into the viewer's PDS (server-side, * via their OAuth session). Returns a discriminated-union result rather than * the generic {@link WriteResult} because a first-time voter's PDS grant may * not yet include the `app.userinput.upvote` collection: the AppView responds * 403 `ScopeInsufficient`, which the caller handles by triggering an OAuth * scope upgrade rather than showing an error. Mirrors {@link createReaction}. * * Never throws. */ declare function castRoadmapVote(config: SifaApiConfig, key: string, options?: ApiFetchOptions): Promise; /** Retract a previously-cast roadmap vote. */ declare function retractRoadmapVote(config: SifaApiConfig, key: string, options?: ApiFetchOptions): Promise; /** * What the server managed to remove from the user's PDS. * * The wipe runs per collection, so it can partly succeed: `success: true` means * the account action completed, NOT that the PDS is clean. A UI that ignores * this can tell someone their data is gone while it is still on their data * server, so treat a non-empty `remaining` as "not deleted". * * Absent when the PDS was not touched (`deletePdsData: false`). */ interface PdsWipeOutcome { /** Collections whose records were removed. */ deleted: string[]; /** Collections whose records are still on the PDS. Non-empty means not done. */ remaining: string[]; /** * The server could not enumerate the repo, so it does not know what survived. * Without this, that case is indistinguishable from "nothing to delete". */ unknown: boolean; } /** * What a PDS wipe could not remove with the grant the session holds today. * * Read this BEFORE the destructive step. Deleting an account destroys the * session, so a missing scope cannot be granted afterwards -- there is nobody * left to ask. A non-empty `needsScopeFor` means the wipe would strand those * records on the user's data server. */ interface WipePreview { /** id.sifa.* collections the current grant cannot delete. */ needsScopeFor: string[]; /** * The server could not enumerate the repo, so the gap list is not * authoritative. Distinct from an empty list, which means "nothing to ask for". */ unknown?: boolean; } /** * Ask which id.sifa.* collections the current grant cannot delete. * * Unlike most read fetchers in this file's neighbourhood, a failure is NOT * flattened into an empty result: an empty gap list reads as "a wipe will be * clean", and a caller must not promise that on the strength of a request that * never arrived. Let it throw and warn. */ declare function fetchWipePreview(config: SifaApiConfig, options?: ApiFetchOptions): Promise; /** Extended write result for {@link resetProfile}. */ interface ResetProfileResult extends WriteResult { /** Present when `deletePdsData: true`. See {@link PdsWipeOutcome}. */ pds?: PdsWipeOutcome; } /** Extended write result for {@link deleteAccount}. */ interface DeleteAccountResult extends WriteResult { /** The deleted handle, returned by the server for confirmation UIs. */ handle?: string; /** Present when `deletePdsData: true`. See {@link PdsWipeOutcome}. */ pds?: PdsWipeOutcome; } /** * Reset the authenticated user's Sifa profile. * * `deletePdsData: true` also deletes the corresponding records on the * user's PDS. `deletePdsData: false` only removes the AppView's * indexed state -- the records on the PDS are left intact and could be * re-indexed later. * * Destructive. Server enforces session check + attestation; the SDK * does not gate on additional confirmation. Wrap call sites in your * own modal if you want a UX confirmation step. */ declare function resetProfile(config: SifaApiConfig, deletePdsData: boolean, options?: ApiFetchOptions): Promise; /** * Delete the authenticated user's account. Returns the deleted handle * on success (used by the post-delete confirmation screen). * * `deletePdsData: true` also deletes the corresponding records on the * user's PDS; `false` leaves the PDS records intact. * * Destructive. Same caveat as {@link resetProfile}. */ declare function deleteAccount(config: SifaApiConfig, deletePdsData: boolean, options?: ApiFetchOptions): Promise; /** * Read what the user's PDS actually holds under id.sifa.*. * * A failure is not flattened into an empty inventory. Zero records reads as * "Sifa has stored nothing about you", and a request that never arrived must * not be allowed to say that. Let it throw. */ declare function fetchRepoInventory(config: SifaApiConfig, options?: ApiFetchOptions): Promise; interface RepoDeleteInput { collection: string; /** The records to remove. Omit and set `all` to remove the whole collection. */ rkeys?: string[]; /** * Remove every record in the collection, including ones written between the * inventory read and this call. A UI offering "delete all of X" must send * this rather than the rkeys it happened to see, or a record created in * between silently survives a delete the user believes was complete. */ all?: boolean; } /** * Delete records from the user's own repo. * * The returned `success` means the request was accepted, NOT that the records * are gone: read `results` for that, per record. `needsScopeUpgrade` means * nothing was attempted and the user has to grant the scope first. * * Destructive and not undoable -- a deleted record's CID cannot be restored. * The server enforces the id.sifa.* boundary and the session check; the SDK * adds no confirmation step, so wrap call sites in one. */ declare function deleteRepoRecords(config: SifaApiConfig, input: RepoDeleteInput, options?: ApiFetchOptions): Promise; /** * URL of the raw-record download. * * A URL rather than a fetcher: the response is a file the browser saves, and * routing it through fetch would buffer the whole repo in memory to hand it * straight back to a download anchor. */ declare function repoExportUrl(config: SifaApiConfig): string; /** * Query key factory for TanStack Query. * * Keys are read-only tuples; the hierarchy matches the SDK's fetcher * grouping. Use these instead of inline arrays so consumers can target * `queryClient.invalidateQueries({ queryKey: keys.profile.all() })` and * similar patterns without typos. * * Convention: every leaf key starts with the namespace ('sifa') so * consumers can invalidate everything Sifa-related in one call. */ declare const sifaQueryKeys: { readonly all: () => readonly ["sifa"]; readonly profile: { readonly all: () => readonly ["sifa", "profile"]; readonly byHandle: (handleOrDid: string) => readonly ["sifa", "profile", string]; readonly atFundLink: (did: string) => readonly ["sifa", "profile", "at-fund-link", string]; readonly view: (actor: string) => readonly ["sifa", "profile", "view", string]; readonly externalAccounts: (handleOrDid: string) => readonly ["sifa", "profile", "external-accounts", string]; }; readonly position: { readonly all: () => readonly ["sifa", "position"]; readonly byOwner: (did: string) => readonly ["sifa", "position", "by-owner", string]; }; readonly search: { readonly all: () => readonly ["sifa", "search"]; readonly profiles: (filters: Record) => readonly ["sifa", "search", "profiles", Record]; readonly companies: (filters: Record) => readonly ["sifa", "search", "companies", Record]; readonly skills: (query: string) => readonly ["sifa", "search", "skills", string]; readonly canonicalSkills: (query: string, limit: number) => readonly ["sifa", "search", "canonical-skills", string, number]; readonly filters: () => readonly ["sifa", "search", "filters"]; }; readonly entity: { readonly all: () => readonly ["sifa", "entity"]; readonly search: (query: string, limit: number) => readonly ["sifa", "entity", "search", string, number]; }; readonly discovery: { readonly all: () => readonly ["sifa", "discovery"]; readonly similar: (did: string, limit: number) => readonly ["sifa", "discovery", "similar", string, number]; readonly suggestions: (opts: Record) => readonly ["sifa", "discovery", "suggestions", Record]; readonly suggestionCount: (since: string | undefined) => readonly ["sifa", "discovery", "suggestion-count", string | null]; readonly featured: () => readonly ["sifa", "discovery", "featured"]; }; readonly follow: { readonly all: () => readonly ["sifa", "follow"]; readonly following: (opts: Record) => readonly ["sifa", "follow", "following", Record]; readonly followers: (handle: string) => readonly ["sifa", "follow", "followers", string]; readonly followingOf: (handle: string) => readonly ["sifa", "follow", "following-of", string]; readonly feed: (opts: Record) => readonly ["sifa", "follow", "feed", Record]; readonly mutuals: (handle: string) => readonly ["sifa", "follow", "mutuals", string]; readonly blueskySuggestions: () => readonly ["sifa", "follow", "bluesky-suggestions"]; }; readonly admin: { readonly all: () => readonly ["sifa", "admin"]; readonly featureAllowlist: (flag: string) => readonly ["sifa", "admin", "feature-allowlist", string]; readonly reviewQueues: () => readonly ["sifa", "admin", "review-queues"]; }; readonly stats: { readonly all: () => readonly ["sifa", "stats"]; readonly homepage: () => readonly ["sifa", "stats", "homepage"]; }; readonly apps: { readonly all: () => readonly ["sifa", "apps"]; readonly registry: () => readonly ["sifa", "apps", "registry"]; readonly hidden: () => readonly ["sifa", "apps", "hidden"]; }; readonly auth: { readonly all: () => readonly ["sifa", "auth"]; readonly accounts: () => readonly ["sifa", "auth", "accounts"]; }; readonly activity: { readonly all: () => readonly ["sifa", "activity"]; readonly heatmap: (handleOrDid: string, days: number) => readonly ["sifa", "activity", "heatmap", string, number]; readonly teaser: (handleOrDid: string) => readonly ["sifa", "activity", "teaser", string]; readonly feed: (handleOrDid: string, opts: Record) => readonly ["sifa", "activity", "feed", string, Record]; }; readonly github: { readonly all: () => readonly ["sifa", "github"]; readonly myPullRequests: (opts: { limit?: number; offset?: number; }) => readonly ["sifa", "github", "my-pull-requests", { limit?: number; offset?: number; }]; }; readonly endorsement: { readonly all: () => readonly ["sifa", "endorsement"]; readonly count: (did: string) => readonly ["sifa", "endorsement", "count", string]; readonly pending: () => readonly ["sifa", "endorsement", "pending"]; readonly reciprocity: () => readonly ["sifa", "endorsement", "reciprocity"]; readonly received: (did: string) => readonly ["sifa", "endorsement", "received", string]; }; readonly confirmation: { readonly all: () => readonly ["sifa", "confirmation"]; readonly pending: () => readonly ["sifa", "confirmation", "pending"]; /** Confirmations this session has given, for the withdraw surface. */ readonly given: () => readonly ["sifa", "confirmation", "given"]; }; readonly stream: { readonly all: () => readonly ["sifa", "stream"]; readonly networkCount: (did: string) => readonly ["sifa", "stream", "network-count", string]; }; readonly reactions: { readonly all: () => readonly ["sifa", "reactions"]; readonly status: (uris: string[]) => readonly ["sifa", "reactions", "status", string[]]; readonly accountCheck: (appId: string) => readonly ["sifa", "reactions", "account-check", string]; }; readonly roadmap: { readonly all: () => readonly ["sifa", "roadmap"]; readonly votes: () => readonly ["sifa", "roadmap", "votes"]; readonly myVotes: () => readonly ["sifa", "roadmap", "my-votes"]; }; readonly bskyPreferences: { readonly all: () => readonly ["sifa", "bsky-preferences"]; readonly contentLabels: () => readonly ["sifa", "bsky-preferences", "content-labels"]; }; readonly repoInventory: { readonly all: () => readonly ["sifa", "repo-inventory"]; readonly list: () => readonly ["sifa", "repo-inventory", "list"]; }; readonly destructive: { readonly all: () => readonly ["sifa", "destructive"]; readonly wipePreview: () => readonly ["sifa", "destructive", "wipe-preview"]; }; }; type SifaQueryKey = ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType | ReturnType; /** How a single entity binding was resolved during a claim. */ interface OrgClaimBinding { entityId: number; entityRef: string; validatedBy: string | null; status: 'active' | 'pending'; dissolved: boolean; } /** The public org-profile echo returned by claim / update endpoints (no `contact`). */ interface OrgProfileEcho { name: string; description: string | null; website: string | null; entityRefs: string[]; } /** Response body of `POST /api/org/claim`. */ interface OrgClaimResult { orgDid: string; status: 'active' | 'review'; bindings: OrgClaimBinding[]; orgProfile: OrgProfileEcho; } /** Response body of `PUT /api/org/profile`. */ interface OrgProfileUpdateResult { ok: boolean; orgProfile: OrgProfileEcho; } /** Response body of `POST /api/org/domains/challenge`. */ interface OrgDomainChallengeResult { domain: string; txtRecordName: string; txtRecordValue: string; } /** Response body of `POST /api/org/domains/verify` (happy path). */ interface OrgDomainVerifyResult { status: 'verified' | 'pending'; domain: string; } /** Response body of `POST /api/org/notification-emails`. */ interface OrgNotificationEmailAddResult { ok: boolean; status: string; } /** Response body of `DELETE /api/org/notification-emails`. */ interface OrgNotificationEmailRemoveResult { ok: boolean; removed: number; } /** * Finalize an org profile claim (`POST /api/org/claim`). Auth-gated (org-claim * JIT scope) and floor-checked server-side. Never throws -- returns the * structured {@link OrgClaimResult} folded into a {@link WriteResult} on success, * or `{ success: false, error, pdsHost? }` on failure. */ declare function submitOrgClaim(config: SifaApiConfig, body: OrgClaimRequestInput, options?: Omit): Promise>; /** * Edit the org record (`PUT /api/org/profile`). Fresh-from-body server-side PUT * (a cleared optional field is dropped, no spread-merge). Never throws. */ declare function updateOrgProfile(config: SifaApiConfig, body: OrgProfileUpdateRequestInput, options?: Omit): Promise>; /** * Issue a one-time DNS TXT domain challenge (`POST /api/org/domains/challenge`). * Returns the TXT record name + value the org must publish. Never throws. */ declare function requestOrgDomainChallenge(config: SifaApiConfig, body: OrgDomainChallengeRequestInput, options?: Omit): Promise>; /** * Verify a DNS TXT domain challenge (`POST /api/org/domains/verify`). On success * `status` is `verified` or `pending`. Expired / confusable / not-found map to * non-2xx server responses and surface as `{ success: false, error }`. Never * throws. */ declare function verifyOrgDomain(config: SifaApiConfig, body: OrgDomainVerifyRequestInput, options?: Omit): Promise>; /** * Add an org notification email (`POST /api/org/notification-emails`). The * address must use a domain the org controls (checked server-side). An * individual verification email is enqueued through the (dormant) sending * pipeline. Never throws. */ declare function addOrgNotificationEmail(config: SifaApiConfig, body: OrgNotificationEmailRequestInput, options?: Omit): Promise>; /** * Remove an org notification email (`DELETE /api/org/notification-emails`). * Never throws. */ declare function removeOrgNotificationEmail(config: SifaApiConfig, body: OrgNotificationEmailRequestInput, options?: Omit): Promise>; export { type HiddenItemType as $, type ApiFetchOptions as A, type BulkHideProfileItemInput as B, type CreateResult as C, type DeleteAccountResult as D, type EndorsementInput as E, type FeatureAllowlistResponse as F, type FetchMyGithubPullRequestsOptions as G, type FetchMyRoadmapVotesOptions as H, type FetchReactionStatusOptions as I, type FetchSuggestionsOptions as J, type FilterOptions as K, type FollowListPage as L, type FollowProfile as M, type FollowProfilePageResponse as N, type FollowUserResult as O, type FollowingResponse as P, type GetAdminReviewQueuesOptions as Q, type GithubPullRequest as R, type SifaApiConfig as S, type GivenConfirmation as T, HIDDEN_ITEM_SOURCES as U, HIDDEN_ITEM_TYPES as V, type WriteResult as W, type HeatmapDay as X, type HeatmapResponse as Y, type HiddenApp as Z, type HiddenItemSource as _, type ConfirmEndorsementInput as a, confirmEndorsement as a$, type HideProfileItemInput as a0, type ListFeatureAllowlistOptions as a1, type MyGithubPullRequestsResponse as a2, type OrgClaimBinding as a3, type OrgClaimResult as a4, type OrgDomainChallengeResult as a5, type OrgDomainVerifyResult as a6, type OrgNotificationEmailAddResult as a7, type OrgNotificationEmailRemoveResult as a8, type OrgProfileEcho as a9, type SearchFilters as aA, type SearchResponse as aB, type SifaQueryKey as aC, type SimilarProfile as aD, type SkillSearchResult as aE, type StatsResponse as aF, type SubCategoryBulkResult as aG, type SuggestionProfile as aH, type SuggestionsResponse as aI, type UpdateProfileOverrideInput as aJ, type UpdateProfileSelfInput as aK, type UploadAvatarResult as aL, type UploadPronunciationAudioResult as aM, type VerifyExternalAccountResult as aN, type WipePreview as aO, addFeatureAllowlist as aP, addOrgNotificationEmail as aQ, apiFetch as aR, apiFetchOrNull as aS, apiWrite as aT, apiWriteCreate as aU, bulkHideProfileItems as aV, bulkHideStandardPublications as aW, bulkUnhideProfileItems as aX, bulkUnhideStandardPublications as aY, castRoadmapVote as aZ, checkAppAccount as a_, type OrgProfileUpdateResult as aa, type PdsWipeOutcome as ab, type PendingConfirmation as ac, type PendingConfirmationsPage as ad, type ProfileIndustryInput as ae, type ProfileLocationAddress as af, type ProfileLocationInput as ag, type ProfileSearchResult as ah, type ProfileSelfLocation as ai, QUOTED_POSTS_BATCH_MAX as aj, type QuotedPostAuthor as ak, type QuotedPostImage as al, type QuotedPostResult as am, type QuotedPostView as an, type ReactionError as ao, type ReactionResult as ap, type ReactionStatus as aq, type RefreshOrcidPublicationsResult as ar, type RefreshPdsResult as as, type RepoDeleteInput as at, type ResetProfileResult as au, type ResolveQuotedPostsOptions as av, type RoadmapVoteError as aw, type RoadmapVoteResult as ax, type RoadmapVoter as ay, type RoadmapVotesResponse as az, type ConfirmEndorsementResult as b, submitOrgClaim as b$, createConfirmation as b0, createEndorsement as b1, createExternalAccount as b2, createProfileLocation as b3, createReaction as b4, createSkill as b5, deleteAccount as b6, deleteAvatarOverride as b7, deleteExternalAccount as b8, deleteNamePronunciationAudio as b9, fetchSuggestionCount as bA, fetchSuggestions as bB, fetchWipePreview as bC, followUser as bD, getAdminReviewQueues as bE, getBlueskySuggestions as bF, getFollowers as bG, getFollowing as bH, getFollowingFeed as bI, getMutuals as bJ, hideOrcidPublication as bK, hideProfileItem as bL, hideSifaPublication as bM, hideStandardPublication as bN, listFeatureAllowlist as bO, refreshOrcidPublications as bP, refreshPds as bQ, removeFeatureAllowlist as bR, removeOrgNotificationEmail as bS, repoExportUrl as bT, requestOrgDomainChallenge as bU, resetProfile as bV, resolveQuotedPosts as bW, retractRoadmapVote as bX, revokeConfirmation as bY, searchSkills as bZ, setExternalAccountPrimary as b_, deleteProfileLocation as ba, deleteReaction as bb, deleteRepoRecords as bc, deleteSkill as bd, dismissConfirmation as be, fetchAccounts as bf, fetchActivityFeed as bg, fetchActivityTeaser as bh, fetchAppsRegistry as bi, fetchExternalAccounts as bj, fetchFeaturedProfile as bk, fetchFollowing as bl, fetchGivenConfirmations as bm, fetchHeatmapData as bn, fetchHiddenApps as bo, fetchMyGithubPullRequests as bp, fetchMyRoadmapVotes as bq, fetchPendingConfirmations as br, fetchReactionStatus as bs, fetchRepoInventory as bt, fetchRoadmapVotes as bu, fetchSearchFilters as bv, fetchSearchProfiles as bw, fetchSimilarProfiles as bx, fetchSkillSuggestions as by, fetchStats as bz, type AccountCheckResult as c, switchAccount as c0, unfollowUser as c1, unhideOrcidPublication as c2, unhideProfileItem as c3, unhideSifaPublication as c4, unhideStandardPublication as c5, unsetExternalAccountPrimary as c6, updateExternalAccount as c7, updateOrgProfile as c8, updateProfileLocation as c9, updateProfileOverride as ca, updateProfileSelf as cb, updateSkill as cc, updateSkillSubCategories as cd, uploadAvatar as ce, uploadNamePronunciationAudio as cf, verifyExternalAccount as cg, verifyOrgDomain as ch, type CompanySearchFilters as ci, type CompanySearchResponse as cj, type CompanySearchResult as ck, fetchSearchCompanies as cl, type AccountSummary as d, type ActivityFeedResponse as e, type ActivityItem as f, type ActivityItemLinkHealth as g, type ActivityTeaserResponse as h, type AdminReviewQueues as i, ApiError as j, type AppRegistryEntry as k, type CastRoadmapVoteResult as l, type CheckAppAccountOptions as m, type ConfirmationInput as n, type ConfirmationSubjectInput as o, type CreateExternalAccountResult as p, type ExternalAccountInput as q, type FeaturedProfile as r, sifaQueryKeys as s, type FetchAccountsOptions as t, type FetchActivityFeedOptions as u, type FetchActivityTeaserOptions as v, type FetchFollowListOptions as w, type FetchFollowProfilePageOptions as x, type FetchFollowingFeedOptions as y, type FetchHiddenAppsOptions as z };