Skip to content

Commit 56652f3

Browse files
Copilotcameri
andauthored
docs: deduplicate dev setup from README, revamp CONTRIBUTING with fairness policy and husky guidance (#554)
* docs(changeset): revamp contributing workflow * docs: revamp CONTRIBUTING.md with fairness policy, dev setup, husky guidance, and deduplicate README Agent-Logs-Url: https://github.com/cameri/nostream/sessions/c6b93441-302b-436f-92b4-cb1ca5bbcce9 Co-authored-by: cameri <378886+cameri@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: cameri <378886+cameri@users.noreply.github.com>
1 parent 3c78e61 commit 56652f3

3 files changed

Lines changed: 306 additions & 176 deletions

File tree

.changeset/sparkly-times-win.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
---
2+
---

CONTRIBUTING.md

Lines changed: 299 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,294 @@ before making a change.
66

77
Please keep the conversations civil, respectful and focus on the topic being discussed.
88

9+
## Issue Assignment & Fairness Policy
10+
11+
To keep the project moving fairly for everyone, please follow these guidelines:
12+
13+
- **Search before submitting.** Before opening a new issue or PR, search existing issues to avoid
14+
duplicates or overlapping work.
15+
- **All PRs must have an associated issue.** Open or find a relevant issue before starting work.
16+
Starting a PR without a linked issue means your work may not be merged, and it does not grant
17+
automatic assignment of an issue.
18+
- **Avoid snowball PRs.** Keep pull requests focused. Do not mix unrelated fixes, features, or
19+
changes in a single PR.
20+
- **Prefer older issues first.** When choosing what to work on, prefer resolving older open issues
21+
before newer ones, unless a blocker exists or the maintainers have explicitly agreed otherwise.
22+
- **Abandoned assignments.** An issue assigned to a contributor and not worked on for **7 days**
23+
(no comments or commits) is considered abandoned, unless the assignee is actively working on it
24+
or has requested an extension from a maintainer.
25+
- **Extensions and transfers.** Assignments can be explicitly extended or transferred to another
26+
contributor if the original assignee is unresponsive.
27+
- **Release your assignment.** If you are no longer interested in an issue, please comment to
28+
request being unassigned so others can pick it up.
29+
30+
## Development Environment Setup
31+
32+
Install Docker Desktop following the [official guide](https://docs.docker.com/desktop/) (if you
33+
plan to use Docker). You may have to uninstall Docker on your machine if you installed it using a
34+
different guide.
35+
36+
Clone the repository and enter the directory:
37+
38+
```
39+
git clone git@github.com:Cameri/nostream.git
40+
cd nostream
41+
```
42+
43+
Install dependencies (this also sets up Husky pre-commit hooks automatically):
44+
45+
```
46+
npm install
47+
```
48+
49+
> **Important:** Pre-commit hooks installed by Husky run linting and formatting checks on every
50+
> commit. Do **not** bypass them with `git commit --no-verify`. If a hook fails, fix the reported
51+
> issues before committing.
52+
53+
### Development Quick Start (Docker Compose)
54+
55+
Start the relay (runs in the foreground until stopped with Ctrl+C):
56+
57+
```
58+
./scripts/start
59+
```
60+
61+
### Development Quick Start (Standalone)
62+
63+
Set the required environment variables (or copy `.env.example` to `.env` and edit it):
64+
65+
```
66+
DB_URI="postgresql://postgres:postgres@localhost:5432/nostr_ts_relay_test"
67+
DB_USER=postgres
68+
```
69+
70+
or:
71+
72+
```
73+
DB_HOST=localhost
74+
DB_PORT=5432
75+
DB_NAME=nostr_ts_relay
76+
DB_USER=postgres
77+
DB_PASSWORD=postgres
78+
```
79+
80+
```
81+
REDIS_URI="redis://default:nostr_ts_relay@localhost:6379"
82+
83+
REDIS_HOST=localhost
84+
REDIS_PORT=6379
85+
REDIS_USER=default
86+
REDIS_PASSWORD=nostr_ts_relay
87+
```
88+
89+
Generate a long random secret and set `SECRET`:
90+
91+
```
92+
SECRET=aaabbbccc...dddeeefff
93+
# Secret shortened for brevity
94+
```
95+
96+
Run migrations (at least once and after pulling new changes):
97+
98+
```
99+
NODE_OPTIONS="-r dotenv/config" npm run db:migrate
100+
```
101+
102+
Create the `.nostr` folder and copy the default settings file:
103+
104+
```
105+
mkdir .nostr
106+
cp resources/default-settings.yaml .nostr/settings.yaml
107+
```
108+
109+
Start in development mode:
110+
111+
```
112+
npm run dev
113+
```
114+
115+
Or start in production mode:
116+
117+
```
118+
npm run start
119+
```
120+
121+
To clean up build, coverage, and test reports:
122+
123+
```
124+
npm run clean
125+
```
126+
127+
## Tests
128+
129+
### Linting and formatting (Biome)
130+
131+
Run code quality checks with Biome:
132+
133+
```
134+
npm run lint
135+
npm run lint:fix
136+
npm run format
137+
npm run format:check
138+
```
139+
140+
### Unit tests
141+
142+
Change to the project's directory:
143+
144+
```
145+
cd /path/to/nostream
146+
```
147+
148+
Run unit tests:
149+
150+
```
151+
npm run test:unit
152+
```
153+
154+
Run unit tests in watch mode:
155+
156+
```
157+
npm run test:unit:watch
158+
```
159+
160+
Get unit test coverage:
161+
162+
```
163+
npm run cover:unit
164+
```
165+
166+
Open the unit test report:
167+
168+
```
169+
open .test-reports/unit/index.html
170+
```
171+
172+
Open the unit test coverage report:
173+
174+
```
175+
open .coverage/unit/lcov-report/index.html
176+
```
177+
178+
### Integration tests (Docker Compose)
179+
180+
Change to the project's directory:
181+
182+
```
183+
cd /path/to/nostream
184+
```
185+
186+
Run integration tests:
187+
188+
```
189+
npm run docker:test:integration
190+
```
191+
192+
Get integration test coverage:
193+
194+
```
195+
npm run docker:cover:integration
196+
```
197+
198+
### Integration tests (Standalone)
199+
200+
Change to the project's directory:
201+
202+
```
203+
cd /path/to/nostream
204+
```
205+
206+
Set the following environment variables:
207+
208+
```
209+
DB_URI="postgresql://postgres:postgres@localhost:5432/nostr_ts_relay_test"
210+
211+
or
212+
213+
DB_HOST=localhost
214+
DB_PORT=5432
215+
DB_NAME=nostr_ts_relay_test
216+
DB_USER=postgres
217+
DB_PASSWORD=postgres
218+
DB_MIN_POOL_SIZE=1
219+
DB_MAX_POOL_SIZE=2
220+
```
221+
222+
Run the integration tests:
223+
224+
```
225+
npm run test:integration
226+
```
227+
228+
Open the integration test report:
229+
230+
```
231+
open .test-reports/integration/report.html
232+
```
233+
234+
Get integration test coverage:
235+
236+
```
237+
npm run cover:integration
238+
```
239+
240+
Open the integration test coverage report:
241+
242+
```
243+
open .coverage/integration/lcov-report/index.html
244+
```
245+
246+
## Security & Load Testing
247+
248+
Nostream includes a specialized security tester to simulate Slowloris-style connection holding and
249+
event flood (spam) attacks. This is used to verify relay resilience and prevent memory leaks.
250+
251+
### Running the Tester
252+
253+
```bash
254+
# Simulates 5,000 idle "zombie" connections + 100 events/sec spam
255+
npm run test:load -- --zombies 5000 --spam-rate 100
256+
```
257+
258+
### Analyzing Memory (Heap Snapshots)
259+
260+
To verify that connections are being correctly evicted and memory reclaimed:
261+
262+
1. Ensure the relay is running with `--inspect` enabled (see `docker-compose.yml`).
263+
2. Open **Chrome DevTools** (`chrome://inspect`) and connect to the relay process.
264+
3. In the **Memory** tab, take a **Heap Snapshot** (Baseline).
265+
4. Run the load tester.
266+
5. Wait for the eviction cycle (default: 120s) and take a second **Heap Snapshot**.
267+
6. Switch the view to **Comparison** and select the Baseline snapshot.
268+
7. Verify that object counts (e.g., `WebSocketAdapter`, `SocketAddress`) return to baseline levels.
269+
270+
### Server-Side Monitoring
271+
272+
To observe client and subscription counts in real-time during a test, you can instrument
273+
`src/adapters/web-socket-server-adapter.ts`:
274+
275+
1. Locate the `onHeartbeat()` method.
276+
2. Add the following logging logic:
277+
```typescript
278+
private onHeartbeat() {
279+
let totalSubs = 0;
280+
let totalClients = 0;
281+
this.webSocketServer.clients.forEach((webSocket) => {
282+
totalClients++;
283+
const webSocketAdapter = this.webSocketsAdapters.get(webSocket) as IWebSocketAdapter;
284+
if (webSocketAdapter) {
285+
webSocketAdapter.emit(WebSocketAdapterEvent.Heartbeat);
286+
totalSubs += webSocketAdapter.getSubscriptions().size;
287+
}
288+
});
289+
console.log(`[HEARTBEAT] Clients: ${totalClients} | Total subscriptions: ${totalSubs} | Heap Used: ${(process.memoryUsage().heapUsed / 1024 / 1024).toFixed(1)} MB`);
290+
}
291+
```
292+
3. View the live output via Docker logs:
293+
```bash
294+
docker compose logs -f nostream
295+
```
296+
9297
## Local Quality Checks
10298

11299
Run dead code and dependency analysis before opening a pull request:
@@ -44,15 +332,23 @@ This interactive prompt will ask you to:
44332

45333
The command creates a file in `.changeset/` — commit it with your PR.
46334

47-
### Docs-only PRs (no release)
335+
### Empty changesets (no source code changes)
48336

49-
If your PR only updates documentation and should not affect versioning, add an empty changeset:
337+
If your PR **only** updates documentation, CI/CD configuration, or test coverage — and leaves all
338+
production source code untouched — an empty changeset is acceptable:
50339

51340
```bash
52341
npx changeset --empty
53342
```
54343

55-
Commit the generated `.changeset/*.md` file with your PR. This satisfies CI without producing a version bump or changelog entry.
344+
Commit the generated `.changeset/*.md` file with your PR. This satisfies CI without producing a
345+
version bump or changelog entry.
346+
347+
This applies to PRs that exclusively contain:
348+
349+
- Documentation updates (README, CONTRIBUTING, CONFIGURATION, etc.)
350+
- CI/CD workflow changes (`.github/` files)
351+
- Test additions or improvements (when no source code is changed)
56352

57353
### Release process
58354

0 commit comments

Comments
 (0)