From f291273a0fcdb5b7acbec26ef6381aa44e95e0dc Mon Sep 17 00:00:00 2001 From: Jana Naumoska Date: Tue, 19 May 2026 04:26:28 +0200 Subject: [PATCH 1/2] Add get or create follow and unfollow endpoints and fix generate command --- generate-openapi.sh | 4 +- .../feeds-client/src/gen/feeds/FeedsApi.ts | 61 +++++++++++++++++++ .../src/gen/model-decoders/decoders.ts | 14 +++++ packages/feeds-client/src/gen/models/index.ts | 54 ++++++++++++++++ 4 files changed, 131 insertions(+), 2 deletions(-) diff --git a/generate-openapi.sh b/generate-openapi.sh index 82842a4c..0018fd09 100755 --- a/generate-openapi.sh +++ b/generate-openapi.sh @@ -6,6 +6,6 @@ CHAT_DIR="../chat" rm -rf $OUTPUT_DIR -( cd $CHAT_DIR ; make openapi ; go run ./cmd/chat-manager openapi generate-client --language ts --spec ./releases/v2/feeds-clientside-api.yaml --output $OUTPUT_DIR ) +( cd $CHAT_DIR ; make openapi ; ./build/chat-manager openapi generate-client --language ts --spec ./releases/v2/feeds-clientside-api.yaml --output $OUTPUT_DIR ) -yarn lint:gen \ No newline at end of file +yarn lint:gen diff --git a/packages/feeds-client/src/gen/feeds/FeedsApi.ts b/packages/feeds-client/src/gen/feeds/FeedsApi.ts index c9f1f05b..12d5cf95 100644 --- a/packages/feeds-client/src/gen/feeds/FeedsApi.ts +++ b/packages/feeds-client/src/gen/feeds/FeedsApi.ts @@ -66,6 +66,9 @@ import type { GetOGResponse, GetOrCreateFeedRequest, GetOrCreateFeedResponse, + GetOrCreateFollowResponse, + GetOrCreateUnfollowRequest, + GetOrCreateUnfollowResponse, GetUserGroupResponse, ImageUploadRequest, ImageUploadResponse, @@ -2246,6 +2249,37 @@ export class FeedsApi { return { ...response.body, metadata: response.metadata }; } + async getOrCreateFollow( + request: FollowRequest, + ): Promise> { + const body = { + source: request?.source, + target: request?.target, + activity_copy_limit: request?.activity_copy_limit, + copy_custom_to_notification: request?.copy_custom_to_notification, + create_notification_activity: request?.create_notification_activity, + enrich_own_fields: request?.enrich_own_fields, + push_preference: request?.push_preference, + skip_push: request?.skip_push, + custom: request?.custom, + }; + + const response = await this.apiClient.sendRequest< + StreamResponse + >( + 'POST', + '/api/v2/feeds/follows/upsert', + undefined, + undefined, + body, + 'application/json', + ); + + decoders.GetOrCreateFollowResponse?.(response.body); + + return { ...response.body, metadata: response.metadata }; + } + async unfollow(request: { source: string; target: string; @@ -2302,6 +2336,33 @@ export class FeedsApi { return { ...response.body, metadata: response.metadata }; } + async getOrCreateUnfollow( + request: GetOrCreateUnfollowRequest, + ): Promise> { + const body = { + source: request?.source, + target: request?.target, + delete_notification_activity: request?.delete_notification_activity, + enrich_own_fields: request?.enrich_own_fields, + keep_history: request?.keep_history, + }; + + const response = await this.apiClient.sendRequest< + StreamResponse + >( + 'POST', + '/api/v2/feeds/unfollow/upsert', + undefined, + undefined, + body, + 'application/json', + ); + + decoders.GetOrCreateUnfollowResponse?.(response.body); + + return { ...response.body, metadata: response.metadata }; + } + async createGuest( request: CreateGuestRequest, ): Promise> { diff --git a/packages/feeds-client/src/gen/model-decoders/decoders.ts b/packages/feeds-client/src/gen/model-decoders/decoders.ts index f97d1a55..3c1d5e3c 100644 --- a/packages/feeds-client/src/gen/model-decoders/decoders.ts +++ b/packages/feeds-client/src/gen/model-decoders/decoders.ts @@ -1390,6 +1390,20 @@ decoders.GetOrCreateFeedResponse = (input?: Record) => { return decode(typeMappings, input); }; +decoders.GetOrCreateFollowResponse = (input?: Record) => { + const typeMappings: TypeMapping = { + follow: { type: 'FollowResponse', isSingle: true }, + }; + return decode(typeMappings, input); +}; + +decoders.GetOrCreateUnfollowResponse = (input?: Record) => { + const typeMappings: TypeMapping = { + follow: { type: 'FollowResponse', isSingle: true }, + }; + return decode(typeMappings, input); +}; + decoders.GetUserGroupResponse = (input?: Record) => { const typeMappings: TypeMapping = { user_group: { type: 'UserGroupResponse', isSingle: true }, diff --git a/packages/feeds-client/src/gen/models/index.ts b/packages/feeds-client/src/gen/models/index.ts index 8c51726d..6f7c8a69 100644 --- a/packages/feeds-client/src/gen/models/index.ts +++ b/packages/feeds-client/src/gen/models/index.ts @@ -5837,6 +5837,60 @@ export interface GetOrCreateFeedResponse { notification_status?: NotificationStatusResponse; } +export interface GetOrCreateFollowResponse { + /** + * True if the follow was newly created by this request; false if it already existed + */ + created: boolean; + + duration: string; + + follow: FollowResponse; + + /** + * Whether a notification activity was successfully created (only set when the follow was newly created) + */ + notification_created?: boolean; +} + +export interface GetOrCreateUnfollowRequest { + /** + * Fully qualified ID of the source feed + */ + source: string; + + /** + * Fully qualified ID of the target feed + */ + target: string; + + /** + * Whether to delete the corresponding notification activity (default: false) + */ + delete_notification_activity?: boolean; + + /** + * If true, enriches the follow's source_feed and target_feed with own_* fields (own_follows, own_followings, own_capabilities, own_membership). Defaults to false for performance. + */ + enrich_own_fields?: boolean; + + /** + * When true, activities from the unfollowed feed will remain in the source feed's timeline (default: false) + */ + keep_history?: boolean; +} + +export interface GetOrCreateUnfollowResponse { + /** + * True if a follow was found and removed by this request; false if no follow existed + */ + deleted: boolean; + + duration: string; + + follow?: FollowResponse; +} + export interface GetUserGroupResponse { duration: string; From c2d26469ea5fc6d741d8c7513d2e70a1c7336b59 Mon Sep 17 00:00:00 2001 From: Zita Szupera Date: Tue, 19 May 2026 07:51:20 -0500 Subject: [PATCH 2/2] add state update from getOrCreateFollow --- .../feeds-client/src/feeds-client/feeds-client.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/feeds-client/src/feeds-client/feeds-client.ts b/packages/feeds-client/src/feeds-client/feeds-client.ts index 0fbd0a62..643bc9fa 100644 --- a/packages/feeds-client/src/feeds-client/feeds-client.ts +++ b/packages/feeds-client/src/feeds-client/feeds-client.ts @@ -1170,6 +1170,21 @@ export class FeedsClient extends FeedsApi { return response; } + async getOrCreateFollow(request: FollowRequest) { + const response = await super.getOrCreateFollow(request); + + this.updateStateFromFollows([response.follow], !!request.enrich_own_fields); + this.checkIfOwnFieldsChanged( + response.follow.source_feed, + !!request.enrich_own_fields, + ); + this.checkIfOwnFieldsChanged( + response.follow.target_feed, + !!request.enrich_own_fields, + ); + return response; + } + async unfollow(request: { source: string; target: string;