From 464b54c1c5a9d5c062db2d3295317e46b1896260 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D0=B3=D0=BE=D1=80=20=D0=9A=D0=BE=D0=BD=D0=BE=D0=B2?= =?UTF-8?q?=D0=B0=D0=BB=D0=BE=D0=B2?= Date: Tue, 5 May 2026 03:18:44 +0300 Subject: [PATCH 1/4] fix(): repetitions timestamp index on collection creation --- src/resolvers/project.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/resolvers/project.js b/src/resolvers/project.js index 65fc2cdc..18da81f3 100644 --- a/src/resolvers/project.js +++ b/src/resolvers/project.js @@ -14,6 +14,7 @@ const { GitHubService } = require('../integrations/github/service'); const EVENTS_GROUP_HASH_INDEX_NAME = 'groupHashUnique'; const REPETITIONS_GROUP_HASH_INDEX_NAME = 'groupHash_hashed'; const REPETITIONS_USER_ID_INDEX_NAME = 'userId'; +const REPETITIONS_TIMESTAMP_INDEX_NAME = 'timestamp'; const EVENTS_TIMESTAMP_INDEX_NAME = 'timestamp'; const EVENTS_PAYLOAD_RELEASE_INDEX_NAME = 'payloadRelease'; const GROUPING_TIMESTAMP_INDEX_NAME = 'groupingTimestamp'; @@ -213,6 +214,13 @@ module.exports = { sparse: true, }); + await projectRepetitionsEventsCollection.createIndex({ + timestamp: 1, + }, { + name: REPETITIONS_TIMESTAMP_INDEX_NAME, + sparse: true, + }); + await projectEventsCollection.createIndex({ timestamp: 1, }, { From f49c3656b1b2d77e8bf6cb2320429ea3c7f72c84 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 5 May 2026 00:23:56 +0000 Subject: [PATCH 2/4] Bump version up to 1.4.14 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8a2c557b..8440fbbe 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hawk.api", - "version": "1.4.13", + "version": "1.4.14", "main": "index.ts", "license": "BUSL-1.1", "scripts": { From db4740b3aca5f24e21f4eb192cb6a7f28a4fdcdb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 5 May 2026 14:26:12 +0000 Subject: [PATCH 3/4] test: add unit test for createProject repetitions timestamp index Agent-Logs-Url: https://github.com/codex-team/hawk.api.nodejs/sessions/5237af31-c1bb-495f-a4d2-c59bf81d4ccc Co-authored-by: neSpecc <3684889+neSpecc@users.noreply.github.com> --- test/resolvers/project.test.ts | 83 ++++++++++++++++++++++++++++++++++ yarn.lock | 8 ++-- 2 files changed, 87 insertions(+), 4 deletions(-) diff --git a/test/resolvers/project.test.ts b/test/resolvers/project.test.ts index 8f50acbc..3d595cb2 100644 --- a/test/resolvers/project.test.ts +++ b/test/resolvers/project.test.ts @@ -8,9 +8,24 @@ jest.mock('../../src/integrations/github/service', () => require('../__mocks__/g // eslint-disable-next-line @typescript-eslint/no-var-requires import { deleteInstallationMock, GitHubService } from '../__mocks__/github-service'; +jest.mock('../../src/mongo', () => ({ + databases: { + events: { + createCollection: jest.fn(), + }, + }, +})); + +jest.mock('../../src/utils/telegram', () => ({ + sendMessage: jest.fn(), +})); + // @ts-expect-error - CommonJS module, TypeScript can't infer types properly import projectResolverModule from '../../src/resolvers/project'; +// eslint-disable-next-line @typescript-eslint/no-var-requires +const mongoMock = require('../../src/mongo'); + /** * Type assertion for CommonJS module */ @@ -18,6 +33,7 @@ const projectResolver = projectResolverModule as { Mutation: { disconnectTaskManager: (...args: unknown[]) => Promise; updateTaskManagerSettings: (...args: unknown[]) => Promise; + createProject: (...args: unknown[]) => Promise; }; Query: { project: (...args: unknown[]) => Promise; @@ -518,3 +534,70 @@ describe('Project Resolver - Task Manager Mutations', () => { }); }); }); + +describe('Project Resolver - createProject', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should create a timestamp index on the repetitions collection', async () => { + const projectId = new ObjectId(); + + const eventsCollectionMock = { createIndex: jest.fn().mockResolvedValue(undefined) }; + const repetitionsCollectionMock = { createIndex: jest.fn().mockResolvedValue(undefined) }; + const dailyEventsCollectionMock = { createIndex: jest.fn().mockResolvedValue(undefined) }; + + mongoMock.databases.events.createCollection.mockImplementation((name: string) => { + if (name.startsWith('events:')) { + return Promise.resolve(eventsCollectionMock); + } + if (name.startsWith('repetitions:')) { + return Promise.resolve(repetitionsCollectionMock); + } + if (name.startsWith('dailyEvents:')) { + return Promise.resolve(dailyEventsCollectionMock); + } + }); + + const mockProject = { + _id: projectId, + createNotificationsRule: jest.fn().mockResolvedValue(undefined), + }; + + const mockProjectsFactory = { + create: jest.fn().mockResolvedValue(mockProject), + findById: jest.fn().mockResolvedValue(mockProject), + }; + + const mockWorkspacesFactory = { + findById: jest.fn().mockResolvedValue({ _id: new ObjectId(), name: 'Test Workspace' }), + }; + + const mockUsersFactory = { + findById: jest.fn().mockResolvedValue({ email: 'test@example.com' }), + }; + + const context = { + user: { id: new ObjectId().toString() }, + factories: { + workspacesFactory: mockWorkspacesFactory as any, + projectsFactory: mockProjectsFactory as any, + usersFactory: mockUsersFactory as any, + plansFactory: {} as any, + businessOperationsFactory: {} as any, + releasesFactory: {} as any, + }, + }; + + await projectResolver.Mutation.createProject( + {}, + { workspaceId: new ObjectId().toString(), name: 'Test Project', image: '' }, + context + ); + + expect(repetitionsCollectionMock.createIndex).toHaveBeenCalledWith( + { timestamp: 1 }, + { name: 'timestamp', sparse: true } + ); + }); +}); diff --git a/yarn.lock b/yarn.lock index bfe5bde9..995f6267 100644 --- a/yarn.lock +++ b/yarn.lock @@ -494,10 +494,10 @@ dependencies: tslib "^2.4.0" -"@hawk.so/nodejs@^3.3.1": - version "3.3.1" - resolved "https://registry.yarnpkg.com/@hawk.so/nodejs/-/nodejs-3.3.1.tgz#23e304607a64cd3a91e488d481cc968fccab6dba" - integrity sha512-GALpgM/96As5gE3YdwVcMglTc57Dfqez3b2EciKJoq0u174gK/h+8tayEL+/65pqBy7BNni8ptCQWdgw5Zv5yA== +"@hawk.so/nodejs@^3.3.2": + version "3.3.2" + resolved "https://registry.yarnpkg.com/@hawk.so/nodejs/-/nodejs-3.3.2.tgz#113db57546f82e5c405c43b6dc5709232827c4df" + integrity sha512-i8KFHjFfwmtgN///Q1oxNDTJSQEtjy5iBqDZBuSMAzpQhBBmBE2n9RNIRDaVOby8r+Z+oo3g4Sik2LlffB5AWQ== dependencies: "@hawk.so/types" "^0.5.8" axios "^0.21.1" From b0ea9d67ddf7c0f59010aa35b7430e1262d42356 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 5 May 2026 14:27:26 +0000 Subject: [PATCH 4/4] test: add explicit error fallback in createCollection mock Agent-Logs-Url: https://github.com/codex-team/hawk.api.nodejs/sessions/5237af31-c1bb-495f-a4d2-c59bf81d4ccc Co-authored-by: neSpecc <3684889+neSpecc@users.noreply.github.com> --- test/resolvers/project.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/test/resolvers/project.test.ts b/test/resolvers/project.test.ts index 3d595cb2..00a4a907 100644 --- a/test/resolvers/project.test.ts +++ b/test/resolvers/project.test.ts @@ -557,6 +557,7 @@ describe('Project Resolver - createProject', () => { if (name.startsWith('dailyEvents:')) { return Promise.resolve(dailyEventsCollectionMock); } + return Promise.reject(new Error(`Unexpected collection name: ${name}`)); }); const mockProject = {