Skip to content

Commit 6da7032

Browse files
authored
Merge branch 'main' into zoranmiladinoski/feeds-1117-support-restoring-soft-deleted-activities
2 parents dd82b5c + 27f61f0 commit 6da7032

File tree

296 files changed

+6638
-5705
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

296 files changed

+6638
-5705
lines changed

AGENTS.md

Lines changed: 48 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,21 @@ Agents should prioritize backwards compatibility, API stability, and high test c
2121
### Project layout (monorepo)
2222

2323
packages/
24-
feeds-client/ # Core Feeds API client
25-
src/
26-
common/ # Common utilities (API client, state management, real-time)
27-
feed/ # Feed management and event handlers
28-
feeds-client/ # Main FeedsClient class
29-
gen/ # Generated API clients and models
30-
utils/ # Utility functions
31-
types.ts # Type definitions
32-
@react-bindings/ # React hooks and contexts
33-
react-sdk/ # React SDK wrapper
34-
react-native-sdk/ # React Native SDK wrapper
24+
feeds-client/ # Core Feeds API client
25+
src/
26+
activity-with-state-updates/ # Activity state management
27+
bindings/ # Framework bindings
28+
common/ # Common utilities (API client, state management, real-time)
29+
feed/ # Feed management and event handlers
30+
feeds-client/ # Main FeedsClient class
31+
gen/ # Generated API clients and models
32+
utils/ # Utility functions
33+
react-sdk/ # React SDK wrapper with hooks and contexts
34+
react-native-sdk/ # React Native SDK wrapper
3535
sample-apps/
36-
react-sample-app/ # Next.js sample application for React
37-
react-native/ # React Native sample application
36+
react-demo/ # Next.js demo application (stream-feeds-react-demo)
37+
react-sample-app/ # Next.js sample application (facebook-clone)
38+
react-native/ # React Native sample application (ExpoTikTokApp)
3839

3940
Use the closest folder's patterns and conventions when editing.
4041

@@ -148,11 +149,11 @@ Commit / PR conventions
148149
Testing policy
149150
• Add/extend tests in each package's test directories with .test.ts suffix.
150151
• Cover:
151-
• Core FeedsClient and Feed classes
152-
• Event handlers and state management - see ai-docs/ai-state-management for details
153-
• React hooks and contexts (@react-bindings)
154-
• Utility functions (token creation, rate limiting, search)
155-
• Generated API clients and their interactions
152+
• Core FeedsClient and Feed classes
153+
• Event handlers and state management - see ai-docs/ai-state-management for details
154+
• React hooks and contexts (react-sdk, react-native-sdk)
155+
• Utility functions (token creation, rate limiting, search)
156+
• Generated API clients and their interactions
156157
• Integration tests are in `__integration-tests__/` directories
157158

158159
Security & credentials
@@ -184,3 +185,32 @@ Quick agent checklist (per commit)
184185
• Test affected packages individually if needed
185186

186187
End of machine guidance. Edit this file to refine agent behavior over time; keep human-facing details in README.md and docs.
188+
189+
## React Demo app
190+
191+
### Purpose
192+
193+
This is a React demo application showcasing the Stream Feeds SDK. Both source code quality and visual design should be excellent—this app serves as a reference implementation.
194+
195+
### UI Framework
196+
197+
This project uses **Tailwind CSS** with **daisyUI** for styling.
198+
199+
#### daisyUI Setup for Cursor
200+
201+
To get accurate daisyUI code generation, use one of these methods:
202+
203+
**Quick use in chat:**
204+
```
205+
@web https://daisyui.com/llms.txt
206+
```
207+
208+
### Stream Feeds SDK Documentation
209+
210+
If something is not clear, ask for a documentation link
211+
212+
### Quality Standards
213+
214+
- **Source code**: Clean, well-structured, following React best practices
215+
- **Design**: Modern, polished UI using daisyUI components effectively
216+
- **Both must be excellent**—this is a showcase application

CLAUDE.md

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Build Commands
6+
7+
```bash
8+
# Install dependencies (run from repository root)
9+
yarn
10+
11+
# Build all packages
12+
yarn build:all
13+
14+
# Build specific packages
15+
yarn build:client # Build feeds-client only
16+
yarn build:react-sdk # Build React SDK only
17+
yarn build:react-native-sdk # Build React Native SDK only
18+
19+
# Development mode with watch (in packages/feeds-client)
20+
yarn start
21+
```
22+
23+
## Testing
24+
25+
```bash
26+
# Run all tests
27+
yarn test:ci:all
28+
29+
# Run tests for library packages only (no sample apps)
30+
yarn test:ci:libs
31+
32+
# Run tests for feeds-client (in packages/feeds-client)
33+
yarn test # Run all tests with vitest
34+
yarn test:unit # Run unit tests only (excludes integration tests)
35+
yarn test <pattern> # Run specific test file, e.g., yarn test feed.test
36+
37+
# Run a single test file
38+
yarn vitest run path/to/test.test.ts
39+
40+
# Integration tests require environment variables:
41+
# VITE_STREAM_API_KEY and VITE_STREAM_API_SECRET (see __integration-tests__/utils.ts)
42+
```
43+
44+
## Linting
45+
46+
```bash
47+
yarn lint:all # Lint all TypeScript files
48+
yarn lint:all:fix # Lint and auto-fix
49+
```
50+
51+
## Verification After Changes
52+
53+
**IMPORTANT**: After making code changes, always verify the build and lint status:
54+
55+
```bash
56+
yarn build:all # Ensure all packages build successfully
57+
yarn lint:all # Check for linting errors
58+
```
59+
60+
These commands should be run from the repository root before considering changes complete.
61+
62+
## Code Generation
63+
64+
```bash
65+
yarn generate # Regenerate OpenAPI types (runs generate-openapi.sh)
66+
yarn lint:gen # Lint and format generated code
67+
```
68+
69+
## Architecture
70+
71+
This is a Yarn 4 monorepo with three main packages and sample applications.
72+
73+
### Package Hierarchy
74+
75+
```
76+
@stream-io/feeds-client (packages/feeds-client)
77+
└── @stream-io/feeds-react-sdk (packages/react-sdk) - re-exports feeds-client
78+
└── @stream-io/feeds-react-native-sdk (packages/react-native-sdk) - re-exports feeds-client
79+
```
80+
81+
### feeds-client Structure
82+
83+
The core SDK with two entry points:
84+
- Main entry (`index.ts`): `FeedsClient`, `Feed`, state management, types
85+
- React bindings entry (`/react-bindings`): hooks, contexts, wrapper components
86+
87+
Key classes:
88+
- **FeedsClient** (`src/feeds-client/feeds-client.ts`): Main client for API communication, WebSocket connections, and state management. Extends auto-generated `FeedsApi`.
89+
- **Feed** (`src/feed/feed.ts`): Represents a single feed with its state. Extends auto-generated `FeedApi`.
90+
- **StateStore**: From `@stream-io/state-store`, manages reactive state for both client and feeds.
91+
92+
### Generated Code
93+
94+
`src/gen/` contains OpenAPI-generated code:
95+
- `models/`: API request/response types
96+
- `feeds/`: `FeedsApi` and `FeedApi` base classes
97+
- `model-decoders/`: WebSocket event decoders
98+
99+
### React Bindings
100+
101+
Located in `src/bindings/react/`:
102+
- **Contexts**: `StreamFeedsContext`, `StreamFeedContext`, `StreamActivityWithStateUpdatesContext`, `StreamSearchContext`
103+
- **Hooks**: `useCreateFeedsClient`, client/feed/search state hooks
104+
- **Wrappers**: `StreamFeeds`, `StreamFeed`, `StreamActivityWithStateUpdates`, `StreamSearch`
105+
106+
### Event Handling
107+
108+
WebSocket events are processed through handlers in `src/feed/event-handlers/`. Each event type (activity, comment, follow, bookmark, etc.) has dedicated handler files that update the appropriate state stores.
109+
110+
### Sample Apps
111+
112+
- `sample-apps/react-demo`: Next.js demo app with stories feature with DaisyUI and Tailwind
113+
- `sample-apps/react-sample-app`: Advanced Next.js example
114+
- `sample-apps/react-native/ExpoTikTokApp`: Expo React Native example
115+
116+
## Key Patterns
117+
118+
- State management uses `@stream-io/state-store` with React bindings via `useSyncExternalStore`
119+
- API types are generated from OpenAPI spec - don't manually edit files in `src/gen/`
120+
- Integration tests in `__integration-tests__/` require Stream API credentials
121+
- Tests use vitest; configuration is in `vite.config.ts`

README.md

Lines changed: 66 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,7 @@ Here are some of the features we support:
4040
- **Search & queries**: Activity search, **query activities**, and **query feeds** endpoints.
4141
- **Modern essentials**: Permissions • OpenAPI spec • GDPR endpoints • realtime WebSocket events • push notifications • “own capabilities” API.
4242

43-
## React sample apps
44-
45-
### React demo app with stories
43+
## React demo app
4644

4745
Deployed version: https://feeds-react-demo.vercel.app
4846

@@ -80,27 +78,80 @@ After the above steps run the following command in `sample-apps/react-demo`:
8078
yarn dev
8179
```
8280

83-
### Advanced React app
81+
## Test Data Generator
8482

85-
Prerequisites:
83+
The `test-data-generator` directory contains scripts to populate your Stream Feeds app with sample data for testing and development purposes.
8684

87-
- Install dependencies: `yarn`
88-
- Build React SDK: `yarn build:client` and `yarn build:react-sdk`
89-
- Create a `.env` file in `sample-apps/react-sample-app` with the following content:
85+
### Setup
86+
87+
1. Create a `.env` file in `test-data-generator/` with your credentials:
9088

9189
```
92-
NEXT_PUBLIC_STREAM_API_KEY=<Your API key>
93-
NEXT_API_SECRET=<Your API secret>
94-
NEXT_PUBLIC_API_URL=<Optionally provide an API URL>
90+
STREAM_API_KEY=<Stream API key>
91+
API_SECRET=<Stream API secret>
92+
API_URL=<Optional, Stream API URL>
9593
```
9694

97-
- Run the `node setup-env.js` script in `sample-apps/react-sample-app`
98-
- If you want to have some pre-made posts in your app, optinally run the `node create-posts.js` script as well
95+
2. Install dependencies: `yarn` (from the repository root)
96+
97+
### Available Scripts
9998

100-
After the above steps run the following command in `sample-apps/react-sample-app`:
99+
Run these commands from the `test-data-generator/` directory:
101100

101+
| Script | Command | Description |
102+
| --------------- | ---------------------- | ------------------------------------------ |
103+
| Create Users | `yarn create-users` | Creates users and their feeds |
104+
| Create Follows | `yarn create-follows` | Sets up follow relationships between users |
105+
| Create Posts | `yarn create-posts` | Generates sample activities/posts |
106+
| Create Stories | `yarn create-stories` | Creates sample stories |
107+
| Download Images | `yarn download-images` | Downloads sample images for posts |
108+
109+
### Create Posts Feature Flags
110+
111+
The `create-posts` script supports a `--features` flag to control which features are included in the generated posts:
112+
113+
```bash
114+
yarn create-posts --features <feature1,feature2,...>
102115
```
103-
yarn dev
116+
117+
**Available features:**
118+
119+
| Feature | Description |
120+
| ------------ | ---------------------------------------- |
121+
| `link` | Adds random URLs to posts |
122+
| `attachment` | Uploads and attaches 1-3 images to posts |
123+
| `mention` | Adds @mentions to other users |
124+
| `poll` | Creates and attaches polls to posts |
125+
| `reaction` | Adds 1-5 reactions from random users |
126+
| `comment` | Adds 1-5 comments from random users |
127+
| `bookmark` | Bookmarks posts by random users |
128+
| `repost` | Creates reposts of existing activities |
129+
130+
**Examples:**
131+
132+
```bash
133+
# Create basic posts without any features
134+
yarn create-posts
135+
136+
# Create posts with polls and reactions
137+
yarn create-posts --features poll,reaction
138+
139+
# Create posts with all content features
140+
yarn create-posts --features link,attachment,mention,poll,reaction,comment,bookmark,repost
141+
```
142+
143+
> Note: Each feature has a probability of being included (not every post will have every enabled feature). Link and attachment are mutually exclusive per post.
144+
145+
### Usage
146+
147+
Typical order of operations:
148+
149+
```bash
150+
cd test-data-generator
151+
yarn create-users
152+
yarn create-follows
153+
yarn create-posts --features link,attachment,mention,poll,reaction,comment,bookmark,repost
154+
yarn create-stories
104155
```
105156

106157
## Local Setup

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
"license": "See license in LICENSE",
88
"workspaces": [
99
"packages/*",
10-
"sample-apps/**"
10+
"sample-apps/**",
11+
"test-data-generator"
1112
],
1213
"scripts": {
1314
"build:all": "yarn workspaces foreach -Avp --topological-dev run build",

packages/feeds-client/__integration-tests__/activity-websocket-events.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ describe('Activity state updates via WebSocket events', () => {
164164
text: 'Test activity',
165165
});
166166

167-
await waitForEvent(feed, 'feeds.activity.added', { timeoutMs: 1000 });
167+
await waitForEvent(feed, 'feeds.activity.added', { timeoutMs: 10000 });
168168

169169
expect(
170170
feed.state

packages/feeds-client/__integration-tests__/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ export const waitForEvent = (
6464
client: FeedsClient | Feed,
6565
type: FeedsEvent['type'] | WSEvent['type'],
6666
{
67-
timeoutMs = 3000,
67+
timeoutMs = 10000,
6868
shouldReject = false,
6969
}: {
7070
timeoutMs?: number;
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { createContext, useContext } from 'react';
2+
3+
import type { ActivityWithStateUpdates } from '../../../activity-with-state-updates/activity-with-state-updates';
4+
5+
export const StreamActivityWithStateUpdatesContext = createContext<ActivityWithStateUpdates | undefined>(undefined);
6+
7+
/**
8+
* The props for the StreamActivityWithStateUpdatesProvider component.
9+
*/
10+
export type StreamActivityWithStateUpdatesContextProps = {
11+
activityWithStateUpdates: ActivityWithStateUpdates;
12+
};
13+
14+
/**
15+
* Hook to access the nearest ActivityWithStateUpdates instance.
16+
*/
17+
export const useActivityWithStateUpdatesContext = () => {
18+
return useContext(StreamActivityWithStateUpdatesContext);
19+
};

packages/feeds-client/src/bindings/react/hooks/feed-state-hooks/useActivityComments.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { checkHasAnotherPage } from '../../../../utils';
77
import type { Feed, FeedState } from '../../../../feed';
88
import type { ActivityState, ActivityWithStateUpdates } from '../../../../activity-with-state-updates/activity-with-state-updates';
99
import type { ActivityResponse, CommentResponse } from '../../../../gen/models';
10+
import { useActivityWithStateUpdatesContext } from '../../contexts/StreamActivityWithStateUpdatesContext';
1011

1112
const canLoadComments = (
1213
feedOrActivity: Feed | ActivityResponse | ActivityWithStateUpdates,
@@ -36,15 +37,17 @@ type UseCommentsReturnType<T extends ActivityResponse | CommentResponse> = {
3637
export function useActivityComments({
3738
feed: feedFromProps,
3839
parentComment,
39-
activity,
40+
activity: activityFromProps,
4041
}: {
4142
feed?: Feed;
4243
parentComment?: CommentResponse;
4344
activity?: ActivityResponse | ActivityWithStateUpdates;
44-
}) {
45+
} = {}) {
4546
const feedFromContext = useFeedContext();
4647
const feed = feedFromProps ?? feedFromContext;
47-
const feedOrActivity = feed ?? activity;
48+
const activityFromContext = useActivityWithStateUpdatesContext();
49+
const activity = activityFromProps ?? activityFromContext;
50+
const feedOrActivity = (activity && canLoadComments(activity)) ? activity : feed;
4851

4952
if (!feedOrActivity) {
5053
throw new Error('Feed or activity is required');

packages/feeds-client/src/bindings/react/hooks/useCreateFeedsClient.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export const useCreateFeedsClient = ({
4747

4848
const connectionPromise = cachedUserData
4949
? _client
50-
.connectUser(cachedUserData, tokenOrProvider)
50+
.connectUser(cachedUserData, tokenOrProvider!)
5151
.then(() => {
5252
setError(null);
5353
})

0 commit comments

Comments
 (0)