first commit

This commit is contained in:
2026-10-03 13:40:26 +02:00
parent 732a5b5a16
commit 566f415fa7
555 changed files with 62704 additions and 0 deletions

View File

@@ -0,0 +1,77 @@
import { Injectable } from '@nestjs/common';
import { QueryBus } from '@nestjs/cqrs';
import { NotFoundError } from '@task-stream/api/shared/domain';
import { ActivityReadModel } from '@task-stream/api/tracker/domain';
import {
ChangeFeed,
CommentChange,
IssueChange,
ProjectChange,
ReleaseChange,
} from './ports/change-feed';
import { CanViewProjectQuery } from './queries/can-view-project.query';
import { GetIssueQuery } from './queries/get-issue.query';
/** Realtime subscriptions, authorised at subscribe time. */
@Injectable()
export class ChangesService {
constructor(
private readonly queryBus: QueryBus,
private readonly changeFeed: ChangeFeed,
) {}
async watchIssues(
viewerId: string,
projectId: string,
): Promise<AsyncIterableIterator<IssueChange>> {
await this.assertCanView(viewerId, projectId);
return this.changeFeed.issues(projectId);
}
async watchComments(
viewerId: string,
issueId: string,
): Promise<AsyncIterableIterator<CommentChange>> {
await this.queryBus.execute(new GetIssueQuery(viewerId, issueId)); // access check
return this.changeFeed.comments(issueId);
}
async watchActivity(
viewerId: string,
projectId: string,
): Promise<AsyncIterableIterator<ActivityReadModel>> {
await this.assertCanView(viewerId, projectId);
return this.changeFeed.activity(projectId);
}
async watchReleases(
viewerId: string,
projectId: string,
): Promise<AsyncIterableIterator<ReleaseChange>> {
await this.assertCanView(viewerId, projectId);
return this.changeFeed.releases(projectId);
}
async watchProject(
viewerId: string,
projectId: string,
): Promise<AsyncIterableIterator<ProjectChange>> {
await this.assertCanView(viewerId, projectId);
return this.changeFeed.project(projectId);
}
/** Projects the viewer is added to or removed from. */
watchMyProjects(viewerId: string): AsyncIterableIterator<ProjectChange> {
return this.changeFeed.userProjects(viewerId);
}
private async assertCanView(
viewerId: string,
projectId: string,
): Promise<void> {
const allowed = await this.queryBus.execute(
new CanViewProjectQuery(viewerId, projectId),
);
if (!allowed) throw new NotFoundError('Project', projectId);
}
}