diff --git a/Makefile b/Makefile deleted file mode 100644 index df0fa78..0000000 --- a/Makefile +++ /dev/null @@ -1,30 +0,0 @@ -PROTOBUF_VERSION = 3.19.1 -PROTOC ?= protoc -UNAME := $(shell uname) -PROTO_FILES := $(wildcard src/*.proto) -export PATH := ts-server/node_modules/.bin:/usr/local/include/:protoc3/bin:$(PATH) - -ifeq ($(UNAME),Darwin) -PROTOBUF_ZIP = protoc-$(PROTOBUF_VERSION)-osx-x86_64.zip -else -PROTOBUF_ZIP = protoc-$(PROTOBUF_VERSION)-linux-x86_64.zip -endif - -# for ts -install_compiler: - @# remove local folder - rm -rf protoc3 || true - - @# Make sure you grab the latest version - curl -OL https://github.com/protocolbuffers/protobuf/releases/download/v$(PROTOBUF_VERSION)/$(PROTOBUF_ZIP) - - @# Unzip - unzip $(PROTOBUF_ZIP) -d protoc3 - @# delete the files - rm $(PROTOBUF_ZIP) - - @# move protoc to /usr/local/bin/ - chmod +x protoc3/bin/protoc - -build: install_compiler - @./build-local-proto.sh diff --git a/friendships_ea.proto b/friendships_ea.proto deleted file mode 100644 index 85f56bc..0000000 --- a/friendships_ea.proto +++ /dev/null @@ -1,158 +0,0 @@ -// THIS LIVES HERE FOR NOW, BUT IT SHOULD BE MOVED TO @dcl/protcol when release - -syntax = "proto3"; -package decentraland.social.friendships_ea; - -import "google/protobuf/empty.proto"; - - -// This message is a response that is sent from the server to the client -message FriendshipEventResponse { - oneof body { - RequestResponse request = 1; - AcceptResponse accept = 2; - RejectResponse reject = 4; - DeleteResponse delete = 5; - CancelResponse cancel = 6; - } -} - -message FriendshipEventResponses { - repeated FriendshipEventResponse responses = 1; -} - -message FriendshipEventPayload { - oneof body { - RequestPayload request = 1; - AcceptPayload accept = 2; - RejectPayload reject = 4; - DeletePayload delete = 5; - CancelPayload cancel = 6; - } -} - -message User { string address = 1; } - -message Users { repeated User users = 1; } - -message RequestResponse { - User user = 1; - int64 created_at = 2; - optional string message = 3; -} - -message RequestPayload { - User user = 1; - optional string message = 3; -} - -message Requests { - int64 total = 1; // Total amount of friendship requests - repeated RequestResponse items = 2; -} - -message RequestEvents { - Requests outgoing = 1; // Requests the authed user have sent to users - Requests incoming = 2; // Requests the authed user have received from users -} - -message AcceptResponse { User user = 1; } - -message AcceptPayload { User user = 1; } - -message RejectResponse { User user = 1; } - -message RejectPayload { User user = 1; } - -message DeleteResponse { User user = 1; } - -message DeletePayload { User user = 1; } - -message CancelResponse { User user = 1; } - -message CancelPayload { User user = 1; } - -message UpdateFriendshipPayload { - FriendshipEventPayload event = 1; -} - -message MutualFriendsPayload { - User user = 1; -} - -message BadRequestError { - string message = 1; -} -message UnauthorizedError { - string message = 1; -} -message ForbiddenError { - string message = 1; -} -message TooManyRequestsError { - string message = 1; -} -message InternalServerError { - string message = 1; -} - -message UsersResponse { - oneof response { - Users users = 1; - InternalServerError internal_server_error = 2; - UnauthorizedError unauthorized_error = 3; - ForbiddenError forbidden_error = 4; - TooManyRequestsError too_many_requests_error = 5; - BadRequestError bad_request_error = 6; - } -} - -message RequestEventsResponse { - oneof response { - RequestEvents events = 1; - InternalServerError internal_server_error = 2; - UnauthorizedError unauthorized_error = 3; - ForbiddenError forbidden_error = 4; - TooManyRequestsError too_many_requests_error = 5; - } -} - -message UpdateFriendshipResponse { - oneof response { - FriendshipEventResponse event = 1; - InternalServerError internal_server_error = 2; - UnauthorizedError unauthorized_error = 3; - ForbiddenError forbidden_error = 4; - TooManyRequestsError too_many_requests_error = 5; - BadRequestError bad_request_error = 6; - } -} - -message SubscribeFriendshipEventsUpdatesResponse { - oneof response { - FriendshipEventResponses events = 1; - InternalServerError internal_server_error = 2; - UnauthorizedError unauthorized_error = 3; - ForbiddenError forbidden_error = 4; - TooManyRequestsError too_many_requests_error = 5; - } -} - -service FriendshipsService { - // Get the list of friends for the authenticated user - rpc GetFriends(google.protobuf.Empty) returns (stream UsersResponse) {} - - // Get the list of mutual friends between the authenticated user and the one in the parameter - rpc GetMutualFriends(MutualFriendsPayload) returns (stream UsersResponse) {} - - // Get the list of request events for the authenticated user - rpc GetRequestEvents(google.protobuf.Empty) returns (RequestEventsResponse) {} - - // Update friendship status: REQUEST, ACCEPT, REJECT, CANCEL, DELETE - rpc UpdateFriendshipEvent(UpdateFriendshipPayload) - returns (UpdateFriendshipResponse) {} - - // Subscribe to updates of friendship status: REQUEST, ACCEPT, REJECT, CANCEL, DELETE - rpc SubscribeFriendshipEventsUpdates(google.protobuf.Empty) - returns (stream SubscribeFriendshipEventsUpdatesResponse) {} -} diff --git a/package.json b/package.json index a8d7491..10386f9 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,8 @@ "@well-known-components/test-helpers": "^1.5.6", "nodemon": "^3.1.0", "ts-node": "^10.9.2", - "typescript": "^5.4.2" + "typescript": "^5.4.2", + "@types/redis": "^4.0.11" }, "prettier": { "printWidth": 120, @@ -29,7 +30,7 @@ }, "dependencies": { "@dcl/platform-crypto-middleware": "^1.0.2", - "@dcl/protocol": "^1.0.0-2569677750.commit-6ce832a", + "@dcl/protocol": "^1.0.0-8789372854.commit-f692c7a", "@dcl/rpc": "^1.1.2", "@well-known-components/env-config-provider": "^1.2.0", "@well-known-components/fetch-component": "^2.0.2", @@ -40,6 +41,9 @@ "@well-known-components/pg-component": "^0.2.2", "@well-known-components/uws-http-server": "^0.0.1-20240314125425.commit-711dd8f", "fp-future": "^1.0.1", + "mitt": "^3.0.1", + "redis": "^4.6.13", + "sql-template-strings": "^2.2.2", "ws": "^8.16.0" } } diff --git a/src/adapters/db.ts b/src/adapters/db.ts index 39dc6b4..4cdcaff 100644 --- a/src/adapters/db.ts +++ b/src/adapters/db.ts @@ -1,7 +1,211 @@ -import { AppComponents } from '../types' +import SQL, { SQLStatement } from 'sql-template-strings' +import { randomUUID } from 'node:crypto' +import { PoolClient } from 'pg' +import { Action, AppComponents, Friendship, FriendshipAction, FriendshipRequest } from '../types' -export interface IDatabaseComponent {} +export interface IDatabaseComponent { + createFriendship(users: [string, string], isActive: boolean, txClient?: PoolClient): Promise + updateFriendshipStatus(friendshipId: string, isActive: boolean, txClient?: PoolClient): Promise + getFriends(userAddress: string, onlyActive?: boolean): AsyncGenerator + getMutualFriends(userAddress1: string, userAddress2: string): AsyncGenerator<{ address: string }> + getFriendship(userAddresses: [string, string]): Promise + getLastFriendshipAction(friendshipId: string): Promise + recordFriendshipAction( + friendshipId: string, + actingUser: string, + action: Action, + metadata: Record | null, + txClient?: PoolClient + ): Promise + getReceivedFriendshipRequests(userAddress: string): Promise + getSentFriendshipRequests(userAddress: string): Promise + executeTx(cb: (client: PoolClient) => Promise): Promise +} + +export function createDBComponent(components: Pick): IDatabaseComponent { + const { pg, logs } = components + + const logger = logs.getLogger('db-component') + + return { + getFriends(userAddress, onlyActive = true) { + let query: SQLStatement + + if (onlyActive) { + query = SQL`SELECT * FROM friendships WHERE (address_requester = ${userAddress} OR address_requested = ${userAddress}) AND is_active = true` + } else { + query = SQL`SELECT * FROM friendships WHERE (address_requester = ${userAddress} OR address_requested = ${userAddress})` + } + + const generator = pg.streamQuery(query) + + return generator + }, + getMutualFriends(userAddress1, userAddress2) { + const generator = pg.streamQuery<{ address: string }>( + SQL`WITH friendsA as ( + SELECT + CASE + WHEN address_requester = ${userAddress1} then address_requested + else address_requester + end as address + FROM + ( + SELECT + f_a.* + from + friendships f_a + where + ( + f_a.address_requester = ${userAddress1} + or f_a.address_requested = ${userAddress1} + ) and f_a.is_active = true + ) as friends_a + ) + SELECT + address + FROM + friendsA f_b + WHERE + address IN ( + SELECT + CASE + WHEN address_requester = ${userAddress2} then address_requested + else address_requester + end as address_a + FROM + ( + SELECT + f_b.* + from + friendships f_b + where + ( + f_b.address_requester = ${userAddress2} + or f_b.address_requested = ${userAddress2} + ) and f_b.is_active = true + ) as friends_b + );` + ) + + return generator + }, + async getFriendship(users) { + const [userAddress1, userAddress2] = users + const query = SQL` + SELECT * FROM friendships + WHERE + (address_requester = ${userAddress1} AND address_requested = ${userAddress2}) + OR + (address_requester = ${userAddress2} AND address_requested = ${userAddress1}) + ` + + const results = await pg.query(query) + + return results.rows[0] + }, + async getLastFriendshipAction(friendshipId) { + const query = SQL` + SELECT * FROM friendship_actions where friendship_id = ${friendshipId} ORDER BY timestamp DESC LIMIT 1 + ` + const results = await pg.query(query) + + return results.rows[0] + }, + async createFriendship(users, isActive, txClient) { + const [addressRequester, addressRequested] = users + const uuid = randomUUID() + + const query = SQL`INSERT INTO friendships (id, address_requester, address_requested, is_active) VALUES (${uuid}, ${addressRequester}, ${addressRequested}, ${isActive})` + + if (txClient) { + await txClient.query(query) + } else { + await pg.query(query) + } + + return uuid + }, + async updateFriendshipStatus(friendshipId, isActive, txClient) { + logger.debug(`updating ${friendshipId} - ${isActive}`) + const query = SQL`UPDATE friendships SET is_active = ${isActive}, updated_at = now() WHERE id = ${friendshipId}` + console.log(query.text) + console.log(query.values) + + if (txClient) { + const results = await txClient.query(query) + return results.rowCount === 1 + } + + const results = await pg.query(query) + return results.rowCount === 1 + }, + async recordFriendshipAction(friendshipId, actingUser, action, metadata, txClient) { + const uuid = randomUUID() + const query = SQL` + INSERT INTO friendship_actions (id, friendship_id, action, acting_user, metadata) + VALUES (${uuid}, ${friendshipId}, ${action}, ${actingUser}, ${metadata})` + + if (txClient) { + await txClient.query(query) + } else { + await pg.query(query) + } + + return true + }, + async getReceivedFriendshipRequests(userAddress) { + const query = SQL` + SELECT f.address_requester as address, fa.timestamp, fa.metadata FROM friendships f + INNER JOIN friendship_actions fa ON f.id = fa.friendship_id + WHERE + f.address_requested = ${userAddress} + AND fa.action = 'request' + AND f.is_active IS FALSE + AND fa.timestamp = ( + SELECT MAX(fa2.timestamp) + FROM friendship_actions fa2 + WHERE fa2.friendship_id = fa.friendship_id + ) + ` + + const results = await pg.query(query) + + return results.rows + }, + async getSentFriendshipRequests(userAddress) { + const query = SQL` + SELECT f.address_requested as address, fa.timestamp, fa.metadata FROM friendships f + INNER JOIN friendship_actions fa ON f.id = fa.friendship_id + WHERE + f.address_requester = ${userAddress} + AND fa.action = 'request' + AND f.is_active IS FALSE + AND fa.timestamp = ( + SELECT MAX(fa2.timestamp) + FROM friendship_actions fa2 + WHERE fa2.friendship_id = fa.friendship_id + ) + ` + + const results = await pg.query(query) -export function createDBComponent(_components: Pick): IDatabaseComponent { - return {} + return results.rows + }, + async executeTx(cb: (client: PoolClient) => Promise): Promise { + const pool = pg.getPool() + const client = await pool.connect() + await client.query('BEGIN') + try { + const res = await cb(client) + await client.query('COMMIT') + return res + } catch (error) { + logger.error(error as any) + await client.query('ROLLBACK') + client.release() + throw error + } + } + } } diff --git a/src/adapters/pubsub.ts b/src/adapters/pubsub.ts new file mode 100644 index 0000000..edcc862 --- /dev/null +++ b/src/adapters/pubsub.ts @@ -0,0 +1,57 @@ +import { IBaseComponent } from '@well-known-components/interfaces' +import { AppComponents, SubscriptionEventsEmitter } from '../types' + +const FRIENDSHIP_UPDATES_CHANNEL = 'FRIENDSHIP_UPDATES' + +export type IPubSubComponent = IBaseComponent & { + subscribeToFriendshipUpdates(cb: (message: string) => void): Promise + publishFriendshipUpdate(update: SubscriptionEventsEmitter['update']): Promise +} + +export default function createPubSubComponent(components: Pick): IPubSubComponent { + const { logs, redis } = components + const logger = logs.getLogger('pubsub-component') + + const subClient = redis.client.duplicate() + const pubClient = redis.client.duplicate() + + let friendshipUpdatesCb: (message: string) => void | undefined + + return { + async start() { + if (!subClient.isReady) { + await subClient.connect() + } + + if (!pubClient.isReady) { + await pubClient.connect() + } + }, + async stop() { + if (subClient.isReady) { + await subClient.disconnect() + } + + if (pubClient.isReady) { + await pubClient.disconnect() + } + }, + async subscribeToFriendshipUpdates(cb) { + try { + friendshipUpdatesCb = cb + await subClient.subscribe(FRIENDSHIP_UPDATES_CHANNEL, friendshipUpdatesCb) + } catch (error) { + logger.error(error as any) + } + }, + async publishFriendshipUpdate(update) { + try { + const message = JSON.stringify(update) + logger.debug('publishing update to FRIENDSHIP_UPDATES > ', { update: message }) + await pubClient.publish(FRIENDSHIP_UPDATES_CHANNEL, message) + } catch (error) { + logger.error(error as any) + } + } + } +} diff --git a/src/adapters/redis.ts b/src/adapters/redis.ts new file mode 100644 index 0000000..9828729 --- /dev/null +++ b/src/adapters/redis.ts @@ -0,0 +1,37 @@ +import { createClient } from 'redis' +import { AppComponents } from '../types' +import { IBaseComponent } from '@well-known-components/interfaces' + +export interface IRedisComponent extends IBaseComponent { + client: ReturnType +} + +export default async function createRedisComponent( + components: Pick +): Promise { + const { logs, config } = components + const logger = logs.getLogger('redis-component') + const REDIS_URL = (await config.getString('REDIS_CONNECTION_STRING')) || `redis://127.0.0.1:6379` + + const client = createClient({ + url: REDIS_URL + }) + + client.on('error', (err) => { + logger.error(err) + }) + + async function start() { + await client.connect() + } + + async function stop() { + await client.disconnect() + } + + return { + client, + start, + stop + } +} diff --git a/src/adapters/rpcServer.ts b/src/adapters/rpcServer.ts index 5c441f1..908a2e9 100644 --- a/src/adapters/rpcServer.ts +++ b/src/adapters/rpcServer.ts @@ -1,74 +1,289 @@ -import { createRpcServer } from '@dcl/rpc' +import { Transport, createRpcServer } from '@dcl/rpc' +import { SocialServiceDefinition } from '@dcl/protocol/out-js/decentraland/social_service_v2/social_service.gen' import { registerService } from '@dcl/rpc/dist/codegen' +import mitt from 'mitt' +import { IBaseComponent } from '@well-known-components/interfaces' import { - FriendshipsServiceDefinition, - UsersResponse, - SubscribeFriendshipEventsUpdatesResponse, - RequestEventsResponse, - UpdateFriendshipResponse -} from '../friendships_ea' -import { AppComponents, RpcServerContext } from '../types' + Action, + AppComponents, + Friendship, + FriendshipStatus, + RpcServerContext, + SubscriptionEventsEmitter +} from '../types' +import { + getNewFriendshipStatus, + parseEmittedUpdateToFriendshipUpdate, + parseUpsertFriendshipRequest, + validateNewFriendshipAction +} from '../logic/friendships' +import emitterToAsyncGenerator from '../utils/emitterToGenerator' +import { normalizeAddress } from '../utils/address' + +export type IRPCServerComponent = IBaseComponent & { + attachUser(user: { transport: Transport; address: string }): void +} + +const FRIENDSHIPS_COUNT_PAGE_STREAM = 20 -export default function createRpcServerComponent(components: Pick) { - const { logs } = components +const INTERNAL_SERVER_ERROR = 'SERVER ERROR' + +export default async function createRpcServerComponent( + components: Pick +): Promise { + const { logs, db, pubsub } = components + + const SHARED_CONTEXT: Pick = { + subscribers: {} + } const server = createRpcServer({ - logger: logs.getLogger('rpc-server') + logger: logs.getLogger('rpcserver') }) - const _logger = logs.getLogger('rpc-server-handler') - // Mocked server until we get the new service definition & db queries done + const logger = logs.getLogger('rpcserver-handler') + server.setHandler(async function handler(port) { - registerService(port, FriendshipsServiceDefinition, async () => ({ - getFriends(_request, _context) { + registerService(port, SocialServiceDefinition, async () => ({ + getFriends(_request, context) { + logger.debug('getting friends for ', { address: context.address }) + let friendsGenerator: AsyncGenerator | undefined + try { + friendsGenerator = db.getFriends(context.address) + } catch (error) { + logger.error(error as any) + // throw an error bc there is no sense to create a generator to send an error + // as it's done in the previous Social Service + throw new Error(INTERNAL_SERVER_ERROR) + } + const generator = async function* () { - const response: UsersResponse = { - users: { users: [] } + let users = [] + for await (const friendship of friendsGenerator) { + const { address_requested, address_requester } = friendship + if (context.address === address_requested) { + users.push({ address: address_requester }) + } else { + users.push({ address: address_requested }) + } + + if (users.length === FRIENDSHIPS_COUNT_PAGE_STREAM) { + const response = { + users: [...users] + } + users = [] + yield response + } + } + + if (users.length) { + const response = { + users + } + yield response } - yield response } return generator() }, - getMutualFriends(_request, _context) { + getMutualFriends(request, context) { + logger.debug(`getting mutual friends ${context.address}<>${request.user!.address}`) + let mutualFriends: AsyncGenerator<{ address: string }> | undefined + try { + mutualFriends = db.getMutualFriends(context.address, normalizeAddress(request.user!.address)) + } catch (error) { + logger.error(error as any) + // throw an error bc there is no sense to create a generator to send an error + // as it's done in the previous Social Service + throw new Error(INTERNAL_SERVER_ERROR) + } + const generator = async function* () { - const response: UsersResponse = { - users: { users: [] } + const users = [] + for await (const friendship of mutualFriends) { + const { address } = friendship + users.push({ address }) + if (users.length === FRIENDSHIPS_COUNT_PAGE_STREAM) { + const response = { + users + } + yield response + } + } + + if (users.length) { + const response = { + users + } + yield response } - yield response } return generator() }, - async getRequestEvents(_request, _context) { - const res: RequestEventsResponse = { - events: { - outgoing: { items: [], total: 0 }, - incoming: { items: [], total: 0 } + async getPendingFriendshipRequests(_request, context) { + try { + const pendingRequests = await db.getReceivedFriendshipRequests(context.address) + const mappedRequestss = pendingRequests.map(({ address, timestamp, metadata }) => ({ + user: { address }, + createdAt: new Date(timestamp).getTime(), + message: metadata?.message || '' + })) + + return { + response: { + $case: 'requests', + requests: { + requests: mappedRequestss + } + } + } + } catch (error) { + logger.error(error as any) + return { + response: { + $case: 'internalServerError', + internalServerError: {} + } } } - return res }, - async updateFriendshipEvent(_request, _context) { - const res: UpdateFriendshipResponse = { - event: { - accept: { - user: { - address: '0xa' + async getSentFriendshipRequests(_request, context) { + try { + const pendingRequests = await db.getSentFriendshipRequests(context.address) + const mappedRequestss = pendingRequests.map(({ address, timestamp, metadata }) => ({ + user: { address }, + createdAt: new Date(timestamp).getTime(), + message: metadata?.message || '' + })) + + return { + response: { + $case: 'requests', + requests: { + requests: mappedRequestss } } } + } catch (error) { + logger.error(error as any) + return { + response: { + $case: 'internalServerError', + internalServerError: {} + } + } } - return res }, - subscribeFriendshipEventsUpdates(_request, _context) { + async upsertFriendship(request, context) { + const parsedRequest = parseUpsertFriendshipRequest(request) + if (!parsedRequest) { + logger.error('upsert friendship received unkwown message: ', request as any) + return { + response: { + $case: 'internalServerError', + internalServerError: {} + } + } + } + + logger.debug(`upsert friendship > `, parsedRequest as Record) + + try { + const friendship = await db.getFriendship([context.address, parsedRequest.user!]) + let lastAction = undefined + if (friendship) { + const lastRecordedAction = await db.getLastFriendshipAction(friendship.id) + lastAction = lastRecordedAction + } + + if ( + !validateNewFriendshipAction( + context.address, + { action: parsedRequest.action, user: parsedRequest.user }, + lastAction + ) + ) { + logger.error('invalid action for a friendship') + return { + response: { + $case: 'invalidFriendshipAction', + invalidFriendshipAction: {} + } + } + } + + const friendshipStatus = getNewFriendshipStatus(parsedRequest.action) + const isActive = friendshipStatus === FriendshipStatus.Friends + + logger.debug('friendshipstatus > ', { isActive: JSON.stringify(isActive), friendshipStatus }) + + const id = await db.executeTx(async (tx) => { + let id + if (friendship) { + await db.updateFriendshipStatus(friendship.id, isActive, tx) + id = friendship.id + } else { + const newFriendshipId = await db.createFriendship([context.address, parsedRequest.user!], isActive, tx) + id = newFriendshipId + } + + await db.recordFriendshipAction( + id, + context.address, + parsedRequest.action, + parsedRequest.action === Action.REQUEST ? parsedRequest.metadata : null, + tx + ) + return id + }) + + logger.debug(`${id} friendship was upserted successfully`) + + await pubsub.publishFriendshipUpdate({ + from: context.address, + to: parsedRequest.user, + action: parsedRequest.action, + timestamp: Date.now(), + metadata: + parsedRequest.action === Action.REQUEST + ? parsedRequest.metadata + ? parsedRequest.metadata + : undefined + : undefined + }) + + return { + response: { + $case: 'accepted', + accepted: {} + } + } + } catch (error) { + logger.error(error as any) + return { + response: { + $case: 'internalServerError', + internalServerError: {} + } + } + } + }, + subscribeToFriendshipUpdates(_request, context) { + const eventEmitter = mitt() + context.subscribers[context.address] = eventEmitter + const updatesGenerator = emitterToAsyncGenerator(eventEmitter, 'update') + const generator = async function* () { - const response: SubscribeFriendshipEventsUpdatesResponse = { - events: { - responses: [] + for await (const update of updatesGenerator) { + logger.debug('> friendship update received, sending: ', { update: update as any }) + const updateToResponse = parseEmittedUpdateToFriendshipUpdate(update) + if (updateToResponse) { + yield updateToResponse + } else { + logger.error('> unable to parse update to FriendshipUpdate > ', { update: update as any }) } } - yield response } return generator() @@ -76,5 +291,27 @@ export default function createRpcServerComponent(components: Pick { + try { + const update = JSON.parse(message) as SubscriptionEventsEmitter['update'] + const updateEmitter = SHARED_CONTEXT.subscribers[update.to] + if (updateEmitter) { + updateEmitter.emit('update', update) + } + } catch (error) { + logger.error(error as any) + } + }) + }, + attachUser({ transport, address }) { + transport.on('close', () => { + if (SHARED_CONTEXT.subscribers[address]) { + delete SHARED_CONTEXT.subscribers[address] + } + }) + server.attachTransport(transport, { subscribers: SHARED_CONTEXT.subscribers, address }) + } + } } diff --git a/src/components.ts b/src/components.ts index e2ed54e..7d9123e 100644 --- a/src/components.ts +++ b/src/components.ts @@ -7,13 +7,15 @@ import { } from '@well-known-components/http-server' import { createLogComponent } from '@well-known-components/logger' import { createMetricsComponent } from '@well-known-components/metrics' +import { createFetchComponent } from '@well-known-components/fetch-component' +import { createPgComponent } from '@well-known-components/pg-component' import { AppComponents, GlobalContext } from './types' import { metricDeclarations } from './metrics' -import { createPgComponent } from '@well-known-components/pg-component' import { createDBComponent } from './adapters/db' import { createWsComponent } from './adapters/ws' import createRpcServerComponent from './adapters/rpcServer' -import { createFetchComponent } from '@well-known-components/fetch-component' +import createRedisComponent from './adapters/redis' +import createPubSubComponent from './adapters/pubsub' // Initialize all the components of the app export async function initComponents(): Promise { @@ -24,7 +26,6 @@ export async function initComponents(): Promise { const ws = await createWsComponent() const server = await createServerComponent({ config, logs, ws: ws.ws }, {}) const statusChecks = await createStatusCheckComponent({ server, config }) - const rpcServer = createRpcServerComponent({ logs }) const fetcher = createFetchComponent() @@ -53,6 +54,10 @@ export async function initComponents(): Promise { const db = createDBComponent({ pg, logs }) + const redis = await createRedisComponent({ logs, config }) + const pubsub = createPubSubComponent({ logs, redis }) + const rpcServer = await createRpcServerComponent({ logs, db, pubsub }) + await instrumentHttpServerWithPromClientRegistry({ metrics, server, config, registry: metrics.registry! }) return { @@ -64,7 +69,9 @@ export async function initComponents(): Promise { pg, db, ws, - rpcServer, - fetcher + fetcher, + redis, + pubsub, + rpcServer } } diff --git a/src/controllers/handlers/ws-handler.ts b/src/controllers/handlers/ws-handler.ts index 2ac23d9..abb3dac 100644 --- a/src/controllers/handlers/ws-handler.ts +++ b/src/controllers/handlers/ws-handler.ts @@ -5,6 +5,7 @@ import { WebSocketTransport } from '@dcl/rpc/dist/transports/WebSocket' import future from 'fp-future' import { verify } from '@dcl/platform-crypto-middleware' import { GlobalContext } from '../../types' +import { normalizeAddress } from '../../utils/address' export async function wsHandler(context: IHttpServerComponent.DefaultContext) { const { logs, rpcServer, fetcher } = context.components @@ -19,7 +20,6 @@ export async function wsHandler(context: IHttpServerComponent.DefaultContext ', { address: authchainVerifyResult.auth }) - rpcServer.attachTransport(wsTransport, { components: context.components, address: authchainVerifyResult.auth }) + const address = normalizeAddress(authchainVerifyResult.auth) + + rpcServer.attachUser({ transport: wsTransport, address }) wsTransport.on('error', (err) => { if (err && err.message) { diff --git a/src/friendships_ea.ts b/src/friendships_ea.ts deleted file mode 100644 index 809002b..0000000 --- a/src/friendships_ea.ts +++ /dev/null @@ -1,2443 +0,0 @@ -/* eslint-disable */ -import Long from "long"; -import _m0 from "protobufjs/minimal"; -import { Empty } from "./google/protobuf/empty"; - -export const protobufPackage = "decentraland.social.friendships_ea"; - -/** This message is a response that is sent from the server to the client */ -export interface FriendshipEventResponse { - request?: RequestResponse | undefined; - accept?: AcceptResponse | undefined; - reject?: RejectResponse | undefined; - delete?: DeleteResponse | undefined; - cancel?: CancelResponse | undefined; -} - -export interface FriendshipEventResponses { - responses: FriendshipEventResponse[]; -} - -export interface FriendshipEventPayload { - request?: RequestPayload | undefined; - accept?: AcceptPayload | undefined; - reject?: RejectPayload | undefined; - delete?: DeletePayload | undefined; - cancel?: CancelPayload | undefined; -} - -export interface User { - address: string; -} - -export interface Users { - users: User[]; -} - -export interface RequestResponse { - user: User | undefined; - createdAt: number; - message?: string | undefined; -} - -export interface RequestPayload { - user: User | undefined; - message?: string | undefined; -} - -export interface Requests { - /** Total amount of friendship requests */ - total: number; - items: RequestResponse[]; -} - -export interface RequestEvents { - /** Requests the authed user have sent to users */ - outgoing: - | Requests - | undefined; - /** Requests the authed user have received from users */ - incoming: Requests | undefined; -} - -export interface AcceptResponse { - user: User | undefined; -} - -export interface AcceptPayload { - user: User | undefined; -} - -export interface RejectResponse { - user: User | undefined; -} - -export interface RejectPayload { - user: User | undefined; -} - -export interface DeleteResponse { - user: User | undefined; -} - -export interface DeletePayload { - user: User | undefined; -} - -export interface CancelResponse { - user: User | undefined; -} - -export interface CancelPayload { - user: User | undefined; -} - -export interface UpdateFriendshipPayload { - event: FriendshipEventPayload | undefined; -} - -export interface MutualFriendsPayload { - user: User | undefined; -} - -export interface BadRequestError { - message: string; -} - -export interface UnauthorizedError { - message: string; -} - -export interface ForbiddenError { - message: string; -} - -export interface TooManyRequestsError { - message: string; -} - -export interface InternalServerError { - message: string; -} - -export interface UsersResponse { - users?: Users | undefined; - internalServerError?: InternalServerError | undefined; - unauthorizedError?: UnauthorizedError | undefined; - forbiddenError?: ForbiddenError | undefined; - tooManyRequestsError?: TooManyRequestsError | undefined; - badRequestError?: BadRequestError | undefined; -} - -export interface RequestEventsResponse { - events?: RequestEvents | undefined; - internalServerError?: InternalServerError | undefined; - unauthorizedError?: UnauthorizedError | undefined; - forbiddenError?: ForbiddenError | undefined; - tooManyRequestsError?: TooManyRequestsError | undefined; -} - -export interface UpdateFriendshipResponse { - event?: FriendshipEventResponse | undefined; - internalServerError?: InternalServerError | undefined; - unauthorizedError?: UnauthorizedError | undefined; - forbiddenError?: ForbiddenError | undefined; - tooManyRequestsError?: TooManyRequestsError | undefined; - badRequestError?: BadRequestError | undefined; -} - -export interface SubscribeFriendshipEventsUpdatesResponse { - events?: FriendshipEventResponses | undefined; - internalServerError?: InternalServerError | undefined; - unauthorizedError?: UnauthorizedError | undefined; - forbiddenError?: ForbiddenError | undefined; - tooManyRequestsError?: TooManyRequestsError | undefined; -} - -function createBaseFriendshipEventResponse(): FriendshipEventResponse { - return { request: undefined, accept: undefined, reject: undefined, delete: undefined, cancel: undefined }; -} - -export const FriendshipEventResponse = { - encode(message: FriendshipEventResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.request !== undefined) { - RequestResponse.encode(message.request, writer.uint32(10).fork()).ldelim(); - } - if (message.accept !== undefined) { - AcceptResponse.encode(message.accept, writer.uint32(18).fork()).ldelim(); - } - if (message.reject !== undefined) { - RejectResponse.encode(message.reject, writer.uint32(34).fork()).ldelim(); - } - if (message.delete !== undefined) { - DeleteResponse.encode(message.delete, writer.uint32(42).fork()).ldelim(); - } - if (message.cancel !== undefined) { - CancelResponse.encode(message.cancel, writer.uint32(50).fork()).ldelim(); - } - return writer; - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): FriendshipEventResponse { - const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); - let end = length === undefined ? reader.len : reader.pos + length; - const message = createBaseFriendshipEventResponse(); - while (reader.pos < end) { - const tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - if (tag !== 10) { - break; - } - - message.request = RequestResponse.decode(reader, reader.uint32()); - continue; - case 2: - if (tag !== 18) { - break; - } - - message.accept = AcceptResponse.decode(reader, reader.uint32()); - continue; - case 4: - if (tag !== 34) { - break; - } - - message.reject = RejectResponse.decode(reader, reader.uint32()); - continue; - case 5: - if (tag !== 42) { - break; - } - - message.delete = DeleteResponse.decode(reader, reader.uint32()); - continue; - case 6: - if (tag !== 50) { - break; - } - - message.cancel = CancelResponse.decode(reader, reader.uint32()); - continue; - } - if ((tag & 7) === 4 || tag === 0) { - break; - } - reader.skipType(tag & 7); - } - return message; - }, - - fromJSON(object: any): FriendshipEventResponse { - return { - request: isSet(object.request) ? RequestResponse.fromJSON(object.request) : undefined, - accept: isSet(object.accept) ? AcceptResponse.fromJSON(object.accept) : undefined, - reject: isSet(object.reject) ? RejectResponse.fromJSON(object.reject) : undefined, - delete: isSet(object.delete) ? DeleteResponse.fromJSON(object.delete) : undefined, - cancel: isSet(object.cancel) ? CancelResponse.fromJSON(object.cancel) : undefined, - }; - }, - - toJSON(message: FriendshipEventResponse): unknown { - const obj: any = {}; - if (message.request !== undefined) { - obj.request = RequestResponse.toJSON(message.request); - } - if (message.accept !== undefined) { - obj.accept = AcceptResponse.toJSON(message.accept); - } - if (message.reject !== undefined) { - obj.reject = RejectResponse.toJSON(message.reject); - } - if (message.delete !== undefined) { - obj.delete = DeleteResponse.toJSON(message.delete); - } - if (message.cancel !== undefined) { - obj.cancel = CancelResponse.toJSON(message.cancel); - } - return obj; - }, - - create, I>>(base?: I): FriendshipEventResponse { - return FriendshipEventResponse.fromPartial(base ?? ({} as any)); - }, - fromPartial, I>>(object: I): FriendshipEventResponse { - const message = createBaseFriendshipEventResponse(); - message.request = (object.request !== undefined && object.request !== null) - ? RequestResponse.fromPartial(object.request) - : undefined; - message.accept = (object.accept !== undefined && object.accept !== null) - ? AcceptResponse.fromPartial(object.accept) - : undefined; - message.reject = (object.reject !== undefined && object.reject !== null) - ? RejectResponse.fromPartial(object.reject) - : undefined; - message.delete = (object.delete !== undefined && object.delete !== null) - ? DeleteResponse.fromPartial(object.delete) - : undefined; - message.cancel = (object.cancel !== undefined && object.cancel !== null) - ? CancelResponse.fromPartial(object.cancel) - : undefined; - return message; - }, -}; - -function createBaseFriendshipEventResponses(): FriendshipEventResponses { - return { responses: [] }; -} - -export const FriendshipEventResponses = { - encode(message: FriendshipEventResponses, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - for (const v of message.responses) { - FriendshipEventResponse.encode(v!, writer.uint32(10).fork()).ldelim(); - } - return writer; - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): FriendshipEventResponses { - const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); - let end = length === undefined ? reader.len : reader.pos + length; - const message = createBaseFriendshipEventResponses(); - while (reader.pos < end) { - const tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - if (tag !== 10) { - break; - } - - message.responses.push(FriendshipEventResponse.decode(reader, reader.uint32())); - continue; - } - if ((tag & 7) === 4 || tag === 0) { - break; - } - reader.skipType(tag & 7); - } - return message; - }, - - fromJSON(object: any): FriendshipEventResponses { - return { - responses: globalThis.Array.isArray(object?.responses) - ? object.responses.map((e: any) => FriendshipEventResponse.fromJSON(e)) - : [], - }; - }, - - toJSON(message: FriendshipEventResponses): unknown { - const obj: any = {}; - if (message.responses?.length) { - obj.responses = message.responses.map((e) => FriendshipEventResponse.toJSON(e)); - } - return obj; - }, - - create, I>>(base?: I): FriendshipEventResponses { - return FriendshipEventResponses.fromPartial(base ?? ({} as any)); - }, - fromPartial, I>>(object: I): FriendshipEventResponses { - const message = createBaseFriendshipEventResponses(); - message.responses = object.responses?.map((e) => FriendshipEventResponse.fromPartial(e)) || []; - return message; - }, -}; - -function createBaseFriendshipEventPayload(): FriendshipEventPayload { - return { request: undefined, accept: undefined, reject: undefined, delete: undefined, cancel: undefined }; -} - -export const FriendshipEventPayload = { - encode(message: FriendshipEventPayload, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.request !== undefined) { - RequestPayload.encode(message.request, writer.uint32(10).fork()).ldelim(); - } - if (message.accept !== undefined) { - AcceptPayload.encode(message.accept, writer.uint32(18).fork()).ldelim(); - } - if (message.reject !== undefined) { - RejectPayload.encode(message.reject, writer.uint32(34).fork()).ldelim(); - } - if (message.delete !== undefined) { - DeletePayload.encode(message.delete, writer.uint32(42).fork()).ldelim(); - } - if (message.cancel !== undefined) { - CancelPayload.encode(message.cancel, writer.uint32(50).fork()).ldelim(); - } - return writer; - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): FriendshipEventPayload { - const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); - let end = length === undefined ? reader.len : reader.pos + length; - const message = createBaseFriendshipEventPayload(); - while (reader.pos < end) { - const tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - if (tag !== 10) { - break; - } - - message.request = RequestPayload.decode(reader, reader.uint32()); - continue; - case 2: - if (tag !== 18) { - break; - } - - message.accept = AcceptPayload.decode(reader, reader.uint32()); - continue; - case 4: - if (tag !== 34) { - break; - } - - message.reject = RejectPayload.decode(reader, reader.uint32()); - continue; - case 5: - if (tag !== 42) { - break; - } - - message.delete = DeletePayload.decode(reader, reader.uint32()); - continue; - case 6: - if (tag !== 50) { - break; - } - - message.cancel = CancelPayload.decode(reader, reader.uint32()); - continue; - } - if ((tag & 7) === 4 || tag === 0) { - break; - } - reader.skipType(tag & 7); - } - return message; - }, - - fromJSON(object: any): FriendshipEventPayload { - return { - request: isSet(object.request) ? RequestPayload.fromJSON(object.request) : undefined, - accept: isSet(object.accept) ? AcceptPayload.fromJSON(object.accept) : undefined, - reject: isSet(object.reject) ? RejectPayload.fromJSON(object.reject) : undefined, - delete: isSet(object.delete) ? DeletePayload.fromJSON(object.delete) : undefined, - cancel: isSet(object.cancel) ? CancelPayload.fromJSON(object.cancel) : undefined, - }; - }, - - toJSON(message: FriendshipEventPayload): unknown { - const obj: any = {}; - if (message.request !== undefined) { - obj.request = RequestPayload.toJSON(message.request); - } - if (message.accept !== undefined) { - obj.accept = AcceptPayload.toJSON(message.accept); - } - if (message.reject !== undefined) { - obj.reject = RejectPayload.toJSON(message.reject); - } - if (message.delete !== undefined) { - obj.delete = DeletePayload.toJSON(message.delete); - } - if (message.cancel !== undefined) { - obj.cancel = CancelPayload.toJSON(message.cancel); - } - return obj; - }, - - create, I>>(base?: I): FriendshipEventPayload { - return FriendshipEventPayload.fromPartial(base ?? ({} as any)); - }, - fromPartial, I>>(object: I): FriendshipEventPayload { - const message = createBaseFriendshipEventPayload(); - message.request = (object.request !== undefined && object.request !== null) - ? RequestPayload.fromPartial(object.request) - : undefined; - message.accept = (object.accept !== undefined && object.accept !== null) - ? AcceptPayload.fromPartial(object.accept) - : undefined; - message.reject = (object.reject !== undefined && object.reject !== null) - ? RejectPayload.fromPartial(object.reject) - : undefined; - message.delete = (object.delete !== undefined && object.delete !== null) - ? DeletePayload.fromPartial(object.delete) - : undefined; - message.cancel = (object.cancel !== undefined && object.cancel !== null) - ? CancelPayload.fromPartial(object.cancel) - : undefined; - return message; - }, -}; - -function createBaseUser(): User { - return { address: "" }; -} - -export const User = { - encode(message: User, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.address !== "") { - writer.uint32(10).string(message.address); - } - return writer; - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): User { - const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); - let end = length === undefined ? reader.len : reader.pos + length; - const message = createBaseUser(); - while (reader.pos < end) { - const tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - if (tag !== 10) { - break; - } - - message.address = reader.string(); - continue; - } - if ((tag & 7) === 4 || tag === 0) { - break; - } - reader.skipType(tag & 7); - } - return message; - }, - - fromJSON(object: any): User { - return { address: isSet(object.address) ? globalThis.String(object.address) : "" }; - }, - - toJSON(message: User): unknown { - const obj: any = {}; - if (message.address !== "") { - obj.address = message.address; - } - return obj; - }, - - create, I>>(base?: I): User { - return User.fromPartial(base ?? ({} as any)); - }, - fromPartial, I>>(object: I): User { - const message = createBaseUser(); - message.address = object.address ?? ""; - return message; - }, -}; - -function createBaseUsers(): Users { - return { users: [] }; -} - -export const Users = { - encode(message: Users, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - for (const v of message.users) { - User.encode(v!, writer.uint32(10).fork()).ldelim(); - } - return writer; - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): Users { - const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); - let end = length === undefined ? reader.len : reader.pos + length; - const message = createBaseUsers(); - while (reader.pos < end) { - const tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - if (tag !== 10) { - break; - } - - message.users.push(User.decode(reader, reader.uint32())); - continue; - } - if ((tag & 7) === 4 || tag === 0) { - break; - } - reader.skipType(tag & 7); - } - return message; - }, - - fromJSON(object: any): Users { - return { users: globalThis.Array.isArray(object?.users) ? object.users.map((e: any) => User.fromJSON(e)) : [] }; - }, - - toJSON(message: Users): unknown { - const obj: any = {}; - if (message.users?.length) { - obj.users = message.users.map((e) => User.toJSON(e)); - } - return obj; - }, - - create, I>>(base?: I): Users { - return Users.fromPartial(base ?? ({} as any)); - }, - fromPartial, I>>(object: I): Users { - const message = createBaseUsers(); - message.users = object.users?.map((e) => User.fromPartial(e)) || []; - return message; - }, -}; - -function createBaseRequestResponse(): RequestResponse { - return { user: undefined, createdAt: 0, message: undefined }; -} - -export const RequestResponse = { - encode(message: RequestResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.user !== undefined) { - User.encode(message.user, writer.uint32(10).fork()).ldelim(); - } - if (message.createdAt !== 0) { - writer.uint32(16).int64(message.createdAt); - } - if (message.message !== undefined) { - writer.uint32(26).string(message.message); - } - return writer; - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): RequestResponse { - const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); - let end = length === undefined ? reader.len : reader.pos + length; - const message = createBaseRequestResponse(); - while (reader.pos < end) { - const tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - if (tag !== 10) { - break; - } - - message.user = User.decode(reader, reader.uint32()); - continue; - case 2: - if (tag !== 16) { - break; - } - - message.createdAt = longToNumber(reader.int64() as Long); - continue; - case 3: - if (tag !== 26) { - break; - } - - message.message = reader.string(); - continue; - } - if ((tag & 7) === 4 || tag === 0) { - break; - } - reader.skipType(tag & 7); - } - return message; - }, - - fromJSON(object: any): RequestResponse { - return { - user: isSet(object.user) ? User.fromJSON(object.user) : undefined, - createdAt: isSet(object.createdAt) ? globalThis.Number(object.createdAt) : 0, - message: isSet(object.message) ? globalThis.String(object.message) : undefined, - }; - }, - - toJSON(message: RequestResponse): unknown { - const obj: any = {}; - if (message.user !== undefined) { - obj.user = User.toJSON(message.user); - } - if (message.createdAt !== 0) { - obj.createdAt = Math.round(message.createdAt); - } - if (message.message !== undefined) { - obj.message = message.message; - } - return obj; - }, - - create, I>>(base?: I): RequestResponse { - return RequestResponse.fromPartial(base ?? ({} as any)); - }, - fromPartial, I>>(object: I): RequestResponse { - const message = createBaseRequestResponse(); - message.user = (object.user !== undefined && object.user !== null) ? User.fromPartial(object.user) : undefined; - message.createdAt = object.createdAt ?? 0; - message.message = object.message ?? undefined; - return message; - }, -}; - -function createBaseRequestPayload(): RequestPayload { - return { user: undefined, message: undefined }; -} - -export const RequestPayload = { - encode(message: RequestPayload, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.user !== undefined) { - User.encode(message.user, writer.uint32(10).fork()).ldelim(); - } - if (message.message !== undefined) { - writer.uint32(26).string(message.message); - } - return writer; - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): RequestPayload { - const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); - let end = length === undefined ? reader.len : reader.pos + length; - const message = createBaseRequestPayload(); - while (reader.pos < end) { - const tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - if (tag !== 10) { - break; - } - - message.user = User.decode(reader, reader.uint32()); - continue; - case 3: - if (tag !== 26) { - break; - } - - message.message = reader.string(); - continue; - } - if ((tag & 7) === 4 || tag === 0) { - break; - } - reader.skipType(tag & 7); - } - return message; - }, - - fromJSON(object: any): RequestPayload { - return { - user: isSet(object.user) ? User.fromJSON(object.user) : undefined, - message: isSet(object.message) ? globalThis.String(object.message) : undefined, - }; - }, - - toJSON(message: RequestPayload): unknown { - const obj: any = {}; - if (message.user !== undefined) { - obj.user = User.toJSON(message.user); - } - if (message.message !== undefined) { - obj.message = message.message; - } - return obj; - }, - - create, I>>(base?: I): RequestPayload { - return RequestPayload.fromPartial(base ?? ({} as any)); - }, - fromPartial, I>>(object: I): RequestPayload { - const message = createBaseRequestPayload(); - message.user = (object.user !== undefined && object.user !== null) ? User.fromPartial(object.user) : undefined; - message.message = object.message ?? undefined; - return message; - }, -}; - -function createBaseRequests(): Requests { - return { total: 0, items: [] }; -} - -export const Requests = { - encode(message: Requests, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.total !== 0) { - writer.uint32(8).int64(message.total); - } - for (const v of message.items) { - RequestResponse.encode(v!, writer.uint32(18).fork()).ldelim(); - } - return writer; - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): Requests { - const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); - let end = length === undefined ? reader.len : reader.pos + length; - const message = createBaseRequests(); - while (reader.pos < end) { - const tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - if (tag !== 8) { - break; - } - - message.total = longToNumber(reader.int64() as Long); - continue; - case 2: - if (tag !== 18) { - break; - } - - message.items.push(RequestResponse.decode(reader, reader.uint32())); - continue; - } - if ((tag & 7) === 4 || tag === 0) { - break; - } - reader.skipType(tag & 7); - } - return message; - }, - - fromJSON(object: any): Requests { - return { - total: isSet(object.total) ? globalThis.Number(object.total) : 0, - items: globalThis.Array.isArray(object?.items) ? object.items.map((e: any) => RequestResponse.fromJSON(e)) : [], - }; - }, - - toJSON(message: Requests): unknown { - const obj: any = {}; - if (message.total !== 0) { - obj.total = Math.round(message.total); - } - if (message.items?.length) { - obj.items = message.items.map((e) => RequestResponse.toJSON(e)); - } - return obj; - }, - - create, I>>(base?: I): Requests { - return Requests.fromPartial(base ?? ({} as any)); - }, - fromPartial, I>>(object: I): Requests { - const message = createBaseRequests(); - message.total = object.total ?? 0; - message.items = object.items?.map((e) => RequestResponse.fromPartial(e)) || []; - return message; - }, -}; - -function createBaseRequestEvents(): RequestEvents { - return { outgoing: undefined, incoming: undefined }; -} - -export const RequestEvents = { - encode(message: RequestEvents, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.outgoing !== undefined) { - Requests.encode(message.outgoing, writer.uint32(10).fork()).ldelim(); - } - if (message.incoming !== undefined) { - Requests.encode(message.incoming, writer.uint32(18).fork()).ldelim(); - } - return writer; - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): RequestEvents { - const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); - let end = length === undefined ? reader.len : reader.pos + length; - const message = createBaseRequestEvents(); - while (reader.pos < end) { - const tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - if (tag !== 10) { - break; - } - - message.outgoing = Requests.decode(reader, reader.uint32()); - continue; - case 2: - if (tag !== 18) { - break; - } - - message.incoming = Requests.decode(reader, reader.uint32()); - continue; - } - if ((tag & 7) === 4 || tag === 0) { - break; - } - reader.skipType(tag & 7); - } - return message; - }, - - fromJSON(object: any): RequestEvents { - return { - outgoing: isSet(object.outgoing) ? Requests.fromJSON(object.outgoing) : undefined, - incoming: isSet(object.incoming) ? Requests.fromJSON(object.incoming) : undefined, - }; - }, - - toJSON(message: RequestEvents): unknown { - const obj: any = {}; - if (message.outgoing !== undefined) { - obj.outgoing = Requests.toJSON(message.outgoing); - } - if (message.incoming !== undefined) { - obj.incoming = Requests.toJSON(message.incoming); - } - return obj; - }, - - create, I>>(base?: I): RequestEvents { - return RequestEvents.fromPartial(base ?? ({} as any)); - }, - fromPartial, I>>(object: I): RequestEvents { - const message = createBaseRequestEvents(); - message.outgoing = (object.outgoing !== undefined && object.outgoing !== null) - ? Requests.fromPartial(object.outgoing) - : undefined; - message.incoming = (object.incoming !== undefined && object.incoming !== null) - ? Requests.fromPartial(object.incoming) - : undefined; - return message; - }, -}; - -function createBaseAcceptResponse(): AcceptResponse { - return { user: undefined }; -} - -export const AcceptResponse = { - encode(message: AcceptResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.user !== undefined) { - User.encode(message.user, writer.uint32(10).fork()).ldelim(); - } - return writer; - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): AcceptResponse { - const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); - let end = length === undefined ? reader.len : reader.pos + length; - const message = createBaseAcceptResponse(); - while (reader.pos < end) { - const tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - if (tag !== 10) { - break; - } - - message.user = User.decode(reader, reader.uint32()); - continue; - } - if ((tag & 7) === 4 || tag === 0) { - break; - } - reader.skipType(tag & 7); - } - return message; - }, - - fromJSON(object: any): AcceptResponse { - return { user: isSet(object.user) ? User.fromJSON(object.user) : undefined }; - }, - - toJSON(message: AcceptResponse): unknown { - const obj: any = {}; - if (message.user !== undefined) { - obj.user = User.toJSON(message.user); - } - return obj; - }, - - create, I>>(base?: I): AcceptResponse { - return AcceptResponse.fromPartial(base ?? ({} as any)); - }, - fromPartial, I>>(object: I): AcceptResponse { - const message = createBaseAcceptResponse(); - message.user = (object.user !== undefined && object.user !== null) ? User.fromPartial(object.user) : undefined; - return message; - }, -}; - -function createBaseAcceptPayload(): AcceptPayload { - return { user: undefined }; -} - -export const AcceptPayload = { - encode(message: AcceptPayload, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.user !== undefined) { - User.encode(message.user, writer.uint32(10).fork()).ldelim(); - } - return writer; - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): AcceptPayload { - const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); - let end = length === undefined ? reader.len : reader.pos + length; - const message = createBaseAcceptPayload(); - while (reader.pos < end) { - const tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - if (tag !== 10) { - break; - } - - message.user = User.decode(reader, reader.uint32()); - continue; - } - if ((tag & 7) === 4 || tag === 0) { - break; - } - reader.skipType(tag & 7); - } - return message; - }, - - fromJSON(object: any): AcceptPayload { - return { user: isSet(object.user) ? User.fromJSON(object.user) : undefined }; - }, - - toJSON(message: AcceptPayload): unknown { - const obj: any = {}; - if (message.user !== undefined) { - obj.user = User.toJSON(message.user); - } - return obj; - }, - - create, I>>(base?: I): AcceptPayload { - return AcceptPayload.fromPartial(base ?? ({} as any)); - }, - fromPartial, I>>(object: I): AcceptPayload { - const message = createBaseAcceptPayload(); - message.user = (object.user !== undefined && object.user !== null) ? User.fromPartial(object.user) : undefined; - return message; - }, -}; - -function createBaseRejectResponse(): RejectResponse { - return { user: undefined }; -} - -export const RejectResponse = { - encode(message: RejectResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.user !== undefined) { - User.encode(message.user, writer.uint32(10).fork()).ldelim(); - } - return writer; - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): RejectResponse { - const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); - let end = length === undefined ? reader.len : reader.pos + length; - const message = createBaseRejectResponse(); - while (reader.pos < end) { - const tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - if (tag !== 10) { - break; - } - - message.user = User.decode(reader, reader.uint32()); - continue; - } - if ((tag & 7) === 4 || tag === 0) { - break; - } - reader.skipType(tag & 7); - } - return message; - }, - - fromJSON(object: any): RejectResponse { - return { user: isSet(object.user) ? User.fromJSON(object.user) : undefined }; - }, - - toJSON(message: RejectResponse): unknown { - const obj: any = {}; - if (message.user !== undefined) { - obj.user = User.toJSON(message.user); - } - return obj; - }, - - create, I>>(base?: I): RejectResponse { - return RejectResponse.fromPartial(base ?? ({} as any)); - }, - fromPartial, I>>(object: I): RejectResponse { - const message = createBaseRejectResponse(); - message.user = (object.user !== undefined && object.user !== null) ? User.fromPartial(object.user) : undefined; - return message; - }, -}; - -function createBaseRejectPayload(): RejectPayload { - return { user: undefined }; -} - -export const RejectPayload = { - encode(message: RejectPayload, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.user !== undefined) { - User.encode(message.user, writer.uint32(10).fork()).ldelim(); - } - return writer; - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): RejectPayload { - const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); - let end = length === undefined ? reader.len : reader.pos + length; - const message = createBaseRejectPayload(); - while (reader.pos < end) { - const tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - if (tag !== 10) { - break; - } - - message.user = User.decode(reader, reader.uint32()); - continue; - } - if ((tag & 7) === 4 || tag === 0) { - break; - } - reader.skipType(tag & 7); - } - return message; - }, - - fromJSON(object: any): RejectPayload { - return { user: isSet(object.user) ? User.fromJSON(object.user) : undefined }; - }, - - toJSON(message: RejectPayload): unknown { - const obj: any = {}; - if (message.user !== undefined) { - obj.user = User.toJSON(message.user); - } - return obj; - }, - - create, I>>(base?: I): RejectPayload { - return RejectPayload.fromPartial(base ?? ({} as any)); - }, - fromPartial, I>>(object: I): RejectPayload { - const message = createBaseRejectPayload(); - message.user = (object.user !== undefined && object.user !== null) ? User.fromPartial(object.user) : undefined; - return message; - }, -}; - -function createBaseDeleteResponse(): DeleteResponse { - return { user: undefined }; -} - -export const DeleteResponse = { - encode(message: DeleteResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.user !== undefined) { - User.encode(message.user, writer.uint32(10).fork()).ldelim(); - } - return writer; - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): DeleteResponse { - const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); - let end = length === undefined ? reader.len : reader.pos + length; - const message = createBaseDeleteResponse(); - while (reader.pos < end) { - const tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - if (tag !== 10) { - break; - } - - message.user = User.decode(reader, reader.uint32()); - continue; - } - if ((tag & 7) === 4 || tag === 0) { - break; - } - reader.skipType(tag & 7); - } - return message; - }, - - fromJSON(object: any): DeleteResponse { - return { user: isSet(object.user) ? User.fromJSON(object.user) : undefined }; - }, - - toJSON(message: DeleteResponse): unknown { - const obj: any = {}; - if (message.user !== undefined) { - obj.user = User.toJSON(message.user); - } - return obj; - }, - - create, I>>(base?: I): DeleteResponse { - return DeleteResponse.fromPartial(base ?? ({} as any)); - }, - fromPartial, I>>(object: I): DeleteResponse { - const message = createBaseDeleteResponse(); - message.user = (object.user !== undefined && object.user !== null) ? User.fromPartial(object.user) : undefined; - return message; - }, -}; - -function createBaseDeletePayload(): DeletePayload { - return { user: undefined }; -} - -export const DeletePayload = { - encode(message: DeletePayload, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.user !== undefined) { - User.encode(message.user, writer.uint32(10).fork()).ldelim(); - } - return writer; - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): DeletePayload { - const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); - let end = length === undefined ? reader.len : reader.pos + length; - const message = createBaseDeletePayload(); - while (reader.pos < end) { - const tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - if (tag !== 10) { - break; - } - - message.user = User.decode(reader, reader.uint32()); - continue; - } - if ((tag & 7) === 4 || tag === 0) { - break; - } - reader.skipType(tag & 7); - } - return message; - }, - - fromJSON(object: any): DeletePayload { - return { user: isSet(object.user) ? User.fromJSON(object.user) : undefined }; - }, - - toJSON(message: DeletePayload): unknown { - const obj: any = {}; - if (message.user !== undefined) { - obj.user = User.toJSON(message.user); - } - return obj; - }, - - create, I>>(base?: I): DeletePayload { - return DeletePayload.fromPartial(base ?? ({} as any)); - }, - fromPartial, I>>(object: I): DeletePayload { - const message = createBaseDeletePayload(); - message.user = (object.user !== undefined && object.user !== null) ? User.fromPartial(object.user) : undefined; - return message; - }, -}; - -function createBaseCancelResponse(): CancelResponse { - return { user: undefined }; -} - -export const CancelResponse = { - encode(message: CancelResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.user !== undefined) { - User.encode(message.user, writer.uint32(10).fork()).ldelim(); - } - return writer; - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): CancelResponse { - const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); - let end = length === undefined ? reader.len : reader.pos + length; - const message = createBaseCancelResponse(); - while (reader.pos < end) { - const tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - if (tag !== 10) { - break; - } - - message.user = User.decode(reader, reader.uint32()); - continue; - } - if ((tag & 7) === 4 || tag === 0) { - break; - } - reader.skipType(tag & 7); - } - return message; - }, - - fromJSON(object: any): CancelResponse { - return { user: isSet(object.user) ? User.fromJSON(object.user) : undefined }; - }, - - toJSON(message: CancelResponse): unknown { - const obj: any = {}; - if (message.user !== undefined) { - obj.user = User.toJSON(message.user); - } - return obj; - }, - - create, I>>(base?: I): CancelResponse { - return CancelResponse.fromPartial(base ?? ({} as any)); - }, - fromPartial, I>>(object: I): CancelResponse { - const message = createBaseCancelResponse(); - message.user = (object.user !== undefined && object.user !== null) ? User.fromPartial(object.user) : undefined; - return message; - }, -}; - -function createBaseCancelPayload(): CancelPayload { - return { user: undefined }; -} - -export const CancelPayload = { - encode(message: CancelPayload, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.user !== undefined) { - User.encode(message.user, writer.uint32(10).fork()).ldelim(); - } - return writer; - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): CancelPayload { - const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); - let end = length === undefined ? reader.len : reader.pos + length; - const message = createBaseCancelPayload(); - while (reader.pos < end) { - const tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - if (tag !== 10) { - break; - } - - message.user = User.decode(reader, reader.uint32()); - continue; - } - if ((tag & 7) === 4 || tag === 0) { - break; - } - reader.skipType(tag & 7); - } - return message; - }, - - fromJSON(object: any): CancelPayload { - return { user: isSet(object.user) ? User.fromJSON(object.user) : undefined }; - }, - - toJSON(message: CancelPayload): unknown { - const obj: any = {}; - if (message.user !== undefined) { - obj.user = User.toJSON(message.user); - } - return obj; - }, - - create, I>>(base?: I): CancelPayload { - return CancelPayload.fromPartial(base ?? ({} as any)); - }, - fromPartial, I>>(object: I): CancelPayload { - const message = createBaseCancelPayload(); - message.user = (object.user !== undefined && object.user !== null) ? User.fromPartial(object.user) : undefined; - return message; - }, -}; - -function createBaseUpdateFriendshipPayload(): UpdateFriendshipPayload { - return { event: undefined }; -} - -export const UpdateFriendshipPayload = { - encode(message: UpdateFriendshipPayload, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.event !== undefined) { - FriendshipEventPayload.encode(message.event, writer.uint32(10).fork()).ldelim(); - } - return writer; - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): UpdateFriendshipPayload { - const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); - let end = length === undefined ? reader.len : reader.pos + length; - const message = createBaseUpdateFriendshipPayload(); - while (reader.pos < end) { - const tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - if (tag !== 10) { - break; - } - - message.event = FriendshipEventPayload.decode(reader, reader.uint32()); - continue; - } - if ((tag & 7) === 4 || tag === 0) { - break; - } - reader.skipType(tag & 7); - } - return message; - }, - - fromJSON(object: any): UpdateFriendshipPayload { - return { event: isSet(object.event) ? FriendshipEventPayload.fromJSON(object.event) : undefined }; - }, - - toJSON(message: UpdateFriendshipPayload): unknown { - const obj: any = {}; - if (message.event !== undefined) { - obj.event = FriendshipEventPayload.toJSON(message.event); - } - return obj; - }, - - create, I>>(base?: I): UpdateFriendshipPayload { - return UpdateFriendshipPayload.fromPartial(base ?? ({} as any)); - }, - fromPartial, I>>(object: I): UpdateFriendshipPayload { - const message = createBaseUpdateFriendshipPayload(); - message.event = (object.event !== undefined && object.event !== null) - ? FriendshipEventPayload.fromPartial(object.event) - : undefined; - return message; - }, -}; - -function createBaseMutualFriendsPayload(): MutualFriendsPayload { - return { user: undefined }; -} - -export const MutualFriendsPayload = { - encode(message: MutualFriendsPayload, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.user !== undefined) { - User.encode(message.user, writer.uint32(10).fork()).ldelim(); - } - return writer; - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): MutualFriendsPayload { - const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); - let end = length === undefined ? reader.len : reader.pos + length; - const message = createBaseMutualFriendsPayload(); - while (reader.pos < end) { - const tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - if (tag !== 10) { - break; - } - - message.user = User.decode(reader, reader.uint32()); - continue; - } - if ((tag & 7) === 4 || tag === 0) { - break; - } - reader.skipType(tag & 7); - } - return message; - }, - - fromJSON(object: any): MutualFriendsPayload { - return { user: isSet(object.user) ? User.fromJSON(object.user) : undefined }; - }, - - toJSON(message: MutualFriendsPayload): unknown { - const obj: any = {}; - if (message.user !== undefined) { - obj.user = User.toJSON(message.user); - } - return obj; - }, - - create, I>>(base?: I): MutualFriendsPayload { - return MutualFriendsPayload.fromPartial(base ?? ({} as any)); - }, - fromPartial, I>>(object: I): MutualFriendsPayload { - const message = createBaseMutualFriendsPayload(); - message.user = (object.user !== undefined && object.user !== null) ? User.fromPartial(object.user) : undefined; - return message; - }, -}; - -function createBaseBadRequestError(): BadRequestError { - return { message: "" }; -} - -export const BadRequestError = { - encode(message: BadRequestError, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.message !== "") { - writer.uint32(10).string(message.message); - } - return writer; - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): BadRequestError { - const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); - let end = length === undefined ? reader.len : reader.pos + length; - const message = createBaseBadRequestError(); - while (reader.pos < end) { - const tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - if (tag !== 10) { - break; - } - - message.message = reader.string(); - continue; - } - if ((tag & 7) === 4 || tag === 0) { - break; - } - reader.skipType(tag & 7); - } - return message; - }, - - fromJSON(object: any): BadRequestError { - return { message: isSet(object.message) ? globalThis.String(object.message) : "" }; - }, - - toJSON(message: BadRequestError): unknown { - const obj: any = {}; - if (message.message !== "") { - obj.message = message.message; - } - return obj; - }, - - create, I>>(base?: I): BadRequestError { - return BadRequestError.fromPartial(base ?? ({} as any)); - }, - fromPartial, I>>(object: I): BadRequestError { - const message = createBaseBadRequestError(); - message.message = object.message ?? ""; - return message; - }, -}; - -function createBaseUnauthorizedError(): UnauthorizedError { - return { message: "" }; -} - -export const UnauthorizedError = { - encode(message: UnauthorizedError, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.message !== "") { - writer.uint32(10).string(message.message); - } - return writer; - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): UnauthorizedError { - const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); - let end = length === undefined ? reader.len : reader.pos + length; - const message = createBaseUnauthorizedError(); - while (reader.pos < end) { - const tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - if (tag !== 10) { - break; - } - - message.message = reader.string(); - continue; - } - if ((tag & 7) === 4 || tag === 0) { - break; - } - reader.skipType(tag & 7); - } - return message; - }, - - fromJSON(object: any): UnauthorizedError { - return { message: isSet(object.message) ? globalThis.String(object.message) : "" }; - }, - - toJSON(message: UnauthorizedError): unknown { - const obj: any = {}; - if (message.message !== "") { - obj.message = message.message; - } - return obj; - }, - - create, I>>(base?: I): UnauthorizedError { - return UnauthorizedError.fromPartial(base ?? ({} as any)); - }, - fromPartial, I>>(object: I): UnauthorizedError { - const message = createBaseUnauthorizedError(); - message.message = object.message ?? ""; - return message; - }, -}; - -function createBaseForbiddenError(): ForbiddenError { - return { message: "" }; -} - -export const ForbiddenError = { - encode(message: ForbiddenError, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.message !== "") { - writer.uint32(10).string(message.message); - } - return writer; - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): ForbiddenError { - const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); - let end = length === undefined ? reader.len : reader.pos + length; - const message = createBaseForbiddenError(); - while (reader.pos < end) { - const tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - if (tag !== 10) { - break; - } - - message.message = reader.string(); - continue; - } - if ((tag & 7) === 4 || tag === 0) { - break; - } - reader.skipType(tag & 7); - } - return message; - }, - - fromJSON(object: any): ForbiddenError { - return { message: isSet(object.message) ? globalThis.String(object.message) : "" }; - }, - - toJSON(message: ForbiddenError): unknown { - const obj: any = {}; - if (message.message !== "") { - obj.message = message.message; - } - return obj; - }, - - create, I>>(base?: I): ForbiddenError { - return ForbiddenError.fromPartial(base ?? ({} as any)); - }, - fromPartial, I>>(object: I): ForbiddenError { - const message = createBaseForbiddenError(); - message.message = object.message ?? ""; - return message; - }, -}; - -function createBaseTooManyRequestsError(): TooManyRequestsError { - return { message: "" }; -} - -export const TooManyRequestsError = { - encode(message: TooManyRequestsError, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.message !== "") { - writer.uint32(10).string(message.message); - } - return writer; - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): TooManyRequestsError { - const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); - let end = length === undefined ? reader.len : reader.pos + length; - const message = createBaseTooManyRequestsError(); - while (reader.pos < end) { - const tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - if (tag !== 10) { - break; - } - - message.message = reader.string(); - continue; - } - if ((tag & 7) === 4 || tag === 0) { - break; - } - reader.skipType(tag & 7); - } - return message; - }, - - fromJSON(object: any): TooManyRequestsError { - return { message: isSet(object.message) ? globalThis.String(object.message) : "" }; - }, - - toJSON(message: TooManyRequestsError): unknown { - const obj: any = {}; - if (message.message !== "") { - obj.message = message.message; - } - return obj; - }, - - create, I>>(base?: I): TooManyRequestsError { - return TooManyRequestsError.fromPartial(base ?? ({} as any)); - }, - fromPartial, I>>(object: I): TooManyRequestsError { - const message = createBaseTooManyRequestsError(); - message.message = object.message ?? ""; - return message; - }, -}; - -function createBaseInternalServerError(): InternalServerError { - return { message: "" }; -} - -export const InternalServerError = { - encode(message: InternalServerError, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.message !== "") { - writer.uint32(10).string(message.message); - } - return writer; - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): InternalServerError { - const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); - let end = length === undefined ? reader.len : reader.pos + length; - const message = createBaseInternalServerError(); - while (reader.pos < end) { - const tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - if (tag !== 10) { - break; - } - - message.message = reader.string(); - continue; - } - if ((tag & 7) === 4 || tag === 0) { - break; - } - reader.skipType(tag & 7); - } - return message; - }, - - fromJSON(object: any): InternalServerError { - return { message: isSet(object.message) ? globalThis.String(object.message) : "" }; - }, - - toJSON(message: InternalServerError): unknown { - const obj: any = {}; - if (message.message !== "") { - obj.message = message.message; - } - return obj; - }, - - create, I>>(base?: I): InternalServerError { - return InternalServerError.fromPartial(base ?? ({} as any)); - }, - fromPartial, I>>(object: I): InternalServerError { - const message = createBaseInternalServerError(); - message.message = object.message ?? ""; - return message; - }, -}; - -function createBaseUsersResponse(): UsersResponse { - return { - users: undefined, - internalServerError: undefined, - unauthorizedError: undefined, - forbiddenError: undefined, - tooManyRequestsError: undefined, - badRequestError: undefined, - }; -} - -export const UsersResponse = { - encode(message: UsersResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.users !== undefined) { - Users.encode(message.users, writer.uint32(10).fork()).ldelim(); - } - if (message.internalServerError !== undefined) { - InternalServerError.encode(message.internalServerError, writer.uint32(18).fork()).ldelim(); - } - if (message.unauthorizedError !== undefined) { - UnauthorizedError.encode(message.unauthorizedError, writer.uint32(26).fork()).ldelim(); - } - if (message.forbiddenError !== undefined) { - ForbiddenError.encode(message.forbiddenError, writer.uint32(34).fork()).ldelim(); - } - if (message.tooManyRequestsError !== undefined) { - TooManyRequestsError.encode(message.tooManyRequestsError, writer.uint32(42).fork()).ldelim(); - } - if (message.badRequestError !== undefined) { - BadRequestError.encode(message.badRequestError, writer.uint32(50).fork()).ldelim(); - } - return writer; - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): UsersResponse { - const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); - let end = length === undefined ? reader.len : reader.pos + length; - const message = createBaseUsersResponse(); - while (reader.pos < end) { - const tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - if (tag !== 10) { - break; - } - - message.users = Users.decode(reader, reader.uint32()); - continue; - case 2: - if (tag !== 18) { - break; - } - - message.internalServerError = InternalServerError.decode(reader, reader.uint32()); - continue; - case 3: - if (tag !== 26) { - break; - } - - message.unauthorizedError = UnauthorizedError.decode(reader, reader.uint32()); - continue; - case 4: - if (tag !== 34) { - break; - } - - message.forbiddenError = ForbiddenError.decode(reader, reader.uint32()); - continue; - case 5: - if (tag !== 42) { - break; - } - - message.tooManyRequestsError = TooManyRequestsError.decode(reader, reader.uint32()); - continue; - case 6: - if (tag !== 50) { - break; - } - - message.badRequestError = BadRequestError.decode(reader, reader.uint32()); - continue; - } - if ((tag & 7) === 4 || tag === 0) { - break; - } - reader.skipType(tag & 7); - } - return message; - }, - - fromJSON(object: any): UsersResponse { - return { - users: isSet(object.users) ? Users.fromJSON(object.users) : undefined, - internalServerError: isSet(object.internalServerError) - ? InternalServerError.fromJSON(object.internalServerError) - : undefined, - unauthorizedError: isSet(object.unauthorizedError) - ? UnauthorizedError.fromJSON(object.unauthorizedError) - : undefined, - forbiddenError: isSet(object.forbiddenError) ? ForbiddenError.fromJSON(object.forbiddenError) : undefined, - tooManyRequestsError: isSet(object.tooManyRequestsError) - ? TooManyRequestsError.fromJSON(object.tooManyRequestsError) - : undefined, - badRequestError: isSet(object.badRequestError) ? BadRequestError.fromJSON(object.badRequestError) : undefined, - }; - }, - - toJSON(message: UsersResponse): unknown { - const obj: any = {}; - if (message.users !== undefined) { - obj.users = Users.toJSON(message.users); - } - if (message.internalServerError !== undefined) { - obj.internalServerError = InternalServerError.toJSON(message.internalServerError); - } - if (message.unauthorizedError !== undefined) { - obj.unauthorizedError = UnauthorizedError.toJSON(message.unauthorizedError); - } - if (message.forbiddenError !== undefined) { - obj.forbiddenError = ForbiddenError.toJSON(message.forbiddenError); - } - if (message.tooManyRequestsError !== undefined) { - obj.tooManyRequestsError = TooManyRequestsError.toJSON(message.tooManyRequestsError); - } - if (message.badRequestError !== undefined) { - obj.badRequestError = BadRequestError.toJSON(message.badRequestError); - } - return obj; - }, - - create, I>>(base?: I): UsersResponse { - return UsersResponse.fromPartial(base ?? ({} as any)); - }, - fromPartial, I>>(object: I): UsersResponse { - const message = createBaseUsersResponse(); - message.users = (object.users !== undefined && object.users !== null) ? Users.fromPartial(object.users) : undefined; - message.internalServerError = (object.internalServerError !== undefined && object.internalServerError !== null) - ? InternalServerError.fromPartial(object.internalServerError) - : undefined; - message.unauthorizedError = (object.unauthorizedError !== undefined && object.unauthorizedError !== null) - ? UnauthorizedError.fromPartial(object.unauthorizedError) - : undefined; - message.forbiddenError = (object.forbiddenError !== undefined && object.forbiddenError !== null) - ? ForbiddenError.fromPartial(object.forbiddenError) - : undefined; - message.tooManyRequestsError = (object.tooManyRequestsError !== undefined && object.tooManyRequestsError !== null) - ? TooManyRequestsError.fromPartial(object.tooManyRequestsError) - : undefined; - message.badRequestError = (object.badRequestError !== undefined && object.badRequestError !== null) - ? BadRequestError.fromPartial(object.badRequestError) - : undefined; - return message; - }, -}; - -function createBaseRequestEventsResponse(): RequestEventsResponse { - return { - events: undefined, - internalServerError: undefined, - unauthorizedError: undefined, - forbiddenError: undefined, - tooManyRequestsError: undefined, - }; -} - -export const RequestEventsResponse = { - encode(message: RequestEventsResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.events !== undefined) { - RequestEvents.encode(message.events, writer.uint32(10).fork()).ldelim(); - } - if (message.internalServerError !== undefined) { - InternalServerError.encode(message.internalServerError, writer.uint32(18).fork()).ldelim(); - } - if (message.unauthorizedError !== undefined) { - UnauthorizedError.encode(message.unauthorizedError, writer.uint32(26).fork()).ldelim(); - } - if (message.forbiddenError !== undefined) { - ForbiddenError.encode(message.forbiddenError, writer.uint32(34).fork()).ldelim(); - } - if (message.tooManyRequestsError !== undefined) { - TooManyRequestsError.encode(message.tooManyRequestsError, writer.uint32(42).fork()).ldelim(); - } - return writer; - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): RequestEventsResponse { - const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); - let end = length === undefined ? reader.len : reader.pos + length; - const message = createBaseRequestEventsResponse(); - while (reader.pos < end) { - const tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - if (tag !== 10) { - break; - } - - message.events = RequestEvents.decode(reader, reader.uint32()); - continue; - case 2: - if (tag !== 18) { - break; - } - - message.internalServerError = InternalServerError.decode(reader, reader.uint32()); - continue; - case 3: - if (tag !== 26) { - break; - } - - message.unauthorizedError = UnauthorizedError.decode(reader, reader.uint32()); - continue; - case 4: - if (tag !== 34) { - break; - } - - message.forbiddenError = ForbiddenError.decode(reader, reader.uint32()); - continue; - case 5: - if (tag !== 42) { - break; - } - - message.tooManyRequestsError = TooManyRequestsError.decode(reader, reader.uint32()); - continue; - } - if ((tag & 7) === 4 || tag === 0) { - break; - } - reader.skipType(tag & 7); - } - return message; - }, - - fromJSON(object: any): RequestEventsResponse { - return { - events: isSet(object.events) ? RequestEvents.fromJSON(object.events) : undefined, - internalServerError: isSet(object.internalServerError) - ? InternalServerError.fromJSON(object.internalServerError) - : undefined, - unauthorizedError: isSet(object.unauthorizedError) - ? UnauthorizedError.fromJSON(object.unauthorizedError) - : undefined, - forbiddenError: isSet(object.forbiddenError) ? ForbiddenError.fromJSON(object.forbiddenError) : undefined, - tooManyRequestsError: isSet(object.tooManyRequestsError) - ? TooManyRequestsError.fromJSON(object.tooManyRequestsError) - : undefined, - }; - }, - - toJSON(message: RequestEventsResponse): unknown { - const obj: any = {}; - if (message.events !== undefined) { - obj.events = RequestEvents.toJSON(message.events); - } - if (message.internalServerError !== undefined) { - obj.internalServerError = InternalServerError.toJSON(message.internalServerError); - } - if (message.unauthorizedError !== undefined) { - obj.unauthorizedError = UnauthorizedError.toJSON(message.unauthorizedError); - } - if (message.forbiddenError !== undefined) { - obj.forbiddenError = ForbiddenError.toJSON(message.forbiddenError); - } - if (message.tooManyRequestsError !== undefined) { - obj.tooManyRequestsError = TooManyRequestsError.toJSON(message.tooManyRequestsError); - } - return obj; - }, - - create, I>>(base?: I): RequestEventsResponse { - return RequestEventsResponse.fromPartial(base ?? ({} as any)); - }, - fromPartial, I>>(object: I): RequestEventsResponse { - const message = createBaseRequestEventsResponse(); - message.events = (object.events !== undefined && object.events !== null) - ? RequestEvents.fromPartial(object.events) - : undefined; - message.internalServerError = (object.internalServerError !== undefined && object.internalServerError !== null) - ? InternalServerError.fromPartial(object.internalServerError) - : undefined; - message.unauthorizedError = (object.unauthorizedError !== undefined && object.unauthorizedError !== null) - ? UnauthorizedError.fromPartial(object.unauthorizedError) - : undefined; - message.forbiddenError = (object.forbiddenError !== undefined && object.forbiddenError !== null) - ? ForbiddenError.fromPartial(object.forbiddenError) - : undefined; - message.tooManyRequestsError = (object.tooManyRequestsError !== undefined && object.tooManyRequestsError !== null) - ? TooManyRequestsError.fromPartial(object.tooManyRequestsError) - : undefined; - return message; - }, -}; - -function createBaseUpdateFriendshipResponse(): UpdateFriendshipResponse { - return { - event: undefined, - internalServerError: undefined, - unauthorizedError: undefined, - forbiddenError: undefined, - tooManyRequestsError: undefined, - badRequestError: undefined, - }; -} - -export const UpdateFriendshipResponse = { - encode(message: UpdateFriendshipResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.event !== undefined) { - FriendshipEventResponse.encode(message.event, writer.uint32(10).fork()).ldelim(); - } - if (message.internalServerError !== undefined) { - InternalServerError.encode(message.internalServerError, writer.uint32(18).fork()).ldelim(); - } - if (message.unauthorizedError !== undefined) { - UnauthorizedError.encode(message.unauthorizedError, writer.uint32(26).fork()).ldelim(); - } - if (message.forbiddenError !== undefined) { - ForbiddenError.encode(message.forbiddenError, writer.uint32(34).fork()).ldelim(); - } - if (message.tooManyRequestsError !== undefined) { - TooManyRequestsError.encode(message.tooManyRequestsError, writer.uint32(42).fork()).ldelim(); - } - if (message.badRequestError !== undefined) { - BadRequestError.encode(message.badRequestError, writer.uint32(50).fork()).ldelim(); - } - return writer; - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): UpdateFriendshipResponse { - const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); - let end = length === undefined ? reader.len : reader.pos + length; - const message = createBaseUpdateFriendshipResponse(); - while (reader.pos < end) { - const tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - if (tag !== 10) { - break; - } - - message.event = FriendshipEventResponse.decode(reader, reader.uint32()); - continue; - case 2: - if (tag !== 18) { - break; - } - - message.internalServerError = InternalServerError.decode(reader, reader.uint32()); - continue; - case 3: - if (tag !== 26) { - break; - } - - message.unauthorizedError = UnauthorizedError.decode(reader, reader.uint32()); - continue; - case 4: - if (tag !== 34) { - break; - } - - message.forbiddenError = ForbiddenError.decode(reader, reader.uint32()); - continue; - case 5: - if (tag !== 42) { - break; - } - - message.tooManyRequestsError = TooManyRequestsError.decode(reader, reader.uint32()); - continue; - case 6: - if (tag !== 50) { - break; - } - - message.badRequestError = BadRequestError.decode(reader, reader.uint32()); - continue; - } - if ((tag & 7) === 4 || tag === 0) { - break; - } - reader.skipType(tag & 7); - } - return message; - }, - - fromJSON(object: any): UpdateFriendshipResponse { - return { - event: isSet(object.event) ? FriendshipEventResponse.fromJSON(object.event) : undefined, - internalServerError: isSet(object.internalServerError) - ? InternalServerError.fromJSON(object.internalServerError) - : undefined, - unauthorizedError: isSet(object.unauthorizedError) - ? UnauthorizedError.fromJSON(object.unauthorizedError) - : undefined, - forbiddenError: isSet(object.forbiddenError) ? ForbiddenError.fromJSON(object.forbiddenError) : undefined, - tooManyRequestsError: isSet(object.tooManyRequestsError) - ? TooManyRequestsError.fromJSON(object.tooManyRequestsError) - : undefined, - badRequestError: isSet(object.badRequestError) ? BadRequestError.fromJSON(object.badRequestError) : undefined, - }; - }, - - toJSON(message: UpdateFriendshipResponse): unknown { - const obj: any = {}; - if (message.event !== undefined) { - obj.event = FriendshipEventResponse.toJSON(message.event); - } - if (message.internalServerError !== undefined) { - obj.internalServerError = InternalServerError.toJSON(message.internalServerError); - } - if (message.unauthorizedError !== undefined) { - obj.unauthorizedError = UnauthorizedError.toJSON(message.unauthorizedError); - } - if (message.forbiddenError !== undefined) { - obj.forbiddenError = ForbiddenError.toJSON(message.forbiddenError); - } - if (message.tooManyRequestsError !== undefined) { - obj.tooManyRequestsError = TooManyRequestsError.toJSON(message.tooManyRequestsError); - } - if (message.badRequestError !== undefined) { - obj.badRequestError = BadRequestError.toJSON(message.badRequestError); - } - return obj; - }, - - create, I>>(base?: I): UpdateFriendshipResponse { - return UpdateFriendshipResponse.fromPartial(base ?? ({} as any)); - }, - fromPartial, I>>(object: I): UpdateFriendshipResponse { - const message = createBaseUpdateFriendshipResponse(); - message.event = (object.event !== undefined && object.event !== null) - ? FriendshipEventResponse.fromPartial(object.event) - : undefined; - message.internalServerError = (object.internalServerError !== undefined && object.internalServerError !== null) - ? InternalServerError.fromPartial(object.internalServerError) - : undefined; - message.unauthorizedError = (object.unauthorizedError !== undefined && object.unauthorizedError !== null) - ? UnauthorizedError.fromPartial(object.unauthorizedError) - : undefined; - message.forbiddenError = (object.forbiddenError !== undefined && object.forbiddenError !== null) - ? ForbiddenError.fromPartial(object.forbiddenError) - : undefined; - message.tooManyRequestsError = (object.tooManyRequestsError !== undefined && object.tooManyRequestsError !== null) - ? TooManyRequestsError.fromPartial(object.tooManyRequestsError) - : undefined; - message.badRequestError = (object.badRequestError !== undefined && object.badRequestError !== null) - ? BadRequestError.fromPartial(object.badRequestError) - : undefined; - return message; - }, -}; - -function createBaseSubscribeFriendshipEventsUpdatesResponse(): SubscribeFriendshipEventsUpdatesResponse { - return { - events: undefined, - internalServerError: undefined, - unauthorizedError: undefined, - forbiddenError: undefined, - tooManyRequestsError: undefined, - }; -} - -export const SubscribeFriendshipEventsUpdatesResponse = { - encode(message: SubscribeFriendshipEventsUpdatesResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.events !== undefined) { - FriendshipEventResponses.encode(message.events, writer.uint32(10).fork()).ldelim(); - } - if (message.internalServerError !== undefined) { - InternalServerError.encode(message.internalServerError, writer.uint32(18).fork()).ldelim(); - } - if (message.unauthorizedError !== undefined) { - UnauthorizedError.encode(message.unauthorizedError, writer.uint32(26).fork()).ldelim(); - } - if (message.forbiddenError !== undefined) { - ForbiddenError.encode(message.forbiddenError, writer.uint32(34).fork()).ldelim(); - } - if (message.tooManyRequestsError !== undefined) { - TooManyRequestsError.encode(message.tooManyRequestsError, writer.uint32(42).fork()).ldelim(); - } - return writer; - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): SubscribeFriendshipEventsUpdatesResponse { - const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); - let end = length === undefined ? reader.len : reader.pos + length; - const message = createBaseSubscribeFriendshipEventsUpdatesResponse(); - while (reader.pos < end) { - const tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - if (tag !== 10) { - break; - } - - message.events = FriendshipEventResponses.decode(reader, reader.uint32()); - continue; - case 2: - if (tag !== 18) { - break; - } - - message.internalServerError = InternalServerError.decode(reader, reader.uint32()); - continue; - case 3: - if (tag !== 26) { - break; - } - - message.unauthorizedError = UnauthorizedError.decode(reader, reader.uint32()); - continue; - case 4: - if (tag !== 34) { - break; - } - - message.forbiddenError = ForbiddenError.decode(reader, reader.uint32()); - continue; - case 5: - if (tag !== 42) { - break; - } - - message.tooManyRequestsError = TooManyRequestsError.decode(reader, reader.uint32()); - continue; - } - if ((tag & 7) === 4 || tag === 0) { - break; - } - reader.skipType(tag & 7); - } - return message; - }, - - fromJSON(object: any): SubscribeFriendshipEventsUpdatesResponse { - return { - events: isSet(object.events) ? FriendshipEventResponses.fromJSON(object.events) : undefined, - internalServerError: isSet(object.internalServerError) - ? InternalServerError.fromJSON(object.internalServerError) - : undefined, - unauthorizedError: isSet(object.unauthorizedError) - ? UnauthorizedError.fromJSON(object.unauthorizedError) - : undefined, - forbiddenError: isSet(object.forbiddenError) ? ForbiddenError.fromJSON(object.forbiddenError) : undefined, - tooManyRequestsError: isSet(object.tooManyRequestsError) - ? TooManyRequestsError.fromJSON(object.tooManyRequestsError) - : undefined, - }; - }, - - toJSON(message: SubscribeFriendshipEventsUpdatesResponse): unknown { - const obj: any = {}; - if (message.events !== undefined) { - obj.events = FriendshipEventResponses.toJSON(message.events); - } - if (message.internalServerError !== undefined) { - obj.internalServerError = InternalServerError.toJSON(message.internalServerError); - } - if (message.unauthorizedError !== undefined) { - obj.unauthorizedError = UnauthorizedError.toJSON(message.unauthorizedError); - } - if (message.forbiddenError !== undefined) { - obj.forbiddenError = ForbiddenError.toJSON(message.forbiddenError); - } - if (message.tooManyRequestsError !== undefined) { - obj.tooManyRequestsError = TooManyRequestsError.toJSON(message.tooManyRequestsError); - } - return obj; - }, - - create, I>>( - base?: I, - ): SubscribeFriendshipEventsUpdatesResponse { - return SubscribeFriendshipEventsUpdatesResponse.fromPartial(base ?? ({} as any)); - }, - fromPartial, I>>( - object: I, - ): SubscribeFriendshipEventsUpdatesResponse { - const message = createBaseSubscribeFriendshipEventsUpdatesResponse(); - message.events = (object.events !== undefined && object.events !== null) - ? FriendshipEventResponses.fromPartial(object.events) - : undefined; - message.internalServerError = (object.internalServerError !== undefined && object.internalServerError !== null) - ? InternalServerError.fromPartial(object.internalServerError) - : undefined; - message.unauthorizedError = (object.unauthorizedError !== undefined && object.unauthorizedError !== null) - ? UnauthorizedError.fromPartial(object.unauthorizedError) - : undefined; - message.forbiddenError = (object.forbiddenError !== undefined && object.forbiddenError !== null) - ? ForbiddenError.fromPartial(object.forbiddenError) - : undefined; - message.tooManyRequestsError = (object.tooManyRequestsError !== undefined && object.tooManyRequestsError !== null) - ? TooManyRequestsError.fromPartial(object.tooManyRequestsError) - : undefined; - return message; - }, -}; - -export type FriendshipsServiceDefinition = typeof FriendshipsServiceDefinition; -export const FriendshipsServiceDefinition = { - name: "FriendshipsService", - fullName: "decentraland.social.friendships_ea.FriendshipsService", - methods: { - /** Get the list of friends for the authenticated user */ - getFriends: { - name: "GetFriends", - requestType: Empty, - requestStream: false, - responseType: UsersResponse, - responseStream: true, - options: {}, - }, - /** Get the list of mutual friends between the authenticated user and the one in the parameter */ - getMutualFriends: { - name: "GetMutualFriends", - requestType: MutualFriendsPayload, - requestStream: false, - responseType: UsersResponse, - responseStream: true, - options: {}, - }, - /** Get the list of request events for the authenticated user */ - getRequestEvents: { - name: "GetRequestEvents", - requestType: Empty, - requestStream: false, - responseType: RequestEventsResponse, - responseStream: false, - options: {}, - }, - /** Update friendship status: REQUEST, ACCEPT, REJECT, CANCEL, DELETE */ - updateFriendshipEvent: { - name: "UpdateFriendshipEvent", - requestType: UpdateFriendshipPayload, - requestStream: false, - responseType: UpdateFriendshipResponse, - responseStream: false, - options: {}, - }, - /** Subscribe to updates of friendship status: REQUEST, ACCEPT, REJECT, CANCEL, DELETE */ - subscribeFriendshipEventsUpdates: { - name: "SubscribeFriendshipEventsUpdates", - requestType: Empty, - requestStream: false, - responseType: SubscribeFriendshipEventsUpdatesResponse, - responseStream: true, - options: {}, - }, - }, -} as const; - -type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined; - -export type DeepPartial = T extends Builtin ? T - : T extends globalThis.Array ? globalThis.Array> - : T extends ReadonlyArray ? ReadonlyArray> - : T extends {} ? { [K in keyof T]?: DeepPartial } - : Partial; - -type KeysOfUnion = T extends T ? keyof T : never; -export type Exact = P extends Builtin ? P - : P & { [K in keyof P]: Exact } & { [K in Exclude>]: never }; - -function longToNumber(long: Long): number { - if (long.gt(globalThis.Number.MAX_SAFE_INTEGER)) { - throw new globalThis.Error("Value is larger than Number.MAX_SAFE_INTEGER"); - } - return long.toNumber(); -} - -if (_m0.util.Long !== Long) { - _m0.util.Long = Long as any; - _m0.configure(); -} - -function isSet(value: any): boolean { - return value !== null && value !== undefined; -} diff --git a/src/google/protobuf/empty.ts b/src/google/protobuf/empty.ts deleted file mode 100644 index aed6f7c..0000000 --- a/src/google/protobuf/empty.ts +++ /dev/null @@ -1,73 +0,0 @@ -/* eslint-disable */ -import _m0 from "protobufjs/minimal"; - -export const protobufPackage = "google.protobuf"; - -/** - * A generic empty message that you can re-use to avoid defining duplicated - * empty messages in your APIs. A typical example is to use it as the request - * or the response type of an API method. For instance: - * - * service Foo { - * rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); - * } - * - * The JSON representation for `Empty` is empty JSON object `{}`. - */ -export interface Empty { -} - -function createBaseEmpty(): Empty { - return {}; -} - -export const Empty = { - encode(_: Empty, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - return writer; - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): Empty { - const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); - let end = length === undefined ? reader.len : reader.pos + length; - const message = createBaseEmpty(); - while (reader.pos < end) { - const tag = reader.uint32(); - switch (tag >>> 3) { - } - if ((tag & 7) === 4 || tag === 0) { - break; - } - reader.skipType(tag & 7); - } - return message; - }, - - fromJSON(_: any): Empty { - return {}; - }, - - toJSON(_: Empty): unknown { - const obj: any = {}; - return obj; - }, - - create, I>>(base?: I): Empty { - return Empty.fromPartial(base ?? ({} as any)); - }, - fromPartial, I>>(_: I): Empty { - const message = createBaseEmpty(); - return message; - }, -}; - -type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined; - -export type DeepPartial = T extends Builtin ? T - : T extends globalThis.Array ? globalThis.Array> - : T extends ReadonlyArray ? ReadonlyArray> - : T extends {} ? { [K in keyof T]?: DeepPartial } - : Partial; - -type KeysOfUnion = T extends T ? keyof T : never; -export type Exact = P extends Builtin ? P - : P & { [K in keyof P]: Exact } & { [K in Exclude>]: never }; diff --git a/src/logic/friendships.ts b/src/logic/friendships.ts new file mode 100644 index 0000000..6e0320c --- /dev/null +++ b/src/logic/friendships.ts @@ -0,0 +1,175 @@ +import { + FriendshipUpdate, + UpsertFriendshipPayload +} from '@dcl/protocol/out-ts/decentraland/social_service_v2/social_service.gen' +import { + Action, + FRIENDSHIP_ACTION_TRANSITIONS, + FriendshipAction, + FriendshipStatus, + SubscriptionEventsEmitter +} from '../types' +import { normalizeAddress } from '../utils/address' + +export function isFriendshipActionValid(from: Action | null, to: Action) { + return FRIENDSHIP_ACTION_TRANSITIONS[to].includes(from) +} + +export function isUserActionValid( + actingUser: string, + newAction: { action: Action; user: string }, + lastAction?: FriendshipAction +) { + if (!lastAction) { + if (newAction.action === Action.REQUEST && actingUser === newAction.user) return false + + return true + } + + if (lastAction.acting_user === actingUser) { + switch (newAction.action) { + case Action.ACCEPT: + case Action.REJECT: + return false + default: + return true + } + } else { + if (newAction.action === Action.CANCEL) return false + return true + } +} + +export function getNewFriendshipStatus(action: Action) { + switch (action) { + case Action.REQUEST: + return FriendshipStatus.Requested + case Action.ACCEPT: + return FriendshipStatus.Friends + case Action.CANCEL: + case Action.REJECT: + case Action.DELETE: + default: + return FriendshipStatus.NotFriends + } +} + +export function validateNewFriendshipAction( + actingUser: string, + newAction: { action: Action; user: string }, + lastAction?: FriendshipAction +): boolean { + if (!isFriendshipActionValid(lastAction?.action || null, newAction.action)) return false + return isUserActionValid(actingUser, newAction, lastAction) +} + +type CommonParsedRequest = { + action: A + user: string +} + +type ParsedUpsertFriendshipRequest = + | (CommonParsedRequest & { metadata: { message: string } | null }) + | CommonParsedRequest + | CommonParsedRequest + | CommonParsedRequest + | CommonParsedRequest + +export function parseUpsertFriendshipRequest(request: UpsertFriendshipPayload): ParsedUpsertFriendshipRequest | null { + switch (request.action?.$case) { + case 'accept': + return { + action: Action.ACCEPT, + user: normalizeAddress(request.action.accept.user!.address) + } + case 'cancel': + return { + action: Action.CANCEL, + user: normalizeAddress(request.action.cancel.user!.address) + } + case 'delete': + return { + action: Action.DELETE, + user: normalizeAddress(request.action.delete.user!.address) + } + case 'reject': + return { + action: Action.REJECT, + user: normalizeAddress(request.action.reject.user!.address) + } + case 'request': + return { + action: Action.REQUEST, + user: normalizeAddress(request.action.request.user!.address), + metadata: request.action.request.message ? { message: request.action.request.message } : null + } + default: + return null + } +} + +export function parseEmittedUpdateToFriendshipUpdate( + update: SubscriptionEventsEmitter['update'] +): FriendshipUpdate | null { + switch (update.action) { + case Action.REQUEST: + return { + update: { + $case: 'request', + request: { + createdAt: update.timestamp, + user: { + address: update.from + }, + message: update.metadata?.message + } + } + } + case Action.CANCEL: + return { + update: { + $case: 'cancel', + cancel: { + user: { + address: update.from + } + } + } + } + case Action.DELETE: + return { + update: { + $case: 'delete', + delete: { + user: { + address: update.from + } + } + } + } + case Action.REJECT: + return { + update: { + $case: 'reject', + reject: { + user: { + address: update.from + } + } + } + } + case Action.ACCEPT: + return { + update: { + $case: 'accept', + accept: { + user: { + address: update.from + } + } + } + } + default: + return null + } +} diff --git a/src/migrations/1712167263170_friendships-table.ts b/src/migrations/1712167263170_friendships-table.ts index 4427acf..7ec33df 100644 --- a/src/migrations/1712167263170_friendships-table.ts +++ b/src/migrations/1712167263170_friendships-table.ts @@ -16,6 +16,18 @@ export async function up(pgm: MigrationBuilder): Promise { address_requested: { type: PgType.VARCHAR, notNull: true + }, + is_active: { + type: PgType.BOOLEAN, + default: false + }, + created_at: { + type: PgType.TIMESTAMP, + default: pgm.func('now()') + }, + updated_at: { + type: PgType.TIMESTAMP, + default: pgm.func('now()') } }) } diff --git a/src/migrations/1712942549875_friendships-history.ts b/src/migrations/1712942549875_friendships-history.ts new file mode 100644 index 0000000..4cdc8ba --- /dev/null +++ b/src/migrations/1712942549875_friendships-history.ts @@ -0,0 +1,37 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import { MigrationBuilder, ColumnDefinitions, PgType } from 'node-pg-migrate' + +export const shorthands: ColumnDefinitions | undefined = undefined + +export async function up(pgm: MigrationBuilder): Promise { + pgm.createTable('friendship_actions', { + id: { + type: PgType.UUID, + primaryKey: true + }, + friendship_id: { + type: PgType.UUID, + notNull: true + }, + action: { + type: PgType.VARCHAR, + notNull: true + }, + acting_user: { + type: PgType.VARCHAR, + notNull: true + }, + metadata: { + type: PgType.JSON, + notNull: false + }, + timestamp: { + type: PgType.TIMESTAMP, + default: pgm.func('now()') + } + }) +} + +export async function down(pgm: MigrationBuilder): Promise { + pgm.dropTable('friendship_actions') +} diff --git a/src/types.ts b/src/types.ts index de35bc1..7fb052f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -7,10 +7,13 @@ import type { IFetchComponent } from '@well-known-components/interfaces' import { IPgComponent } from '@well-known-components/pg-component' +import { WebSocketServer } from 'ws' +import { Emitter } from 'mitt' import { metricDeclarations } from './metrics' import { IDatabaseComponent } from './adapters/db' -import { WebSocketServer } from 'ws' -import { RpcServer } from '@dcl/rpc' +import { IRedisComponent } from './adapters/redis' +import { IRPCServerComponent } from './adapters/rpcServer' +import { IPubSubComponent } from './adapters/pubsub' export type GlobalContext = { components: BaseComponents @@ -25,8 +28,10 @@ export type BaseComponents = { pg: IPgComponent db: IDatabaseComponent ws: IWebSocketComponent - rpcServer: RpcServer + rpcServer: IRPCServerComponent fetcher: IFetchComponent + redis: IRedisComponent + pubsub: IPubSubComponent } // components used in runtime @@ -57,4 +62,64 @@ export type IWebSocketComponent = IBaseComponent & { ws: WebSocketServer } -export type RpcServerContext = GlobalContext & { address: string } +export type RpcServerContext = { + address: string + subscribers: Record> +} + +export type Friendship = { + id: string + address_requester: string + address_requested: string + is_active: boolean + created_at: string + updated_at: string +} + +export enum Action { + REQUEST = 'request', // request a friendship + CANCEL = 'cancel', // cancel a friendship request + ACCEPT = 'accept', // accept a friendship request + REJECT = 'reject', // reject a friendship request + DELETE = 'delete' // delete a friendship +} + +// [to]: [from] +export const FRIENDSHIP_ACTION_TRANSITIONS: Record = { + [Action.REQUEST]: [Action.CANCEL, Action.REJECT, Action.DELETE, null], + [Action.ACCEPT]: [Action.REQUEST], + [Action.CANCEL]: [Action.REQUEST], + [Action.REJECT]: [Action.REQUEST], + [Action.DELETE]: [Action.ACCEPT] +} + +export type FriendshipAction = { + id: string + friendship_id: string + action: Action + acting_user: string + metadata?: Record + timestamp: string +} + +export enum FriendshipStatus { + Requested, + Friends, + NotFriends +} + +export type FriendshipRequest = { + address: string + timestamp: string + metadata: Record | null +} + +export type SubscriptionEventsEmitter = { + update: { + to: string + from: string + action: Action + timestamp: number + metadata?: { message: string } + } +} diff --git a/src/utils/address.ts b/src/utils/address.ts new file mode 100644 index 0000000..31abf34 --- /dev/null +++ b/src/utils/address.ts @@ -0,0 +1,3 @@ +export function normalizeAddress(address: string) { + return address.toLowerCase() +} diff --git a/src/utils/emitterToGenerator.ts b/src/utils/emitterToGenerator.ts new file mode 100644 index 0000000..f94fd23 --- /dev/null +++ b/src/utils/emitterToGenerator.ts @@ -0,0 +1,58 @@ +import { EventType, Emitter } from 'mitt' + +/** + * Turns an `EventEmitter` into an `AsyncGenerator` + * @param emitter `Emitter` from `mitt` package + * @param event type of event to listen to + * @returns `AsyncGenerator` + */ +export default function emitterToAsyncGenerator, T extends keyof Events>( + emitter: Emitter, + event: T +): AsyncGenerator { + const isDone = false + const nextQueue: { + resolve: (value: IteratorResult | PromiseLike>) => void + reject: (reason?: any) => void + }[] = [] + const valueQueue: Events[T][] = [] + + function eventHandler(value: Events[T]) { + if (nextQueue.length > 0) { + const { resolve } = nextQueue.shift()! + resolve({ done: false, value }) + return + } + valueQueue.push(value) + } + + emitter.on(event, eventHandler) + + return { + [Symbol.asyncIterator]() { + return this + }, + async next() { + if (valueQueue.length) { + const value = valueQueue.shift()! + return { + done: isDone && valueQueue.length === 0, + value + } + } + + return new Promise((resolve, reject) => { + nextQueue.push({ resolve, reject }) + }) + }, + async return(value) { + return { + done: true, + value + } + }, + async throw(e) { + throw e + } + } +} diff --git a/test/unit/friendships.spec.ts b/test/unit/friendships.spec.ts new file mode 100644 index 0000000..6af800e --- /dev/null +++ b/test/unit/friendships.spec.ts @@ -0,0 +1,511 @@ +import { + getNewFriendshipStatus, + isFriendshipActionValid, + isUserActionValid, + parseEmittedUpdateToFriendshipUpdate, + parseUpsertFriendshipRequest, + validateNewFriendshipAction +} from '../../src/logic/friendships' +import { Action, FriendshipStatus } from '../../src/types' + +describe('isFriendshipActionValid()', () => { + test('it should be valid if from is null and to is REQUEST ', () => { + expect(isFriendshipActionValid(null, Action.REQUEST)).toBeTruthy() + }) + + test('it should be valid if from is REQUEST and to is CANCEL ', () => { + expect(isFriendshipActionValid(Action.REQUEST, Action.CANCEL)).toBeTruthy() + }) + + test('it should be valid if from is REQUEST and to is ACCEPT ', () => { + expect(isFriendshipActionValid(Action.REQUEST, Action.ACCEPT)).toBeTruthy() + }) + + test('it should be valid if from is REQUEST and to is REJECT ', () => { + expect(isFriendshipActionValid(Action.REQUEST, Action.REJECT)).toBeTruthy() + }) + + test('it should be valid if from is REQUEST and to is DELETE ', () => { + expect(isFriendshipActionValid(Action.REQUEST, Action.DELETE)).toBeFalsy() + }) + + test('it should NOT be valid if "from" is null and "to" is whatever except REQUEST ', () => { + expect(isFriendshipActionValid(null, Action.ACCEPT)).toBeFalsy() + expect(isFriendshipActionValid(null, Action.DELETE)).toBeFalsy() + expect(isFriendshipActionValid(null, Action.REJECT)).toBeFalsy() + expect(isFriendshipActionValid(null, Action.CANCEL)).toBeFalsy() + }) +}) + +describe('isUserActionValid()', () => { + test('it should NOT be valid if acting user is the targeted user and is sending a REQUEST', () => { + expect(isUserActionValid('0xA', { action: Action.REQUEST, user: '0xA' })).toBeFalsy() + }) + + test('it should be valid if acting user is different to the targeted user and is sending a REQUEST', () => { + expect(isUserActionValid('0xA', { action: Action.REQUEST, user: '0xB' })).toBeTruthy() + }) + + test('it should NOT be valid if last acting user is sending either an ACCEPT or REJECT', () => { + expect( + isUserActionValid( + '0xA', + { action: Action.ACCEPT, user: '0xA' }, + { + id: '1111', + acting_user: '0xA', + action: Action.REQUEST, + friendship_id: '1111', + timestamp: new Date().toISOString() + } + ) + ).toBeFalsy() + expect( + isUserActionValid( + '0xA', + { action: Action.REJECT, user: '0xA' }, + { + id: '1111', + acting_user: '0xA', + action: Action.REQUEST, + friendship_id: '1111', + timestamp: new Date().toISOString() + } + ) + ).toBeFalsy() + }) + + test('it should NOT be valid if acting user is sending a CANCEL but didnt send the REQUEST', () => { + expect( + isUserActionValid( + '0xB', + { action: Action.CANCEL, user: '0xA' }, + { + id: '1111', + acting_user: '0xA', + action: Action.REQUEST, + friendship_id: '1111', + timestamp: new Date().toISOString() + } + ) + ).toBeFalsy() + }) + + test('it should be valid if acting user is sending a CANCEL after sending a REQUEST', () => { + expect( + isUserActionValid( + '0xA', + { action: Action.CANCEL, user: '0xB' }, + { + id: '1111', + acting_user: '0xA', + action: Action.REQUEST, + friendship_id: '1111', + timestamp: new Date().toISOString() + } + ) + ).toBeTruthy() + }) +}) + +describe('getNewFriendshipStatus()', () => { + test('it should be FriendshipStatus.Requested', () => { + expect(getNewFriendshipStatus(Action.REQUEST)).toBe(FriendshipStatus.Requested) + }) + + test('it should be FriendshipStatus.Friends', () => { + expect(getNewFriendshipStatus(Action.ACCEPT)).toBe(FriendshipStatus.Friends) + }) + + test('it should be FriendshipStatus.NotFriends', () => { + expect(getNewFriendshipStatus(Action.CANCEL)).toBe(FriendshipStatus.NotFriends) + expect(getNewFriendshipStatus(Action.DELETE)).toBe(FriendshipStatus.NotFriends) + expect(getNewFriendshipStatus(Action.REJECT)).toBe(FriendshipStatus.NotFriends) + }) +}) + +describe('validateNewFriendshipAction()', () => { + test('it should be a valid friendship action', () => { + expect(validateNewFriendshipAction('0xA', { action: Action.REQUEST, user: '0xB' })).toBeTruthy() + expect( + validateNewFriendshipAction( + '0xB', + { action: Action.ACCEPT, user: '0xA' }, + { + id: '1111', + acting_user: '0xA', + action: Action.REQUEST, + friendship_id: '1111', + timestamp: new Date().toISOString() + } + ) + ).toBeTruthy() + expect( + validateNewFriendshipAction( + '0xA', + { action: Action.CANCEL, user: '0xB' }, + { + id: '1111', + acting_user: '0xA', + action: Action.REQUEST, + friendship_id: '1111', + timestamp: new Date().toISOString() + } + ) + ).toBeTruthy() + expect( + validateNewFriendshipAction( + '0xB', + { action: Action.REJECT, user: '0xA' }, + { + id: '1111', + acting_user: '0xA', + action: Action.REQUEST, + friendship_id: '1111', + timestamp: new Date().toISOString() + } + ) + ).toBeTruthy() + expect( + validateNewFriendshipAction( + '0xA', + { action: Action.DELETE, user: '0xB' }, + { + id: '1111', + acting_user: '0xB', + action: Action.ACCEPT, + friendship_id: '1111', + timestamp: new Date().toISOString() + } + ) + ).toBeTruthy() + }) + + test('it should NOT be a valid friendship action', () => { + expect(validateNewFriendshipAction('0xA', { action: Action.REQUEST, user: '0xA' })).toBeFalsy() + expect( + validateNewFriendshipAction( + '0xA', + { action: Action.DELETE, user: '0xB' }, + { + id: '1111', + acting_user: '0xB', + action: Action.REQUEST, + friendship_id: '1111', + timestamp: new Date().toISOString() + } + ) + ).toBeFalsy() + expect( + validateNewFriendshipAction( + '0xB', + { action: Action.CANCEL, user: '0xA' }, + { + id: '1111', + acting_user: '0xA', + action: Action.REQUEST, + friendship_id: '1111', + timestamp: new Date().toISOString() + } + ) + ).toBeFalsy() + expect( + validateNewFriendshipAction( + '0xA', + { action: Action.REQUEST, user: '0xB' }, + { + id: '1111', + acting_user: '0xA', + action: Action.REQUEST, + friendship_id: '1111', + timestamp: new Date().toISOString() + } + ) + ).toBeFalsy() + expect( + validateNewFriendshipAction( + '0xA', + { action: Action.REJECT, user: '0xB' }, + { + id: '1111', + acting_user: '0xA', + action: Action.ACCEPT, + friendship_id: '1111', + timestamp: new Date().toISOString() + } + ) + ).toBeFalsy() + }) +}) + +describe('parseUpsertFriendshipRequest()', () => { + test('it should parse ACCEPT request properly', () => { + expect( + parseUpsertFriendshipRequest({ + action: { + $case: 'accept', + accept: { + user: { + address: '0xA' + } + } + } + }) + ).toEqual({ + action: Action.ACCEPT, + user: '0xa' + }) + }) + + test('it should parse CANCEL request properly', () => { + expect( + parseUpsertFriendshipRequest({ + action: { + $case: 'cancel', + cancel: { + user: { + address: '0xA' + } + } + } + }) + ).toEqual({ + action: Action.CANCEL, + user: '0xa' + }) + }) + + test('it should parse DELETE request properly', () => { + expect( + parseUpsertFriendshipRequest({ + action: { + $case: 'delete', + delete: { + user: { + address: '0xA' + } + } + } + }) + ).toEqual({ + action: Action.DELETE, + user: '0xa' + }) + }) + + test('it should parse REJECT request properly', () => { + expect( + parseUpsertFriendshipRequest({ + action: { + $case: 'reject', + reject: { + user: { + address: '0xA' + } + } + } + }) + ).toEqual({ + action: Action.REJECT, + user: '0xa' + }) + }) + + test('it should parse REQUEST request properly', () => { + expect( + parseUpsertFriendshipRequest({ + action: { + $case: 'request', + request: { + user: { + address: '0xA' + } + } + } + }) + ).toEqual({ + action: Action.REQUEST, + user: '0xa', + metadata: null + }) + + expect( + parseUpsertFriendshipRequest({ + action: { + $case: 'request', + request: { + user: { + address: '0xA' + }, + message: 'Hi!' + } + } + }) + ).toEqual({ + action: Action.REQUEST, + user: '0xa', + metadata: { + message: 'Hi!' + } + }) + }) + + test('it should return null', () => { + expect( + parseUpsertFriendshipRequest({ + action: { + $case: 'whaterver' as any, + request: { + user: { + address: '0xA' + } + } + } + }) + ).toBe(null) + }) +}) + +describe('parseEmittedUpdateToFriendshipUpdate()', () => { + test('it should parse REQUEST update properly', () => { + const now = Date.now() + expect( + parseEmittedUpdateToFriendshipUpdate({ + action: Action.REQUEST, + timestamp: now, + from: '0xA', + to: '0xB' + }) + ).toEqual({ + update: { + $case: 'request', + request: { + createdAt: now, + user: { + address: '0xA' + }, + message: undefined + } + } + }) + + expect( + parseEmittedUpdateToFriendshipUpdate({ + action: Action.REQUEST, + timestamp: now, + from: '0xA', + to: '0xB', + metadata: { + message: 'Hi!' + } + }) + ).toEqual({ + update: { + $case: 'request', + request: { + createdAt: now, + user: { + address: '0xA' + }, + message: 'Hi!' + } + } + }) + }) + + test('it should parse CANCEL update properly', () => { + const now = Date.now() + expect( + parseEmittedUpdateToFriendshipUpdate({ + action: Action.CANCEL, + timestamp: now, + from: '0xA', + to: '0xB' + }) + ).toEqual({ + update: { + $case: 'cancel', + cancel: { + user: { + address: '0xA' + } + } + } + }) + }) + + test('it should parse DELETE update properly', () => { + const now = Date.now() + expect( + parseEmittedUpdateToFriendshipUpdate({ + action: Action.DELETE, + timestamp: now, + from: '0xA', + to: '0xB' + }) + ).toEqual({ + update: { + $case: 'delete', + delete: { + user: { + address: '0xA' + } + } + } + }) + }) + + test('it should parse REJECT update properly', () => { + const now = Date.now() + expect( + parseEmittedUpdateToFriendshipUpdate({ + action: Action.REJECT, + timestamp: now, + from: '0xA', + to: '0xB' + }) + ).toEqual({ + update: { + $case: 'reject', + reject: { + user: { + address: '0xA' + } + } + } + }) + }) + + test('it should parse ACCEPT update properly', () => { + const now = Date.now() + expect( + parseEmittedUpdateToFriendshipUpdate({ + action: Action.ACCEPT, + timestamp: now, + from: '0xA', + to: '0xB' + }) + ).toEqual({ + update: { + $case: 'accept', + accept: { + user: { + address: '0xA' + } + } + } + }) + }) + + test('it should return null', () => { + const now = Date.now() + expect( + parseEmittedUpdateToFriendshipUpdate({ + action: 'whaterver' as Action, + timestamp: now, + from: '0xA', + to: '0xB' + }) + ).toBe(null) + }) +}) diff --git a/test/unit/seed.spec.ts b/test/unit/seed.spec.ts deleted file mode 100644 index 014429b..0000000 --- a/test/unit/seed.spec.ts +++ /dev/null @@ -1,3 +0,0 @@ -it('seed', () => { - expect(true).toBeTruthy() -}) diff --git a/yarn.lock b/yarn.lock index c4b14a7..e3657ae 100644 --- a/yarn.lock +++ b/yarn.lock @@ -344,10 +344,12 @@ "@well-known-components/fetch-component" "^2.0.2" "@well-known-components/interfaces" "^1.4.2" -"@dcl/protocol@^1.0.0-2569677750.commit-6ce832a": - version "1.0.0-2569677750.commit-6ce832a" - resolved "https://registry.yarnpkg.com/@dcl/protocol/-/protocol-1.0.0-2569677750.commit-6ce832a.tgz#e46fd372802c4434b0460c82effad05bfd824edc" - integrity sha512-PqQ340fVpZsjoSKsCPcaIJj6BcI5p1rJOLKfMyKuX2uGsqxcdh8E/H4/nfx1RO5Cz4V4EDvXhYN7fZ+GV3LnqQ== +"@dcl/protocol@^1.0.0-8789372854.commit-f692c7a": + version "1.0.0-8789372854.commit-f692c7a" + resolved "https://registry.yarnpkg.com/@dcl/protocol/-/protocol-1.0.0-8789372854.commit-f692c7a.tgz#1d817d50852dbbc143e2507d3eb617d1c79f9914" + integrity sha512-emLWfF/8Iciz0nnXFShZXBSbpsdbTHAJuh8st3de5C+4hlNV00Gs5pDBehsxENqHiq9yqL8rDng8EzTXhryAXw== + dependencies: + "@dcl/ts-proto" "1.154.0" "@dcl/rpc@^1.1.2": version "1.1.2" @@ -366,6 +368,19 @@ ajv-errors "^3.0.0" ajv-keywords "^5.1.0" +"@dcl/ts-proto@1.154.0": + version "1.154.0" + resolved "https://registry.yarnpkg.com/@dcl/ts-proto/-/ts-proto-1.154.0.tgz#25cc76d90b148500bf95c7bffde86702fcde3329" + integrity sha512-2S5AKMMPVZrVfa/1WRy4/h0niikcbu3Yf6dCoudh7ScG7BsyKAPC3CMg6IJKHzrmWS593UZClq7YJof6Vt4O+w== + dependencies: + "@types/object-hash" "^3.0.2" + case-anything "^2.1.10" + dataloader "^1.4.0" + object-hash "^3.0.0" + protobufjs "^7.2.4" + ts-poet "^6.4.1" + ts-proto-descriptors "^1.15.0" + "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" @@ -764,6 +779,40 @@ resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== +"@redis/bloom@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@redis/bloom/-/bloom-1.2.0.tgz#d3fd6d3c0af3ef92f26767b56414a370c7b63b71" + integrity sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg== + +"@redis/client@1.5.14": + version "1.5.14" + resolved "https://registry.yarnpkg.com/@redis/client/-/client-1.5.14.tgz#1107893464d092f140d77c468b018a6ed306a180" + integrity sha512-YGn0GqsRBFUQxklhY7v562VMOP0DcmlrHHs3IV1mFE3cbxe31IITUkqhBcIhVSI/2JqtWAJXg5mjV4aU+zD0HA== + dependencies: + cluster-key-slot "1.1.2" + generic-pool "3.9.0" + yallist "4.0.0" + +"@redis/graph@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@redis/graph/-/graph-1.1.1.tgz#8c10df2df7f7d02741866751764031a957a170ea" + integrity sha512-FEMTcTHZozZciLRl6GiiIB4zGm5z5F3F6a6FZCyrfxdKOhFlGkiAqlexWMBzCi4DcRoyiOsuLfW+cjlGWyExOw== + +"@redis/json@1.0.6": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@redis/json/-/json-1.0.6.tgz#b7a7725bbb907765d84c99d55eac3fcf772e180e" + integrity sha512-rcZO3bfQbm2zPRpqo82XbW8zg4G/w4W3tI7X8Mqleq9goQjAGLL7q/1n1ZX4dXEAmORVZ4s1+uKLaUOg7LrUhw== + +"@redis/search@1.1.6": + version "1.1.6" + resolved "https://registry.yarnpkg.com/@redis/search/-/search-1.1.6.tgz#33bcdd791d9ed88ab6910243a355d85a7fedf756" + integrity sha512-mZXCxbTYKBQ3M2lZnEddwEAks0Kc7nauire8q20oA0oA/LoA+E/b5Y5KZn232ztPb1FkIGqo12vh3Lf+Vw5iTw== + +"@redis/time-series@1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@redis/time-series/-/time-series-1.0.5.tgz#a6d70ef7a0e71e083ea09b967df0a0ed742bc6ad" + integrity sha512-IFjIgTusQym2B5IZJG3XKr5llka7ey84fw/NOYqESP5WUfQs9zz1ww/9+qoz4ka/S6KcGBodzlCeZ5UImKbscg== + "@scure/base@~1.1.0": version "1.1.6" resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.6.tgz#8ce5d304b436e4c84f896e0550c83e4d88cb917d" @@ -952,6 +1001,11 @@ dependencies: undici-types "~5.26.4" +"@types/object-hash@^3.0.2": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@types/object-hash/-/object-hash-3.0.6.tgz#25c052428199d374ef723b7b0ed44b5bfe1b3029" + integrity sha512-fOBV8C1FIu2ELinoILQ+ApxcUKz4ngq+IWUYrxSGjXzzjUALijilampwkMgEtJ+h2njAW3pi853QpzNVCHB73w== + "@types/pg@^8.0.0", "@types/pg@^8.6.5": version "8.11.4" resolved "https://registry.npmjs.org/@types/pg/-/pg-8.11.4.tgz" @@ -961,6 +1015,13 @@ pg-protocol "*" pg-types "^4.0.1" +"@types/redis@^4.0.11": + version "4.0.11" + resolved "https://registry.yarnpkg.com/@types/redis/-/redis-4.0.11.tgz#0bb4c11ac9900a21ad40d2a6768ec6aaf651c0e1" + integrity sha512-bI+gth8La8Wg/QCR1+V1fhrL9+LZUSWfcqpOj2Kc80ZQ4ffbdL173vQd5wovmoV9i071FU9oP2g6etLuEwb6Rg== + dependencies: + redis "*" + "@types/semver@^7.5.0": version "7.5.8" resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e" @@ -1438,7 +1499,7 @@ caniuse-lite@^1.0.30001587: resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001599.tgz" integrity sha512-LRAQHZ4yT1+f9LemSMeqdMpMxZcc4RMWdj4tiFe3G8tNkWK+E58g+/tzotb5cU6TbcVJLr4fySiAW7XmxQvZQA== -case-anything@^2.1.13: +case-anything@^2.1.10, case-anything@^2.1.13: version "2.1.13" resolved "https://registry.yarnpkg.com/case-anything/-/case-anything-2.1.13.tgz#0cdc16278cb29a7fcdeb072400da3f342ba329e9" integrity sha512-zlOQ80VrQ2Ue+ymH5OuM/DlDq64mEm+B9UTdHULv5osUMD6HalNTblf2b1u/m6QecjsnOkBpqVZ+XPwIVsy7Ng== @@ -1508,6 +1569,11 @@ cliui@^8.0.1: strip-ansi "^6.0.1" wrap-ansi "^7.0.0" +cluster-key-slot@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz#88ddaa46906e303b5de30d3153b7d9fe0a0c19ac" + integrity sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA== + co@^4.6.0: version "4.6.0" resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz" @@ -1593,6 +1659,11 @@ cross-spawn@^7.0.2, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" +dataloader@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/dataloader/-/dataloader-1.4.0.tgz#bca11d867f5d3f1b9ed9f737bd15970c65dff5c8" + integrity sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw== + debug@^3.2.7: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" @@ -2099,6 +2170,11 @@ function-bind@^1.1.2: resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== +generic-pool@3.9.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/generic-pool/-/generic-pool-3.9.0.tgz#36f4a678e963f4fdb8707eab050823abc4e8f5e4" + integrity sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g== + gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" @@ -2959,7 +3035,7 @@ minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" -mitt@^3.0.0: +mitt@^3.0.0, mitt@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz" integrity sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw== @@ -3057,6 +3133,11 @@ npm-run-path@^4.0.1: dependencies: path-key "^3.0.0" +object-hash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9" + integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw== + obuf@~1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz" @@ -3443,6 +3524,18 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" +redis@*, redis@^4.6.13: + version "4.6.13" + resolved "https://registry.yarnpkg.com/redis/-/redis-4.6.13.tgz#e247267c5f3ba35ab8277b57343d3a56acb2f0a6" + integrity sha512-MHgkS4B+sPjCXpf+HfdetBwbRz6vCtsceTmw1pHNYJAsYxrfpOP6dz+piJWGos8wqG7qb3vj/Rrc5qOlmInUuA== + dependencies: + "@redis/bloom" "1.2.0" + "@redis/client" "1.5.14" + "@redis/graph" "1.1.1" + "@redis/json" "1.0.6" + "@redis/search" "1.1.6" + "@redis/time-series" "1.0.5" + require-directory@^2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" @@ -3596,7 +3689,7 @@ sprintf-js@~1.0.2: sql-template-strings@^2.2.2: version "2.2.2" - resolved "https://registry.npmjs.org/sql-template-strings/-/sql-template-strings-2.2.2.tgz" + resolved "https://registry.yarnpkg.com/sql-template-strings/-/sql-template-strings-2.2.2.tgz#3f11508a25addfce217a3042a9d300c3193b96ff" integrity sha512-UXhXR2869FQaD+GMly8jAMCRZ94nU5KcrFetZfWEMd+LVVG6y0ExgHAhatEcKZ/wk8YcKPdi+hiD2wm75lq3/Q== stack-utils@^2.0.3: @@ -3787,6 +3880,13 @@ ts-node@^10.9.2: v8-compile-cache-lib "^3.0.1" yn "3.1.1" +ts-poet@^6.4.1: + version "6.8.1" + resolved "https://registry.yarnpkg.com/ts-poet/-/ts-poet-6.8.1.tgz#7202e9fda7ad428ae7b42cfa19291e77e23cfc51" + integrity sha512-uqdjJGnQQjBwUeJggUi4o8VhRjUmEdRfo+uqEL+K8w7mKPfLUFAQ1dSURyhFfbA4T/cWPh8Xa7iBgO7jJNsc1A== + dependencies: + dprint-node "^1.0.8" + ts-poet@^6.7.0: version "6.8.0" resolved "https://registry.yarnpkg.com/ts-poet/-/ts-poet-6.8.0.tgz#fb7304165bf84c764b71d471e7ac9c152d4ca586" @@ -3794,7 +3894,7 @@ ts-poet@^6.7.0: dependencies: dprint-node "^1.0.8" -ts-proto-descriptors@1.15.0: +ts-proto-descriptors@1.15.0, ts-proto-descriptors@^1.15.0: version "1.15.0" resolved "https://registry.yarnpkg.com/ts-proto-descriptors/-/ts-proto-descriptors-1.15.0.tgz#e859e3a2887da2d954c552524719b80bdb6ee355" integrity sha512-TYyJ7+H+7Jsqawdv+mfsEpZPTIj9siDHS6EMCzG/z3b/PZiphsX+mWtqFfFVe5/N0Th6V3elK9lQqjnrgTOfrg== @@ -3956,16 +4056,16 @@ y18n@^5.0.5: resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== +yallist@4.0.0, yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + yallist@^3.0.2: version "3.1.1" resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== - yargs-parser@^21.0.0, yargs-parser@^21.0.1, yargs-parser@^21.1.1: version "21.1.1" resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz"