diff --git a/ee/apps/federation-service/package.json b/ee/apps/federation-service/package.json index d5e9ad9819ade..caa8a894a013c 100644 --- a/ee/apps/federation-service/package.json +++ b/ee/apps/federation-service/package.json @@ -25,7 +25,7 @@ "@rocket.chat/core-typings": "workspace:*", "@rocket.chat/emitter": "^0.31.25", "@rocket.chat/federation-matrix": "workspace:^", - "@rocket.chat/federation-sdk": "0.1.10", + "@rocket.chat/federation-sdk": "0.1.11", "@rocket.chat/http-router": "workspace:*", "@rocket.chat/instance-status": "workspace:^", "@rocket.chat/license": "workspace:^", diff --git a/ee/packages/federation-matrix/package.json b/ee/packages/federation-matrix/package.json index 76d068aaf789c..dd9a7e7fcc1db 100644 --- a/ee/packages/federation-matrix/package.json +++ b/ee/packages/federation-matrix/package.json @@ -38,7 +38,7 @@ "@rocket.chat/core-services": "workspace:^", "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/emitter": "^0.31.25", - "@rocket.chat/federation-sdk": "0.1.10", + "@rocket.chat/federation-sdk": "0.1.11", "@rocket.chat/http-router": "workspace:^", "@rocket.chat/license": "workspace:^", "@rocket.chat/models": "workspace:^", diff --git a/ee/packages/federation-matrix/src/api/_matrix/transactions.ts b/ee/packages/federation-matrix/src/api/_matrix/transactions.ts index ffbdd639811e0..683a189f63d02 100644 --- a/ee/packages/federation-matrix/src/api/_matrix/transactions.ts +++ b/ee/packages/federation-matrix/src/api/_matrix/transactions.ts @@ -252,6 +252,67 @@ const GetStateResponseSchema = { const isGetStateResponseProps = ajv.compile(GetStateResponseSchema); +const BackfillParamsSchema = { + type: 'object', + properties: { + roomId: { + type: 'string', + pattern: '^![A-Za-z0-9_=\\/.+-]+:(.+)$', + description: 'Matrix room ID', + }, + }, + required: ['roomId'], + additionalProperties: false, +}; + +const isBackfillParamsProps = ajv.compile(BackfillParamsSchema); + +const BackfillQuerySchema = { + type: 'object', + properties: { + limit: { + type: 'number', + minimum: 1, + maximum: 100, + description: 'Maximum number of events to retrieve', + }, + v: { + oneOf: [{ type: 'string' }, { type: 'array', items: { type: 'string' } }], + description: 'Event ID(s) to backfill from', + }, + }, + required: ['limit', 'v'], + additionalProperties: false, +}; + +const isBackfillQueryProps = ajv.compile<{ + limit: number; + v: string | string[]; +}>(BackfillQuerySchema); + +const BackfillResponseSchema = { + type: 'object', + properties: { + origin: { + type: 'string', + description: 'Origin server', + }, + origin_server_ts: { + type: 'number', + minimum: 0, + description: 'Unix timestamp in milliseconds', + }, + pdus: { + type: 'array', + items: EventBaseSchema, + description: 'Events in reverse chronological order', + }, + }, + required: ['origin', 'origin_server_ts', 'pdus'], +}; + +const isBackfillResponseProps = ajv.compile(BackfillResponseSchema); + export const getMatrixTransactionsRoutes = (services: HomeserverServices) => { const { event, federationAuth } = services; @@ -397,5 +458,49 @@ export const getMatrixTransactionsRoutes = (services: HomeserverServices) => { }; }, ) + // GET /_matrix/federation/v1/backfill/{roomId} + .get( + '/v1/backfill/:roomId', + { + params: isBackfillParamsProps, + query: isBackfillQueryProps, + response: { + 200: isBackfillResponseProps, + }, + tags: ['Federation'], + license: ['federation'], + }, + async (c) => { + const roomId = c.req.param('roomId'); + const limit = Number(c.req.query('limit') || 100); + const eventIds = c.req.queries('v'); + if (!eventIds?.length) { + return { + body: { + errcode: 'M_BAD_REQUEST', + error: 'Event ID must be provided in v query parameter', + }, + statusCode: 400, + }; + } + + try { + const result = await event.getBackfillEvents(roomId, eventIds as EventID[], limit); + + return { + body: result, + statusCode: 200, + }; + } catch (error) { + return { + body: { + errcode: 'M_UNKNOWN', + error: 'Failed to get backfill events', + }, + statusCode: 500, + }; + } + }, + ) ); }; diff --git a/yarn.lock b/yarn.lock index 110651e883e89..2d88324060794 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7543,7 +7543,7 @@ __metadata: "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/emitter": "npm:^0.31.25" "@rocket.chat/eslint-config": "workspace:^" - "@rocket.chat/federation-sdk": "npm:0.1.10" + "@rocket.chat/federation-sdk": "npm:0.1.11" "@rocket.chat/http-router": "workspace:^" "@rocket.chat/license": "workspace:^" "@rocket.chat/models": "workspace:^" @@ -7569,9 +7569,9 @@ __metadata: languageName: unknown linkType: soft -"@rocket.chat/federation-sdk@npm:0.1.10": - version: 0.1.10 - resolution: "@rocket.chat/federation-sdk@npm:0.1.10" +"@rocket.chat/federation-sdk@npm:0.1.11": + version: 0.1.11 + resolution: "@rocket.chat/federation-sdk@npm:0.1.11" dependencies: "@datastructures-js/priority-queue": "npm:^6.3.3" "@noble/ed25519": "npm:^3.0.0" @@ -7584,7 +7584,7 @@ __metadata: zod: "npm:^3.22.4" peerDependencies: typescript: ~5.9.2 - checksum: 10/39ec551128f6717b561c122cebab2354635f4d2dd6bb77be7d3581f4cbfe4f6e63953acf4764eba0e9e36239a5019d52d5f0426bc2968bca2674ed4a3ce60284 + checksum: 10/f45d1d43e28033e3b20022cedbd5825967bbf85346cebc2d6600d490f306fd253713a95bc51ce571e90027087d96497349c694e72a2c2913319d08e1046b0c06 languageName: node linkType: hard @@ -7597,7 +7597,7 @@ __metadata: "@rocket.chat/core-typings": "workspace:*" "@rocket.chat/emitter": "npm:^0.31.25" "@rocket.chat/federation-matrix": "workspace:^" - "@rocket.chat/federation-sdk": "npm:0.1.10" + "@rocket.chat/federation-sdk": "npm:0.1.11" "@rocket.chat/http-router": "workspace:*" "@rocket.chat/instance-status": "workspace:^" "@rocket.chat/license": "workspace:^"