@singi-labs/sifa-sdk 0.19.49 → 0.19.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/{org-CxTEjjrm.d.ts → org-Bp4mNT8K.d.ts} +26 -2
- package/dist/{org-DC_FpoTY.d.cts → org-CFzRg61Q.d.cts} +26 -2
- package/dist/query/fetchers/follow.js +30 -6
- package/dist/query/fetchers/follow.js.map +1 -1
- package/dist/query/fetchers/index.cjs +31 -6
- package/dist/query/fetchers/index.cjs.map +1 -1
- package/dist/query/fetchers/index.d.cts +1 -1
- package/dist/query/fetchers/index.d.ts +1 -1
- package/dist/query/fetchers/index.js +4 -0
- package/dist/query/fetchers/index.js.map +1 -1
- package/dist/query/hooks/index.cjs +45 -7
- package/dist/query/hooks/index.cjs.map +1 -1
- package/dist/query/hooks/index.d.cts +2 -2
- package/dist/query/hooks/index.d.ts +2 -2
- package/dist/query/hooks/index.js +2 -0
- package/dist/query/hooks/index.js.map +1 -1
- package/dist/query/hooks/use-follow.js +21 -1
- package/dist/query/hooks/use-follow.js.map +1 -1
- package/dist/query/index.cjs +51 -7
- package/dist/query/index.cjs.map +1 -1
- package/dist/query/index.d.cts +3 -3
- package/dist/query/index.d.ts +3 -3
- package/dist/query/index.js +6 -0
- package/dist/query/index.js.map +1 -1
- package/dist/query/keys.js +1 -0
- package/dist/query/keys.js.map +1 -1
- package/dist/{use-org-notification-emails-CWWi1D8t.d.ts → use-org-notification-emails-CJ0hKqco.d.ts} +9 -3
- package/dist/{use-org-notification-emails-DOyAF0C_.d.cts → use-org-notification-emails-Dk084Rrw.d.cts} +9 -3
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -7128,7 +7128,7 @@ function describeSifaRecord(collection, value) {
|
|
|
7128
7128
|
}
|
|
7129
7129
|
|
|
7130
7130
|
// src/index.ts
|
|
7131
|
-
var SIFA_SDK_VERSION = "0.19.
|
|
7131
|
+
var SIFA_SDK_VERSION = "0.19.50";
|
|
7132
7132
|
|
|
7133
7133
|
exports.ACTIVITY_TIERS = ACTIVITY_TIERS;
|
|
7134
7134
|
exports.ACTIVITY_VERBS = ACTIVITY_VERBS;
|
package/dist/index.js
CHANGED
|
@@ -347,7 +347,7 @@ import {
|
|
|
347
347
|
roadmapIssueUrl
|
|
348
348
|
} from "./roadmap/index.js";
|
|
349
349
|
import { SIFA_REPO_GROUPS, describeSifaRecord, repoGroupForCollection } from "./repo/index.js";
|
|
350
|
-
var SIFA_SDK_VERSION = "0.19.
|
|
350
|
+
var SIFA_SDK_VERSION = "0.19.50";
|
|
351
351
|
export {
|
|
352
352
|
ACTIVITY_TIERS,
|
|
353
353
|
ACTIVITY_VERBS,
|
|
@@ -1050,7 +1050,9 @@ interface FollowingFeedApp {
|
|
|
1050
1050
|
* Why a following-feed page came back empty. Lets a client say something true
|
|
1051
1051
|
* per case instead of one catch-all sentence, and point at the right next step.
|
|
1052
1052
|
*/
|
|
1053
|
-
type FollowingFeedEmptyReason = 'no_follows' | 'no_visible_follows' | 'no_cross_app_activity' | 'no_recent_records' | 'all_hidden' | 'nothing_renderable' | 'hydration_failed'
|
|
1053
|
+
type FollowingFeedEmptyReason = 'no_follows' | 'no_visible_follows' | 'no_cross_app_activity' | 'no_recent_records' | 'all_hidden' | 'nothing_renderable' | 'hydration_failed'
|
|
1054
|
+
/** The feed is still being built. Nothing is wrong: ask again shortly. */
|
|
1055
|
+
| 'building';
|
|
1054
1056
|
/** Options for {@link fetchFollowingFeed}. */
|
|
1055
1057
|
interface FetchFollowingFeedOptions extends ApiFetchOptions {
|
|
1056
1058
|
limit?: number;
|
|
@@ -1079,6 +1081,14 @@ interface FollowingFeedResponse extends ActivityFeedResponse {
|
|
|
1079
1081
|
apps?: FollowingFeedApp[];
|
|
1080
1082
|
/** Set only when `items` is empty. */
|
|
1081
1083
|
reason?: FollowingFeedEmptyReason;
|
|
1084
|
+
/** When this feed was built (ISO 8601). Absent on a `building` answer. */
|
|
1085
|
+
builtAt?: string;
|
|
1086
|
+
/**
|
|
1087
|
+
* True when this is an older build, served while a newer one is built in
|
|
1088
|
+
* the background. Poll {@link fetchFollowingFeedVersion} to learn when the
|
|
1089
|
+
* newer one is ready.
|
|
1090
|
+
*/
|
|
1091
|
+
stale?: boolean;
|
|
1082
1092
|
}
|
|
1083
1093
|
/**
|
|
1084
1094
|
* The viewer's cross-app following feed: what OTHER apps their connections use
|
|
@@ -1092,6 +1102,19 @@ interface FollowingFeedResponse extends ActivityFeedResponse {
|
|
|
1092
1102
|
* finite first page (no cursor yet).
|
|
1093
1103
|
*/
|
|
1094
1104
|
declare function fetchFollowingFeed(config: SifaApiConfig, opts?: FetchFollowingFeedOptions): Promise<FollowingFeedResponse | null>;
|
|
1105
|
+
/** When the cached following feed for a query was built. */
|
|
1106
|
+
interface FollowingFeedVersion {
|
|
1107
|
+
/** ISO 8601, or null when nothing is cached for this query. */
|
|
1108
|
+
builtAt: string | null;
|
|
1109
|
+
}
|
|
1110
|
+
/**
|
|
1111
|
+
* When the cached following feed for the same query was built. Cheap: it never
|
|
1112
|
+
* builds a feed. A client showing a `stale` feed polls this and offers the
|
|
1113
|
+
* newer one once {@link isNewerFollowingFeed} says so. Returns `null` on error.
|
|
1114
|
+
*/
|
|
1115
|
+
declare function fetchFollowingFeedVersion(config: SifaApiConfig, opts?: FetchFollowingFeedOptions): Promise<FollowingFeedVersion | null>;
|
|
1116
|
+
/** True when `latestBuiltAt` is a newer build than the one shown (`shownBuiltAt`). */
|
|
1117
|
+
declare function isNewerFollowingFeed(shownBuiltAt: string | null | undefined, latestBuiltAt: string | null | undefined): boolean;
|
|
1095
1118
|
|
|
1096
1119
|
/**
|
|
1097
1120
|
* Options shared by the cursor-paginated follow-graph endpoints introduced in
|
|
@@ -1553,6 +1576,7 @@ declare const sifaQueryKeys: {
|
|
|
1553
1576
|
readonly followers: (handle: string) => readonly ["sifa", "follow", "followers", string];
|
|
1554
1577
|
readonly followingOf: (handle: string) => readonly ["sifa", "follow", "following-of", string];
|
|
1555
1578
|
readonly feed: (opts: Record<string, unknown>) => readonly ["sifa", "follow", "feed", Record<string, unknown>];
|
|
1579
|
+
readonly feedVersion: (opts: Record<string, unknown>) => readonly ["sifa", "follow", "feed-version", Record<string, unknown>];
|
|
1556
1580
|
readonly mutuals: (handle: string) => readonly ["sifa", "follow", "mutuals", string];
|
|
1557
1581
|
readonly blueskySuggestions: () => readonly ["sifa", "follow", "bluesky-suggestions"];
|
|
1558
1582
|
};
|
|
@@ -1718,4 +1742,4 @@ declare function addOrgNotificationEmail(config: SifaApiConfig, body: OrgNotific
|
|
|
1718
1742
|
*/
|
|
1719
1743
|
declare function removeOrgNotificationEmail(config: SifaApiConfig, body: OrgNotificationEmailRequestInput, options?: Omit<ApiFetchOptions, 'method' | 'body'>): Promise<WriteResult & Partial<OrgNotificationEmailRemoveResult>>;
|
|
1720
1744
|
|
|
1721
|
-
export { type
|
|
1745
|
+
export { type HeatmapDay as $, type AccountCheckResult as A, type BulkHideProfileItemInput as B, type ConfirmEndorsementInput as C, type DeleteAccountResult as D, type EndorsementInput as E, type FeatureAllowlistResponse as F, type FetchInboxCountsOptions as G, type FetchMyGithubPullRequestsOptions as H, type FetchMyRoadmapVotesOptions as I, type FetchProfileCompletenessOptions as J, type FetchReactionStatusOptions as K, type FetchSuggestionsOptions as L, type FetchUnlinkedPositionsOptions as M, type FollowListPage as N, type FollowProfile as O, type FollowProfilePageResponse as P, type FollowUserResult as Q, type FollowingFeedApp as R, type FollowingFeedEmptyReason as S, type FollowingFeedResponse as T, type FollowingFeedVersion as U, type FollowingResponse as V, type GetAdminReviewQueuesOptions as W, type GithubPullRequest as X, type GivenConfirmation as Y, HIDDEN_ITEM_SOURCES as Z, HIDDEN_ITEM_TYPES as _, type ConfirmEndorsementResult as a, bulkHideProfileItems as a$, type HeatmapResponse as a0, type HiddenActivityItem as a1, type HiddenApp as a2, type HiddenItemSource as a3, type HiddenItemType as a4, type HideActivityItemInput as a5, type HideProfileItemInput as a6, type InboxCounts as a7, type ListFeatureAllowlistOptions as a8, type MyGithubPullRequestsResponse as a9, type ReactionStatus as aA, type RefreshOrcidPublicationsResult as aB, type RefreshPdsResult as aC, type RepoDeleteInput as aD, type ResetProfileResult as aE, type ResolveQuotedPostsOptions as aF, type RoadmapVoteError as aG, type RoadmapVoteResult as aH, type RoadmapVoter as aI, type RoadmapVotesResponse as aJ, type SifaQueryKey as aK, type SimilarProfile as aL, type StatsResponse as aM, type SubCategoryBulkResult as aN, type SuggestionProfile as aO, type SuggestionsResponse as aP, type UnhideActivityItemInput as aQ, type UnlinkedPosition as aR, type UnlinkedPositionsResult as aS, type UpdateProfileOverrideInput as aT, type UpdateProfileSelfInput as aU, type UploadAvatarResult as aV, type UploadPronunciationAudioResult as aW, type VerifyExternalAccountResult as aX, type WipePreview as aY, addFeatureAllowlist as aZ, addOrgNotificationEmail as a_, type OrgClaimBinding as aa, type OrgClaimResult as ab, type OrgDomainChallengeResult as ac, type OrgDomainVerifyResult as ad, type OrgNotificationEmailAddResult as ae, type OrgNotificationEmailRemoveResult as af, type OrgProfileEcho as ag, type OrgProfileUpdateResult as ah, PROFILE_COMPLETENESS_SIGNALS as ai, type PdsWipeOutcome as aj, type PendingConfirmation as ak, type PendingConfirmationsPage as al, type PrimarySection as am, type ProfileCompleteness as an, type ProfileCompletenessSignal as ao, type ProfileIndustryInput as ap, type ProfileLocationAddress as aq, type ProfileLocationInput as ar, type ProfileSelfLocation as as, QUOTED_POSTS_BATCH_MAX as at, type QuotedPostAuthor as au, type QuotedPostImage as av, type QuotedPostResult as aw, type QuotedPostView as ax, type ReactionError as ay, type ReactionResult as az, type AccountSummary as b, refreshPds as b$, bulkHideStandardPublications as b0, bulkUnhideProfileItems as b1, bulkUnhideStandardPublications as b2, castRoadmapVote as b3, checkAppAccount as b4, confirmEndorsement as b5, createConfirmation as b6, createEndorsement as b7, createExternalAccount as b8, createProfileLocation as b9, fetchMyGithubPullRequests as bA, fetchMyRoadmapVotes as bB, fetchPendingConfirmations as bC, fetchProfileCompleteness as bD, fetchReactionStatus as bE, fetchRepoInventory as bF, fetchRoadmapVotes as bG, fetchSimilarProfiles as bH, fetchStats as bI, fetchSuggestionCount as bJ, fetchSuggestions as bK, fetchUnlinkedPositions as bL, fetchWipePreview as bM, followUser as bN, getAdminReviewQueues as bO, getBlueskySuggestions as bP, getFollowers as bQ, getFollowing as bR, getMutuals as bS, hideActivityItem as bT, hideOrcidPublication as bU, hideProfileItem as bV, hideSifaPublication as bW, hideStandardPublication as bX, isNewerFollowingFeed as bY, listFeatureAllowlist as bZ, refreshOrcidPublications as b_, createReaction as ba, createSkill as bb, deleteAccount as bc, deleteAvatarOverride as bd, deleteExternalAccount as be, deleteNamePronunciationAudio as bf, deleteProfileLocation as bg, deleteReaction as bh, deleteRepoRecords as bi, deleteSkill as bj, dismissConfirmation as bk, dismissUnlinkedPosition as bl, fetchAccounts as bm, fetchActivityFeed as bn, fetchActivityTeaser as bo, fetchAppsRegistry as bp, fetchExternalAccounts as bq, fetchFeaturedProfile as br, fetchFollowing as bs, fetchFollowingFeed as bt, fetchFollowingFeedVersion as bu, fetchGivenConfirmations as bv, fetchHeatmapData as bw, fetchHiddenActivityItems as bx, fetchHiddenApps as by, fetchInboxCounts as bz, type ActivityFeedResponse as c, removeFeatureAllowlist as c0, removeOrgNotificationEmail as c1, repoExportUrl as c2, requestOrgDomainChallenge as c3, resetProfile as c4, resolveQuotedPosts as c5, retractRoadmapVote as c6, revokeConfirmation as c7, setExternalAccountPrimary as c8, setSectionPrimary as c9, submitOrgClaim as ca, switchAccount as cb, unfollowUser as cc, unhideActivityItem as cd, unhideOrcidPublication as ce, unhideProfileItem as cf, unhideSifaPublication as cg, unhideStandardPublication as ch, unsetExternalAccountPrimary as ci, unsetSectionPrimary as cj, updateExternalAccount as ck, updateOrgProfile as cl, updateProfileLocation as cm, updateProfileOverride as cn, updateProfileSelf as co, updateSkill as cp, updateSkillSubCategories as cq, uploadAvatar as cr, uploadNamePronunciationAudio as cs, verifyExternalAccount as ct, verifyOrgDomain as cu, type ActivityItem as d, type ActivityItemLinkHealth as e, type ActivityTeaserResponse as f, type AdminReviewQueues as g, type AppRegistryEntry as h, type CastRoadmapVoteResult as i, type CheckAppAccountOptions as j, type ConfirmationInput as k, type ConfirmationSubjectInput as l, type CreateExternalAccountResult as m, type DismissUnlinkedPositionInput as n, type ExternalAccountInput as o, type FeaturedProfile as p, type FetchAccountsOptions as q, type FetchActivityFeedOptions as r, sifaQueryKeys as s, type FetchActivityTeaserOptions as t, type FetchConfirmationsOptions as u, type FetchFollowListOptions as v, type FetchFollowProfilePageOptions as w, type FetchFollowingFeedOptions as x, type FetchHiddenActivityItemsOptions as y, type FetchHiddenAppsOptions as z };
|
|
@@ -1050,7 +1050,9 @@ interface FollowingFeedApp {
|
|
|
1050
1050
|
* Why a following-feed page came back empty. Lets a client say something true
|
|
1051
1051
|
* per case instead of one catch-all sentence, and point at the right next step.
|
|
1052
1052
|
*/
|
|
1053
|
-
type FollowingFeedEmptyReason = 'no_follows' | 'no_visible_follows' | 'no_cross_app_activity' | 'no_recent_records' | 'all_hidden' | 'nothing_renderable' | 'hydration_failed'
|
|
1053
|
+
type FollowingFeedEmptyReason = 'no_follows' | 'no_visible_follows' | 'no_cross_app_activity' | 'no_recent_records' | 'all_hidden' | 'nothing_renderable' | 'hydration_failed'
|
|
1054
|
+
/** The feed is still being built. Nothing is wrong: ask again shortly. */
|
|
1055
|
+
| 'building';
|
|
1054
1056
|
/** Options for {@link fetchFollowingFeed}. */
|
|
1055
1057
|
interface FetchFollowingFeedOptions extends ApiFetchOptions {
|
|
1056
1058
|
limit?: number;
|
|
@@ -1079,6 +1081,14 @@ interface FollowingFeedResponse extends ActivityFeedResponse {
|
|
|
1079
1081
|
apps?: FollowingFeedApp[];
|
|
1080
1082
|
/** Set only when `items` is empty. */
|
|
1081
1083
|
reason?: FollowingFeedEmptyReason;
|
|
1084
|
+
/** When this feed was built (ISO 8601). Absent on a `building` answer. */
|
|
1085
|
+
builtAt?: string;
|
|
1086
|
+
/**
|
|
1087
|
+
* True when this is an older build, served while a newer one is built in
|
|
1088
|
+
* the background. Poll {@link fetchFollowingFeedVersion} to learn when the
|
|
1089
|
+
* newer one is ready.
|
|
1090
|
+
*/
|
|
1091
|
+
stale?: boolean;
|
|
1082
1092
|
}
|
|
1083
1093
|
/**
|
|
1084
1094
|
* The viewer's cross-app following feed: what OTHER apps their connections use
|
|
@@ -1092,6 +1102,19 @@ interface FollowingFeedResponse extends ActivityFeedResponse {
|
|
|
1092
1102
|
* finite first page (no cursor yet).
|
|
1093
1103
|
*/
|
|
1094
1104
|
declare function fetchFollowingFeed(config: SifaApiConfig, opts?: FetchFollowingFeedOptions): Promise<FollowingFeedResponse | null>;
|
|
1105
|
+
/** When the cached following feed for a query was built. */
|
|
1106
|
+
interface FollowingFeedVersion {
|
|
1107
|
+
/** ISO 8601, or null when nothing is cached for this query. */
|
|
1108
|
+
builtAt: string | null;
|
|
1109
|
+
}
|
|
1110
|
+
/**
|
|
1111
|
+
* When the cached following feed for the same query was built. Cheap: it never
|
|
1112
|
+
* builds a feed. A client showing a `stale` feed polls this and offers the
|
|
1113
|
+
* newer one once {@link isNewerFollowingFeed} says so. Returns `null` on error.
|
|
1114
|
+
*/
|
|
1115
|
+
declare function fetchFollowingFeedVersion(config: SifaApiConfig, opts?: FetchFollowingFeedOptions): Promise<FollowingFeedVersion | null>;
|
|
1116
|
+
/** True when `latestBuiltAt` is a newer build than the one shown (`shownBuiltAt`). */
|
|
1117
|
+
declare function isNewerFollowingFeed(shownBuiltAt: string | null | undefined, latestBuiltAt: string | null | undefined): boolean;
|
|
1095
1118
|
|
|
1096
1119
|
/**
|
|
1097
1120
|
* Options shared by the cursor-paginated follow-graph endpoints introduced in
|
|
@@ -1553,6 +1576,7 @@ declare const sifaQueryKeys: {
|
|
|
1553
1576
|
readonly followers: (handle: string) => readonly ["sifa", "follow", "followers", string];
|
|
1554
1577
|
readonly followingOf: (handle: string) => readonly ["sifa", "follow", "following-of", string];
|
|
1555
1578
|
readonly feed: (opts: Record<string, unknown>) => readonly ["sifa", "follow", "feed", Record<string, unknown>];
|
|
1579
|
+
readonly feedVersion: (opts: Record<string, unknown>) => readonly ["sifa", "follow", "feed-version", Record<string, unknown>];
|
|
1556
1580
|
readonly mutuals: (handle: string) => readonly ["sifa", "follow", "mutuals", string];
|
|
1557
1581
|
readonly blueskySuggestions: () => readonly ["sifa", "follow", "bluesky-suggestions"];
|
|
1558
1582
|
};
|
|
@@ -1718,4 +1742,4 @@ declare function addOrgNotificationEmail(config: SifaApiConfig, body: OrgNotific
|
|
|
1718
1742
|
*/
|
|
1719
1743
|
declare function removeOrgNotificationEmail(config: SifaApiConfig, body: OrgNotificationEmailRequestInput, options?: Omit<ApiFetchOptions, 'method' | 'body'>): Promise<WriteResult & Partial<OrgNotificationEmailRemoveResult>>;
|
|
1720
1744
|
|
|
1721
|
-
export { type
|
|
1745
|
+
export { type HeatmapDay as $, type AccountCheckResult as A, type BulkHideProfileItemInput as B, type ConfirmEndorsementInput as C, type DeleteAccountResult as D, type EndorsementInput as E, type FeatureAllowlistResponse as F, type FetchInboxCountsOptions as G, type FetchMyGithubPullRequestsOptions as H, type FetchMyRoadmapVotesOptions as I, type FetchProfileCompletenessOptions as J, type FetchReactionStatusOptions as K, type FetchSuggestionsOptions as L, type FetchUnlinkedPositionsOptions as M, type FollowListPage as N, type FollowProfile as O, type FollowProfilePageResponse as P, type FollowUserResult as Q, type FollowingFeedApp as R, type FollowingFeedEmptyReason as S, type FollowingFeedResponse as T, type FollowingFeedVersion as U, type FollowingResponse as V, type GetAdminReviewQueuesOptions as W, type GithubPullRequest as X, type GivenConfirmation as Y, HIDDEN_ITEM_SOURCES as Z, HIDDEN_ITEM_TYPES as _, type ConfirmEndorsementResult as a, bulkHideProfileItems as a$, type HeatmapResponse as a0, type HiddenActivityItem as a1, type HiddenApp as a2, type HiddenItemSource as a3, type HiddenItemType as a4, type HideActivityItemInput as a5, type HideProfileItemInput as a6, type InboxCounts as a7, type ListFeatureAllowlistOptions as a8, type MyGithubPullRequestsResponse as a9, type ReactionStatus as aA, type RefreshOrcidPublicationsResult as aB, type RefreshPdsResult as aC, type RepoDeleteInput as aD, type ResetProfileResult as aE, type ResolveQuotedPostsOptions as aF, type RoadmapVoteError as aG, type RoadmapVoteResult as aH, type RoadmapVoter as aI, type RoadmapVotesResponse as aJ, type SifaQueryKey as aK, type SimilarProfile as aL, type StatsResponse as aM, type SubCategoryBulkResult as aN, type SuggestionProfile as aO, type SuggestionsResponse as aP, type UnhideActivityItemInput as aQ, type UnlinkedPosition as aR, type UnlinkedPositionsResult as aS, type UpdateProfileOverrideInput as aT, type UpdateProfileSelfInput as aU, type UploadAvatarResult as aV, type UploadPronunciationAudioResult as aW, type VerifyExternalAccountResult as aX, type WipePreview as aY, addFeatureAllowlist as aZ, addOrgNotificationEmail as a_, type OrgClaimBinding as aa, type OrgClaimResult as ab, type OrgDomainChallengeResult as ac, type OrgDomainVerifyResult as ad, type OrgNotificationEmailAddResult as ae, type OrgNotificationEmailRemoveResult as af, type OrgProfileEcho as ag, type OrgProfileUpdateResult as ah, PROFILE_COMPLETENESS_SIGNALS as ai, type PdsWipeOutcome as aj, type PendingConfirmation as ak, type PendingConfirmationsPage as al, type PrimarySection as am, type ProfileCompleteness as an, type ProfileCompletenessSignal as ao, type ProfileIndustryInput as ap, type ProfileLocationAddress as aq, type ProfileLocationInput as ar, type ProfileSelfLocation as as, QUOTED_POSTS_BATCH_MAX as at, type QuotedPostAuthor as au, type QuotedPostImage as av, type QuotedPostResult as aw, type QuotedPostView as ax, type ReactionError as ay, type ReactionResult as az, type AccountSummary as b, refreshPds as b$, bulkHideStandardPublications as b0, bulkUnhideProfileItems as b1, bulkUnhideStandardPublications as b2, castRoadmapVote as b3, checkAppAccount as b4, confirmEndorsement as b5, createConfirmation as b6, createEndorsement as b7, createExternalAccount as b8, createProfileLocation as b9, fetchMyGithubPullRequests as bA, fetchMyRoadmapVotes as bB, fetchPendingConfirmations as bC, fetchProfileCompleteness as bD, fetchReactionStatus as bE, fetchRepoInventory as bF, fetchRoadmapVotes as bG, fetchSimilarProfiles as bH, fetchStats as bI, fetchSuggestionCount as bJ, fetchSuggestions as bK, fetchUnlinkedPositions as bL, fetchWipePreview as bM, followUser as bN, getAdminReviewQueues as bO, getBlueskySuggestions as bP, getFollowers as bQ, getFollowing as bR, getMutuals as bS, hideActivityItem as bT, hideOrcidPublication as bU, hideProfileItem as bV, hideSifaPublication as bW, hideStandardPublication as bX, isNewerFollowingFeed as bY, listFeatureAllowlist as bZ, refreshOrcidPublications as b_, createReaction as ba, createSkill as bb, deleteAccount as bc, deleteAvatarOverride as bd, deleteExternalAccount as be, deleteNamePronunciationAudio as bf, deleteProfileLocation as bg, deleteReaction as bh, deleteRepoRecords as bi, deleteSkill as bj, dismissConfirmation as bk, dismissUnlinkedPosition as bl, fetchAccounts as bm, fetchActivityFeed as bn, fetchActivityTeaser as bo, fetchAppsRegistry as bp, fetchExternalAccounts as bq, fetchFeaturedProfile as br, fetchFollowing as bs, fetchFollowingFeed as bt, fetchFollowingFeedVersion as bu, fetchGivenConfirmations as bv, fetchHeatmapData as bw, fetchHiddenActivityItems as bx, fetchHiddenApps as by, fetchInboxCounts as bz, type ActivityFeedResponse as c, removeFeatureAllowlist as c0, removeOrgNotificationEmail as c1, repoExportUrl as c2, requestOrgDomainChallenge as c3, resetProfile as c4, resolveQuotedPosts as c5, retractRoadmapVote as c6, revokeConfirmation as c7, setExternalAccountPrimary as c8, setSectionPrimary as c9, submitOrgClaim as ca, switchAccount as cb, unfollowUser as cc, unhideActivityItem as cd, unhideOrcidPublication as ce, unhideProfileItem as cf, unhideSifaPublication as cg, unhideStandardPublication as ch, unsetExternalAccountPrimary as ci, unsetSectionPrimary as cj, updateExternalAccount as ck, updateOrgProfile as cl, updateProfileLocation as cm, updateProfileOverride as cn, updateProfileSelf as co, updateSkill as cp, updateSkillSubCategories as cq, uploadAvatar as cr, uploadNamePronunciationAudio as cs, verifyExternalAccount as ct, verifyOrgDomain as cu, type ActivityItem as d, type ActivityItemLinkHealth as e, type ActivityTeaserResponse as f, type AdminReviewQueues as g, type AppRegistryEntry as h, type CastRoadmapVoteResult as i, type CheckAppAccountOptions as j, type ConfirmationInput as k, type ConfirmationSubjectInput as l, type CreateExternalAccountResult as m, type DismissUnlinkedPositionInput as n, type ExternalAccountInput as o, type FeaturedProfile as p, type FetchAccountsOptions as q, type FetchActivityFeedOptions as r, sifaQueryKeys as s, type FetchActivityTeaserOptions as t, type FetchConfirmationsOptions as u, type FetchFollowListOptions as v, type FetchFollowProfilePageOptions as w, type FetchFollowingFeedOptions as x, type FetchHiddenActivityItemsOptions as y, type FetchHiddenAppsOptions as z };
|
|
@@ -71,7 +71,7 @@ async function getFollowing(config, handle, opts = {}) {
|
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
73
|
var FOLLOWING_FEED_LXM = "id.sifa.feed.getFollowingFeed";
|
|
74
|
-
async function
|
|
74
|
+
async function followingFeedRequest(config, opts) {
|
|
75
75
|
const params = new URLSearchParams();
|
|
76
76
|
if (opts.limit) params.set("limit", String(opts.limit));
|
|
77
77
|
if (opts.app) params.set("app", opts.app);
|
|
@@ -83,23 +83,47 @@ async function fetchFollowingFeed(config, opts = {}) {
|
|
|
83
83
|
const token = await config.getAuthToken(FOLLOWING_FEED_LXM);
|
|
84
84
|
if (token) headers.Authorization = `Bearer ${token}`;
|
|
85
85
|
}
|
|
86
|
+
return { query: qs ? `?${qs}` : "", headers };
|
|
87
|
+
}
|
|
88
|
+
async function fetchFollowingFeed(config, opts = {}) {
|
|
89
|
+
const { query, headers } = await followingFeedRequest(config, opts);
|
|
86
90
|
try {
|
|
87
|
-
return await apiFetch(
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
91
|
+
return await apiFetch(config, `/api/following/feed${query}`, {
|
|
92
|
+
credentials: "include",
|
|
93
|
+
cache: "no-store",
|
|
94
|
+
...opts,
|
|
95
|
+
headers
|
|
96
|
+
});
|
|
92
97
|
} catch {
|
|
93
98
|
return null;
|
|
94
99
|
}
|
|
95
100
|
}
|
|
101
|
+
async function fetchFollowingFeedVersion(config, opts = {}) {
|
|
102
|
+
const { query, headers } = await followingFeedRequest(config, opts);
|
|
103
|
+
try {
|
|
104
|
+
return await apiFetch(config, `/api/following/feed/version${query}`, {
|
|
105
|
+
credentials: "include",
|
|
106
|
+
cache: "no-store",
|
|
107
|
+
...opts,
|
|
108
|
+
headers
|
|
109
|
+
});
|
|
110
|
+
} catch {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
function isNewerFollowingFeed(shownBuiltAt, latestBuiltAt) {
|
|
115
|
+
if (!shownBuiltAt || !latestBuiltAt) return false;
|
|
116
|
+
return Date.parse(latestBuiltAt) > Date.parse(shownBuiltAt);
|
|
117
|
+
}
|
|
96
118
|
export {
|
|
97
119
|
FOLLOWING_FEED_LXM,
|
|
98
120
|
fetchFollowing,
|
|
99
121
|
fetchFollowingFeed,
|
|
122
|
+
fetchFollowingFeedVersion,
|
|
100
123
|
followUser,
|
|
101
124
|
getFollowers,
|
|
102
125
|
getFollowing,
|
|
126
|
+
isNewerFollowingFeed,
|
|
103
127
|
unfollowUser
|
|
104
128
|
};
|
|
105
129
|
//# sourceMappingURL=follow.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/query/fetchers/follow.ts"],"sourcesContent":["import {\n apiFetch,\n encodeIdentifier,\n apiWrite,\n type ApiFetchOptions,\n type SifaApiConfig,\n type WriteResult,\n} from '../client.js';\nimport type { ActivityFeedResponse } from './activity.js';\n\nexport interface FollowProfile {\n did: string;\n handle: string;\n displayName?: string;\n headline?: string;\n avatarUrl?: string;\n source: string;\n claimed: boolean;\n followedAt: string;\n blueskyVerified?: boolean;\n blueskyVerifiedAt?: string | null;\n}\n\nexport interface FollowingResponse {\n follows: FollowProfile[];\n cursor?: string;\n}\n\n/** People the authenticated user follows. Empty on error. */\nexport async function fetchFollowing(\n config: SifaApiConfig,\n opts: { source?: string; cursor?: string; limit?: number } & ApiFetchOptions = {},\n): Promise<FollowingResponse> {\n const params = new URLSearchParams();\n if (opts.source) params.set('source', opts.source);\n if (opts.cursor) params.set('cursor', opts.cursor);\n if (opts.limit) params.set('limit', String(opts.limit));\n const qs = params.toString();\n\n try {\n return await apiFetch<FollowingResponse>(config, `/api/following${qs ? `?${qs}` : ''}`, {\n credentials: 'include',\n cache: 'no-store',\n ...opts,\n });\n } catch {\n return { follows: [] };\n }\n}\n\n/**\n * Result of {@link followUser}. Extends {@link WriteResult} with the\n * follow `rkey` returned by sifa-api on success. Self-follow + invalid\n * handle surface as `success: false` with the server-provided message;\n * dup-follow is idempotent (sifa-api E7) and resolves as `success: true`.\n */\nexport interface FollowUserResult extends WriteResult {\n rkey?: string;\n /** DID of the followed subject (server-resolved from the handle). */\n subjectDid?: string;\n}\n\n/**\n * Create an `id.sifa.graph.follow` record on the caller's PDS via the\n * AppView. Idempotent on duplicate (server catches the unique-violation\n * and returns 200, per sifa-api#673 E7).\n */\nexport function followUser(\n config: SifaApiConfig,\n handle: string,\n opts: { note?: string } & Omit<ApiFetchOptions, 'method' | 'body'> = {},\n): Promise<FollowUserResult> {\n const { note, ...rest } = opts;\n return apiWrite<{ rkey?: string; subjectDid?: string }>(\n config,\n `/api/follow/${encodeIdentifier(handle)}`,\n 'POST',\n {\n body: note !== undefined ? { note } : undefined,\n ...rest,\n },\n );\n}\n\n/** Delete the authenticated viewer's `id.sifa.graph.follow` for `handle`. */\nexport function unfollowUser(\n config: SifaApiConfig,\n handle: string,\n opts: Omit<ApiFetchOptions, 'method' | 'body'> = {},\n): Promise<WriteResult> {\n return apiWrite(config, `/api/follow/${encodeIdentifier(handle)}`, 'DELETE', opts);\n}\n\nexport interface FollowListPage {\n follows: FollowProfile[];\n cursor: string | null;\n}\n\nexport interface FetchFollowListOptions extends ApiFetchOptions {\n cursor?: string;\n limit?: number;\n /**\n * Pass the caller's `Cookie` header on Next.js RSC server-side calls\n * (mirrors {@link FetchActivityFeedOptions}; required for authenticated\n * server fetches because `credentials: 'include'` does not propagate\n * cookies from RSC).\n */\n cookieHeader?: string;\n}\n\nfunction buildListPath(prefix: string, opts: FetchFollowListOptions): string {\n const params = new URLSearchParams();\n if (opts.cursor) params.set('cursor', opts.cursor);\n if (opts.limit) params.set('limit', String(opts.limit));\n const qs = params.toString();\n return `${prefix}${qs ? `?${qs}` : ''}`;\n}\n\n/**\n * Paginated list of `handle`'s followers. Returns an empty page on error\n * so the UI can render a graceful \"no followers yet\" state.\n */\nexport async function getFollowers(\n config: SifaApiConfig,\n handle: string,\n opts: FetchFollowListOptions = {},\n): Promise<FollowListPage> {\n const headers: Record<string, string> = { ...(opts.headers ?? {}) };\n if (opts.cookieHeader) headers.cookie = opts.cookieHeader;\n try {\n const res = await apiFetch<{ follows: FollowProfile[]; cursor?: string | null }>(\n config,\n buildListPath(`/api/profile/${encodeIdentifier(handle)}/followers`, opts),\n { credentials: 'include', cache: 'no-store', ...opts, headers },\n );\n return { follows: res.follows, cursor: res.cursor ?? null };\n } catch {\n return { follows: [], cursor: null };\n }\n}\n\n/** Paginated list of who `handle` follows. */\nexport async function getFollowing(\n config: SifaApiConfig,\n handle: string,\n opts: FetchFollowListOptions = {},\n): Promise<FollowListPage> {\n const headers: Record<string, string> = { ...(opts.headers ?? {}) };\n if (opts.cookieHeader) headers.cookie = opts.cookieHeader;\n try {\n const res = await apiFetch<{ follows: FollowProfile[]; cursor?: string | null }>(\n config,\n buildListPath(`/api/profile/${encodeIdentifier(handle)}/following`, opts),\n { credentials: 'include', cache: 'no-store', ...opts, headers },\n );\n return { follows: res.follows, cursor: res.cursor ?? null };\n } catch {\n return { follows: [], cursor: null };\n }\n}\n\n/** The method binding for the following-feed service-auth token; MUST match the\n * sifa-api endpoint's `lxm`. */\nexport const FOLLOWING_FEED_LXM = 'id.sifa.feed.getFollowingFeed';\n\n/** One app the viewer's network is active on, for the feed's source tabs. */\nexport interface FollowingFeedApp {\n /** Registry app id, e.g. `tangled`. Pass back as {@link FetchFollowingFeedOptions.app}. */\n id: string;\n name: string;\n /** Summed recent activity across the network; the tab ordering. */\n count: number;\n}\n\n/**\n * Why a following-feed page came back empty. Lets a client say something true\n * per case instead of one catch-all sentence, and point at the right next step.\n */\nexport type FollowingFeedEmptyReason =\n | 'no_follows'\n | 'no_visible_follows'\n | 'no_cross_app_activity'\n | 'no_recent_records'\n | 'all_hidden'\n | 'nothing_renderable'\n | 'hydration_failed';\n\n/** Options for {@link fetchFollowingFeed}. */\nexport interface FetchFollowingFeedOptions extends ApiFetchOptions {\n limit?: number;\n /**\n * Opt in to the viewer's Bluesky activity too. Off by default: the point of\n * the feed is what connections do on OTHER apps.\n *\n * Ignored when {@link app} is set, since a source tab selects one app.\n */\n includeBluesky?: boolean;\n /**\n * Restrict the page to one app (a registry id from the response's `apps`).\n * This is what a source tab selects. `app: 'bluesky'` selects Bluesky even\n * though it is excluded from the default mixed view.\n */\n app?: string;\n /** Forward a `Cookie` header on Next.js RSC server-side calls (web). */\n cookieHeader?: string;\n}\n\n/** The following feed's response: an activity feed plus its tab metadata. */\nexport interface FollowingFeedResponse extends ActivityFeedResponse {\n /**\n * Apps the viewer's network is actually active on, most active first.\n * Present on empty pages too, so a client's tabs survive a quiet tab.\n */\n apps?: FollowingFeedApp[];\n /** Set only when `items` is empty. */\n reason?: FollowingFeedEmptyReason;\n}\n\n/**\n * The viewer's cross-app following feed: what OTHER apps their connections use\n * (Tangled, WhiteWind, Smoke Signal, ...) — Bluesky is excluded server-side by\n * default, as it is the least interesting part and other apps already surface\n * it. Pass `includeBluesky: true` to bring it back in.\n *\n * Auth is identity-only server-side, so the NATIVE app supplies\n * `config.getAuthToken` to mint a service-auth Bearer, while WEB relies on its\n * session cookie (`credentials: 'include'`). Returns `null` on error. v1 is a\n * finite first page (no cursor yet).\n */\nexport async function fetchFollowingFeed(\n config: SifaApiConfig,\n opts: FetchFollowingFeedOptions = {},\n): Promise<FollowingFeedResponse | null> {\n const params = new URLSearchParams();\n if (opts.limit) params.set('limit', String(opts.limit));\n // A selected tab decides Bluesky on its own, so the flag is not also sent.\n if (opts.app) params.set('app', opts.app);\n else if (opts.includeBluesky) params.set('includeBluesky', 'true');\n const qs = params.toString();\n\n const headers: Record<string, string> = { ...(opts.headers ?? {}) };\n if (opts.cookieHeader) headers.cookie = opts.cookieHeader;\n if (config.getAuthToken) {\n const token = await config.getAuthToken(FOLLOWING_FEED_LXM);\n if (token) headers.Authorization = `Bearer ${token}`;\n }\n\n try {\n return await apiFetch<FollowingFeedResponse>(\n config,\n `/api/following/feed${qs ? `?${qs}` : ''}`,\n { credentials: 'include', cache: 'no-store', ...opts, headers },\n );\n } catch {\n return null;\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/query/fetchers/follow.ts"],"sourcesContent":["import {\n apiFetch,\n encodeIdentifier,\n apiWrite,\n type ApiFetchOptions,\n type SifaApiConfig,\n type WriteResult,\n} from '../client.js';\nimport type { ActivityFeedResponse } from './activity.js';\n\nexport interface FollowProfile {\n did: string;\n handle: string;\n displayName?: string;\n headline?: string;\n avatarUrl?: string;\n source: string;\n claimed: boolean;\n followedAt: string;\n blueskyVerified?: boolean;\n blueskyVerifiedAt?: string | null;\n}\n\nexport interface FollowingResponse {\n follows: FollowProfile[];\n cursor?: string;\n}\n\n/** People the authenticated user follows. Empty on error. */\nexport async function fetchFollowing(\n config: SifaApiConfig,\n opts: { source?: string; cursor?: string; limit?: number } & ApiFetchOptions = {},\n): Promise<FollowingResponse> {\n const params = new URLSearchParams();\n if (opts.source) params.set('source', opts.source);\n if (opts.cursor) params.set('cursor', opts.cursor);\n if (opts.limit) params.set('limit', String(opts.limit));\n const qs = params.toString();\n\n try {\n return await apiFetch<FollowingResponse>(config, `/api/following${qs ? `?${qs}` : ''}`, {\n credentials: 'include',\n cache: 'no-store',\n ...opts,\n });\n } catch {\n return { follows: [] };\n }\n}\n\n/**\n * Result of {@link followUser}. Extends {@link WriteResult} with the\n * follow `rkey` returned by sifa-api on success. Self-follow + invalid\n * handle surface as `success: false` with the server-provided message;\n * dup-follow is idempotent (sifa-api E7) and resolves as `success: true`.\n */\nexport interface FollowUserResult extends WriteResult {\n rkey?: string;\n /** DID of the followed subject (server-resolved from the handle). */\n subjectDid?: string;\n}\n\n/**\n * Create an `id.sifa.graph.follow` record on the caller's PDS via the\n * AppView. Idempotent on duplicate (server catches the unique-violation\n * and returns 200, per sifa-api#673 E7).\n */\nexport function followUser(\n config: SifaApiConfig,\n handle: string,\n opts: { note?: string } & Omit<ApiFetchOptions, 'method' | 'body'> = {},\n): Promise<FollowUserResult> {\n const { note, ...rest } = opts;\n return apiWrite<{ rkey?: string; subjectDid?: string }>(\n config,\n `/api/follow/${encodeIdentifier(handle)}`,\n 'POST',\n {\n body: note !== undefined ? { note } : undefined,\n ...rest,\n },\n );\n}\n\n/** Delete the authenticated viewer's `id.sifa.graph.follow` for `handle`. */\nexport function unfollowUser(\n config: SifaApiConfig,\n handle: string,\n opts: Omit<ApiFetchOptions, 'method' | 'body'> = {},\n): Promise<WriteResult> {\n return apiWrite(config, `/api/follow/${encodeIdentifier(handle)}`, 'DELETE', opts);\n}\n\nexport interface FollowListPage {\n follows: FollowProfile[];\n cursor: string | null;\n}\n\nexport interface FetchFollowListOptions extends ApiFetchOptions {\n cursor?: string;\n limit?: number;\n /**\n * Pass the caller's `Cookie` header on Next.js RSC server-side calls\n * (mirrors {@link FetchActivityFeedOptions}; required for authenticated\n * server fetches because `credentials: 'include'` does not propagate\n * cookies from RSC).\n */\n cookieHeader?: string;\n}\n\nfunction buildListPath(prefix: string, opts: FetchFollowListOptions): string {\n const params = new URLSearchParams();\n if (opts.cursor) params.set('cursor', opts.cursor);\n if (opts.limit) params.set('limit', String(opts.limit));\n const qs = params.toString();\n return `${prefix}${qs ? `?${qs}` : ''}`;\n}\n\n/**\n * Paginated list of `handle`'s followers. Returns an empty page on error\n * so the UI can render a graceful \"no followers yet\" state.\n */\nexport async function getFollowers(\n config: SifaApiConfig,\n handle: string,\n opts: FetchFollowListOptions = {},\n): Promise<FollowListPage> {\n const headers: Record<string, string> = { ...(opts.headers ?? {}) };\n if (opts.cookieHeader) headers.cookie = opts.cookieHeader;\n try {\n const res = await apiFetch<{ follows: FollowProfile[]; cursor?: string | null }>(\n config,\n buildListPath(`/api/profile/${encodeIdentifier(handle)}/followers`, opts),\n { credentials: 'include', cache: 'no-store', ...opts, headers },\n );\n return { follows: res.follows, cursor: res.cursor ?? null };\n } catch {\n return { follows: [], cursor: null };\n }\n}\n\n/** Paginated list of who `handle` follows. */\nexport async function getFollowing(\n config: SifaApiConfig,\n handle: string,\n opts: FetchFollowListOptions = {},\n): Promise<FollowListPage> {\n const headers: Record<string, string> = { ...(opts.headers ?? {}) };\n if (opts.cookieHeader) headers.cookie = opts.cookieHeader;\n try {\n const res = await apiFetch<{ follows: FollowProfile[]; cursor?: string | null }>(\n config,\n buildListPath(`/api/profile/${encodeIdentifier(handle)}/following`, opts),\n { credentials: 'include', cache: 'no-store', ...opts, headers },\n );\n return { follows: res.follows, cursor: res.cursor ?? null };\n } catch {\n return { follows: [], cursor: null };\n }\n}\n\n/** The method binding for the following-feed service-auth token; MUST match the\n * sifa-api endpoint's `lxm`. */\nexport const FOLLOWING_FEED_LXM = 'id.sifa.feed.getFollowingFeed';\n\n/** One app the viewer's network is active on, for the feed's source tabs. */\nexport interface FollowingFeedApp {\n /** Registry app id, e.g. `tangled`. Pass back as {@link FetchFollowingFeedOptions.app}. */\n id: string;\n name: string;\n /** Summed recent activity across the network; the tab ordering. */\n count: number;\n}\n\n/**\n * Why a following-feed page came back empty. Lets a client say something true\n * per case instead of one catch-all sentence, and point at the right next step.\n */\nexport type FollowingFeedEmptyReason =\n | 'no_follows'\n | 'no_visible_follows'\n | 'no_cross_app_activity'\n | 'no_recent_records'\n | 'all_hidden'\n | 'nothing_renderable'\n | 'hydration_failed'\n /** The feed is still being built. Nothing is wrong: ask again shortly. */\n | 'building';\n\n/** Options for {@link fetchFollowingFeed}. */\nexport interface FetchFollowingFeedOptions extends ApiFetchOptions {\n limit?: number;\n /**\n * Opt in to the viewer's Bluesky activity too. Off by default: the point of\n * the feed is what connections do on OTHER apps.\n *\n * Ignored when {@link app} is set, since a source tab selects one app.\n */\n includeBluesky?: boolean;\n /**\n * Restrict the page to one app (a registry id from the response's `apps`).\n * This is what a source tab selects. `app: 'bluesky'` selects Bluesky even\n * though it is excluded from the default mixed view.\n */\n app?: string;\n /** Forward a `Cookie` header on Next.js RSC server-side calls (web). */\n cookieHeader?: string;\n}\n\n/** The following feed's response: an activity feed plus its tab metadata. */\nexport interface FollowingFeedResponse extends ActivityFeedResponse {\n /**\n * Apps the viewer's network is actually active on, most active first.\n * Present on empty pages too, so a client's tabs survive a quiet tab.\n */\n apps?: FollowingFeedApp[];\n /** Set only when `items` is empty. */\n reason?: FollowingFeedEmptyReason;\n /** When this feed was built (ISO 8601). Absent on a `building` answer. */\n builtAt?: string;\n /**\n * True when this is an older build, served while a newer one is built in\n * the background. Poll {@link fetchFollowingFeedVersion} to learn when the\n * newer one is ready.\n */\n stale?: boolean;\n}\n\n/** Query string and auth headers shared by the feed and its version check. */\nasync function followingFeedRequest(config: SifaApiConfig, opts: FetchFollowingFeedOptions) {\n const params = new URLSearchParams();\n if (opts.limit) params.set('limit', String(opts.limit));\n // A selected tab decides Bluesky on its own, so the flag is not also sent.\n if (opts.app) params.set('app', opts.app);\n else if (opts.includeBluesky) params.set('includeBluesky', 'true');\n const qs = params.toString();\n\n const headers: Record<string, string> = { ...(opts.headers ?? {}) };\n if (opts.cookieHeader) headers.cookie = opts.cookieHeader;\n if (config.getAuthToken) {\n const token = await config.getAuthToken(FOLLOWING_FEED_LXM);\n if (token) headers.Authorization = `Bearer ${token}`;\n }\n return { query: qs ? `?${qs}` : '', headers };\n}\n\n/**\n * The viewer's cross-app following feed: what OTHER apps their connections use\n * (Tangled, WhiteWind, Smoke Signal, ...) — Bluesky is excluded server-side by\n * default, as it is the least interesting part and other apps already surface\n * it. Pass `includeBluesky: true` to bring it back in.\n *\n * Auth is identity-only server-side, so the NATIVE app supplies\n * `config.getAuthToken` to mint a service-auth Bearer, while WEB relies on its\n * session cookie (`credentials: 'include'`). Returns `null` on error. v1 is a\n * finite first page (no cursor yet).\n */\nexport async function fetchFollowingFeed(\n config: SifaApiConfig,\n opts: FetchFollowingFeedOptions = {},\n): Promise<FollowingFeedResponse | null> {\n const { query, headers } = await followingFeedRequest(config, opts);\n try {\n return await apiFetch<FollowingFeedResponse>(config, `/api/following/feed${query}`, {\n credentials: 'include',\n cache: 'no-store',\n ...opts,\n headers,\n });\n } catch {\n return null;\n }\n}\n\n/** When the cached following feed for a query was built. */\nexport interface FollowingFeedVersion {\n /** ISO 8601, or null when nothing is cached for this query. */\n builtAt: string | null;\n}\n\n/**\n * When the cached following feed for the same query was built. Cheap: it never\n * builds a feed. A client showing a `stale` feed polls this and offers the\n * newer one once {@link isNewerFollowingFeed} says so. Returns `null` on error.\n */\nexport async function fetchFollowingFeedVersion(\n config: SifaApiConfig,\n opts: FetchFollowingFeedOptions = {},\n): Promise<FollowingFeedVersion | null> {\n const { query, headers } = await followingFeedRequest(config, opts);\n try {\n return await apiFetch<FollowingFeedVersion>(config, `/api/following/feed/version${query}`, {\n credentials: 'include',\n cache: 'no-store',\n ...opts,\n headers,\n });\n } catch {\n return null;\n }\n}\n\n/** True when `latestBuiltAt` is a newer build than the one shown (`shownBuiltAt`). */\nexport function isNewerFollowingFeed(\n shownBuiltAt: string | null | undefined,\n latestBuiltAt: string | null | undefined,\n): boolean {\n if (!shownBuiltAt || !latestBuiltAt) return false;\n return Date.parse(latestBuiltAt) > Date.parse(shownBuiltAt);\n}\n"],"mappings":";AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AAsBP,eAAsB,eACpB,QACA,OAA+E,CAAC,GACpD;AAC5B,QAAM,SAAS,IAAI,gBAAgB;AACnC,MAAI,KAAK,OAAQ,QAAO,IAAI,UAAU,KAAK,MAAM;AACjD,MAAI,KAAK,OAAQ,QAAO,IAAI,UAAU,KAAK,MAAM;AACjD,MAAI,KAAK,MAAO,QAAO,IAAI,SAAS,OAAO,KAAK,KAAK,CAAC;AACtD,QAAM,KAAK,OAAO,SAAS;AAE3B,MAAI;AACF,WAAO,MAAM,SAA4B,QAAQ,iBAAiB,KAAK,IAAI,EAAE,KAAK,EAAE,IAAI;AAAA,MACtF,aAAa;AAAA,MACb,OAAO;AAAA,MACP,GAAG;AAAA,IACL,CAAC;AAAA,EACH,QAAQ;AACN,WAAO,EAAE,SAAS,CAAC,EAAE;AAAA,EACvB;AACF;AAmBO,SAAS,WACd,QACA,QACA,OAAqE,CAAC,GAC3C;AAC3B,QAAM,EAAE,MAAM,GAAG,KAAK,IAAI;AAC1B,SAAO;AAAA,IACL;AAAA,IACA,eAAe,iBAAiB,MAAM,CAAC;AAAA,IACvC;AAAA,IACA;AAAA,MACE,MAAM,SAAS,SAAY,EAAE,KAAK,IAAI;AAAA,MACtC,GAAG;AAAA,IACL;AAAA,EACF;AACF;AAGO,SAAS,aACd,QACA,QACA,OAAiD,CAAC,GAC5B;AACtB,SAAO,SAAS,QAAQ,eAAe,iBAAiB,MAAM,CAAC,IAAI,UAAU,IAAI;AACnF;AAmBA,SAAS,cAAc,QAAgB,MAAsC;AAC3E,QAAM,SAAS,IAAI,gBAAgB;AACnC,MAAI,KAAK,OAAQ,QAAO,IAAI,UAAU,KAAK,MAAM;AACjD,MAAI,KAAK,MAAO,QAAO,IAAI,SAAS,OAAO,KAAK,KAAK,CAAC;AACtD,QAAM,KAAK,OAAO,SAAS;AAC3B,SAAO,GAAG,MAAM,GAAG,KAAK,IAAI,EAAE,KAAK,EAAE;AACvC;AAMA,eAAsB,aACpB,QACA,QACA,OAA+B,CAAC,GACP;AACzB,QAAM,UAAkC,EAAE,GAAI,KAAK,WAAW,CAAC,EAAG;AAClE,MAAI,KAAK,aAAc,SAAQ,SAAS,KAAK;AAC7C,MAAI;AACF,UAAM,MAAM,MAAM;AAAA,MAChB;AAAA,MACA,cAAc,gBAAgB,iBAAiB,MAAM,CAAC,cAAc,IAAI;AAAA,MACxE,EAAE,aAAa,WAAW,OAAO,YAAY,GAAG,MAAM,QAAQ;AAAA,IAChE;AACA,WAAO,EAAE,SAAS,IAAI,SAAS,QAAQ,IAAI,UAAU,KAAK;AAAA,EAC5D,QAAQ;AACN,WAAO,EAAE,SAAS,CAAC,GAAG,QAAQ,KAAK;AAAA,EACrC;AACF;AAGA,eAAsB,aACpB,QACA,QACA,OAA+B,CAAC,GACP;AACzB,QAAM,UAAkC,EAAE,GAAI,KAAK,WAAW,CAAC,EAAG;AAClE,MAAI,KAAK,aAAc,SAAQ,SAAS,KAAK;AAC7C,MAAI;AACF,UAAM,MAAM,MAAM;AAAA,MAChB;AAAA,MACA,cAAc,gBAAgB,iBAAiB,MAAM,CAAC,cAAc,IAAI;AAAA,MACxE,EAAE,aAAa,WAAW,OAAO,YAAY,GAAG,MAAM,QAAQ;AAAA,IAChE;AACA,WAAO,EAAE,SAAS,IAAI,SAAS,QAAQ,IAAI,UAAU,KAAK;AAAA,EAC5D,QAAQ;AACN,WAAO,EAAE,SAAS,CAAC,GAAG,QAAQ,KAAK;AAAA,EACrC;AACF;AAIO,IAAM,qBAAqB;AAkElC,eAAe,qBAAqB,QAAuB,MAAiC;AAC1F,QAAM,SAAS,IAAI,gBAAgB;AACnC,MAAI,KAAK,MAAO,QAAO,IAAI,SAAS,OAAO,KAAK,KAAK,CAAC;AAEtD,MAAI,KAAK,IAAK,QAAO,IAAI,OAAO,KAAK,GAAG;AAAA,WAC/B,KAAK,eAAgB,QAAO,IAAI,kBAAkB,MAAM;AACjE,QAAM,KAAK,OAAO,SAAS;AAE3B,QAAM,UAAkC,EAAE,GAAI,KAAK,WAAW,CAAC,EAAG;AAClE,MAAI,KAAK,aAAc,SAAQ,SAAS,KAAK;AAC7C,MAAI,OAAO,cAAc;AACvB,UAAM,QAAQ,MAAM,OAAO,aAAa,kBAAkB;AAC1D,QAAI,MAAO,SAAQ,gBAAgB,UAAU,KAAK;AAAA,EACpD;AACA,SAAO,EAAE,OAAO,KAAK,IAAI,EAAE,KAAK,IAAI,QAAQ;AAC9C;AAaA,eAAsB,mBACpB,QACA,OAAkC,CAAC,GACI;AACvC,QAAM,EAAE,OAAO,QAAQ,IAAI,MAAM,qBAAqB,QAAQ,IAAI;AAClE,MAAI;AACF,WAAO,MAAM,SAAgC,QAAQ,sBAAsB,KAAK,IAAI;AAAA,MAClF,aAAa;AAAA,MACb,OAAO;AAAA,MACP,GAAG;AAAA,MACH;AAAA,IACF,CAAC;AAAA,EACH,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAaA,eAAsB,0BACpB,QACA,OAAkC,CAAC,GACG;AACtC,QAAM,EAAE,OAAO,QAAQ,IAAI,MAAM,qBAAqB,QAAQ,IAAI;AAClE,MAAI;AACF,WAAO,MAAM,SAA+B,QAAQ,8BAA8B,KAAK,IAAI;AAAA,MACzF,aAAa;AAAA,MACb,OAAO;AAAA,MACP,GAAG;AAAA,MACH;AAAA,IACF,CAAC;AAAA,EACH,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGO,SAAS,qBACd,cACA,eACS;AACT,MAAI,CAAC,gBAAgB,CAAC,cAAe,QAAO;AAC5C,SAAO,KAAK,MAAM,aAAa,IAAI,KAAK,MAAM,YAAY;AAC5D;","names":[]}
|
|
@@ -1063,7 +1063,7 @@ async function getFollowing(config, handle, opts = {}) {
|
|
|
1063
1063
|
}
|
|
1064
1064
|
}
|
|
1065
1065
|
var FOLLOWING_FEED_LXM = "id.sifa.feed.getFollowingFeed";
|
|
1066
|
-
async function
|
|
1066
|
+
async function followingFeedRequest(config, opts) {
|
|
1067
1067
|
const params = new URLSearchParams();
|
|
1068
1068
|
if (opts.limit) params.set("limit", String(opts.limit));
|
|
1069
1069
|
if (opts.app) params.set("app", opts.app);
|
|
@@ -1075,16 +1075,38 @@ async function fetchFollowingFeed(config, opts = {}) {
|
|
|
1075
1075
|
const token = await config.getAuthToken(FOLLOWING_FEED_LXM);
|
|
1076
1076
|
if (token) headers.Authorization = `Bearer ${token}`;
|
|
1077
1077
|
}
|
|
1078
|
+
return { query: qs ? `?${qs}` : "", headers };
|
|
1079
|
+
}
|
|
1080
|
+
async function fetchFollowingFeed(config, opts = {}) {
|
|
1081
|
+
const { query, headers } = await followingFeedRequest(config, opts);
|
|
1078
1082
|
try {
|
|
1079
|
-
return await apiFetch(
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1083
|
+
return await apiFetch(config, `/api/following/feed${query}`, {
|
|
1084
|
+
credentials: "include",
|
|
1085
|
+
cache: "no-store",
|
|
1086
|
+
...opts,
|
|
1087
|
+
headers
|
|
1088
|
+
});
|
|
1084
1089
|
} catch {
|
|
1085
1090
|
return null;
|
|
1086
1091
|
}
|
|
1087
1092
|
}
|
|
1093
|
+
async function fetchFollowingFeedVersion(config, opts = {}) {
|
|
1094
|
+
const { query, headers } = await followingFeedRequest(config, opts);
|
|
1095
|
+
try {
|
|
1096
|
+
return await apiFetch(config, `/api/following/feed/version${query}`, {
|
|
1097
|
+
credentials: "include",
|
|
1098
|
+
cache: "no-store",
|
|
1099
|
+
...opts,
|
|
1100
|
+
headers
|
|
1101
|
+
});
|
|
1102
|
+
} catch {
|
|
1103
|
+
return null;
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
function isNewerFollowingFeed(shownBuiltAt, latestBuiltAt) {
|
|
1107
|
+
if (!shownBuiltAt || !latestBuiltAt) return false;
|
|
1108
|
+
return Date.parse(latestBuiltAt) > Date.parse(shownBuiltAt);
|
|
1109
|
+
}
|
|
1088
1110
|
|
|
1089
1111
|
// src/query/fetchers/follow-extras.ts
|
|
1090
1112
|
function buildListPath2(prefix, opts) {
|
|
@@ -1816,6 +1838,7 @@ var sifaQueryKeys = {
|
|
|
1816
1838
|
followers: (handle) => ["sifa", "follow", "followers", handle],
|
|
1817
1839
|
followingOf: (handle) => ["sifa", "follow", "following-of", handle],
|
|
1818
1840
|
feed: (opts) => ["sifa", "follow", "feed", opts],
|
|
1841
|
+
feedVersion: (opts) => ["sifa", "follow", "feed-version", opts],
|
|
1819
1842
|
mutuals: (handle) => ["sifa", "follow", "mutuals", handle],
|
|
1820
1843
|
blueskySuggestions: () => ["sifa", "follow", "bluesky-suggestions"]
|
|
1821
1844
|
},
|
|
@@ -2101,6 +2124,7 @@ exports.fetchExternalAccounts = fetchExternalAccounts;
|
|
|
2101
2124
|
exports.fetchFeaturedProfile = fetchFeaturedProfile;
|
|
2102
2125
|
exports.fetchFollowing = fetchFollowing;
|
|
2103
2126
|
exports.fetchFollowingFeed = fetchFollowingFeed;
|
|
2127
|
+
exports.fetchFollowingFeedVersion = fetchFollowingFeedVersion;
|
|
2104
2128
|
exports.fetchGetProfileView = fetchGetProfileView;
|
|
2105
2129
|
exports.fetchGivenConfirmations = fetchGivenConfirmations;
|
|
2106
2130
|
exports.fetchHeatmapData = fetchHeatmapData;
|
|
@@ -2149,6 +2173,7 @@ exports.hideStandardPublication = hideStandardPublication;
|
|
|
2149
2173
|
exports.importSearchEntities = importSearchEntities;
|
|
2150
2174
|
exports.initiateNetworkMapGeneration = initiateNetworkMapGeneration;
|
|
2151
2175
|
exports.isNetworkMapResponse = isNetworkMapResponse;
|
|
2176
|
+
exports.isNewerFollowingFeed = isNewerFollowingFeed;
|
|
2152
2177
|
exports.linkSkillToPosition = linkSkillToPosition;
|
|
2153
2178
|
exports.listFeatureAllowlist = listFeatureAllowlist;
|
|
2154
2179
|
exports.refreshOrcidPublications = refreshOrcidPublications;
|