From fbe3b0327c12465147189c0d97ce8ea9c1eb075e Mon Sep 17 00:00:00 2001 From: lendry Date: Thu, 21 May 2026 21:49:32 +0300 Subject: [PATCH] first commit --- .github/workflows/publish-go.yml | 31 ++ .github/workflows/publish-npm.yml | 37 ++ .gitignore | 8 + .npmignore | 10 + gen/glifa/auth/v1/service.ts | 518 +++++++++++++++++++++ gen/glifa/auth/v1/types.ts | 288 ++++++++++++ gen/glifa/channel/v1/service.ts | 307 ++++++++++++ gen/glifa/channel/v1/types.ts | 99 ++++ gen/glifa/common/v1/authz.ts | 42 ++ gen/glifa/common/v1/enums.ts | 63 +++ gen/glifa/common/v1/types.ts | 102 ++++ gen/glifa/core/v1/service.ts | 393 ++++++++++++++++ gen/glifa/core/v1/types.ts | 170 +++++++ gen/glifa/edge/v1/service.ts | 65 +++ gen/glifa/events/v1/auth_events.ts | 127 +++++ gen/glifa/events/v1/channel_events.ts | 87 ++++ gen/glifa/events/v1/core_events.ts | 126 +++++ gen/glifa/events/v1/eventlope.ts | 42 ++ gen/glifa/events/v1/media_events.ts | 61 +++ gen/glifa/media/v1/service.ts | 249 ++++++++++ gen/glifa/media/v1/types.ts | 144 ++++++ gen/glifa/ws/v1/service.ts | 173 +++++++ gen/glifa/ws/v1/types.ts | 101 ++++ gen/google/protobuf/any.ts | 134 ++++++ gen/google/protobuf/struct.ts | 197 ++++++++ gen/google/protobuf/timestamp.ts | 118 +++++ package.json | 27 ++ proto/glifa/auth/v1/service.proto | 235 ++++++++++ proto/glifa/auth/v1/types.proto | 150 ++++++ proto/glifa/channel/v1/service.proto | 146 ++++++ proto/glifa/channel/v1/types.proto | 53 +++ proto/glifa/common/v1/authz.proto | 26 ++ proto/glifa/common/v1/enums.proto | 40 ++ proto/glifa/common/v1/types.proto | 64 +++ proto/glifa/core/v1/service.proto | 187 ++++++++ proto/glifa/core/v1/types.proto | 93 ++++ proto/glifa/edge/v1/service.proto | 30 ++ proto/glifa/events/v1/auth_events.proto | 82 ++++ proto/glifa/events/v1/channel_events.proto | 55 +++ proto/glifa/events/v1/core_events.proto | 78 ++++ proto/glifa/events/v1/eventlope.proto | 24 + proto/glifa/events/v1/media_events.proto | 39 ++ proto/glifa/media/v1/service.proto | 107 +++++ proto/glifa/media/v1/types.proto | 80 ++++ proto/glifa/ws/v1/service.proto | 76 +++ proto/glifa/ws/v1/types.proto | 56 +++ scripts/generate-proto.mjs | 97 ++++ yarn.lock | 86 ++++ 48 files changed, 5523 insertions(+) create mode 100644 .github/workflows/publish-go.yml create mode 100644 .github/workflows/publish-npm.yml create mode 100644 .gitignore create mode 100644 .npmignore create mode 100644 gen/glifa/auth/v1/service.ts create mode 100644 gen/glifa/auth/v1/types.ts create mode 100644 gen/glifa/channel/v1/service.ts create mode 100644 gen/glifa/channel/v1/types.ts create mode 100644 gen/glifa/common/v1/authz.ts create mode 100644 gen/glifa/common/v1/enums.ts create mode 100644 gen/glifa/common/v1/types.ts create mode 100644 gen/glifa/core/v1/service.ts create mode 100644 gen/glifa/core/v1/types.ts create mode 100644 gen/glifa/edge/v1/service.ts create mode 100644 gen/glifa/events/v1/auth_events.ts create mode 100644 gen/glifa/events/v1/channel_events.ts create mode 100644 gen/glifa/events/v1/core_events.ts create mode 100644 gen/glifa/events/v1/eventlope.ts create mode 100644 gen/glifa/events/v1/media_events.ts create mode 100644 gen/glifa/media/v1/service.ts create mode 100644 gen/glifa/media/v1/types.ts create mode 100644 gen/glifa/ws/v1/service.ts create mode 100644 gen/glifa/ws/v1/types.ts create mode 100644 gen/google/protobuf/any.ts create mode 100644 gen/google/protobuf/struct.ts create mode 100644 gen/google/protobuf/timestamp.ts create mode 100644 package.json create mode 100644 proto/glifa/auth/v1/service.proto create mode 100644 proto/glifa/auth/v1/types.proto create mode 100644 proto/glifa/channel/v1/service.proto create mode 100644 proto/glifa/channel/v1/types.proto create mode 100644 proto/glifa/common/v1/authz.proto create mode 100644 proto/glifa/common/v1/enums.proto create mode 100644 proto/glifa/common/v1/types.proto create mode 100644 proto/glifa/core/v1/service.proto create mode 100644 proto/glifa/core/v1/types.proto create mode 100644 proto/glifa/edge/v1/service.proto create mode 100644 proto/glifa/events/v1/auth_events.proto create mode 100644 proto/glifa/events/v1/channel_events.proto create mode 100644 proto/glifa/events/v1/core_events.proto create mode 100644 proto/glifa/events/v1/eventlope.proto create mode 100644 proto/glifa/events/v1/media_events.proto create mode 100644 proto/glifa/media/v1/service.proto create mode 100644 proto/glifa/media/v1/types.proto create mode 100644 proto/glifa/ws/v1/service.proto create mode 100644 proto/glifa/ws/v1/types.proto create mode 100644 scripts/generate-proto.mjs create mode 100644 yarn.lock diff --git a/.github/workflows/publish-go.yml b/.github/workflows/publish-go.yml new file mode 100644 index 0000000..f1aeb4a --- /dev/null +++ b/.github/workflows/publish-go.yml @@ -0,0 +1,31 @@ +name: Publish Go Bindings + +on: + push: + tags: + - "v*.*.*" + +jobs: + publish: + name: Publish Job + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version: 1.23 + + - name: Install protoc + run: sudo apt-get update && sudo apt-get install -y protobuf-compiler + + - name: Install Go protobuf plugin + run: / + go install google.golang.org/protobuf/cmd/protoc-gen-go@latest && \ + go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest + + - name: Generate Go Protobuf + run: go run ./scripts/generate_go.sh diff --git a/.github/workflows/publish-npm.yml b/.github/workflows/publish-npm.yml new file mode 100644 index 0000000..cd6c26c --- /dev/null +++ b/.github/workflows/publish-npm.yml @@ -0,0 +1,37 @@ +name: Publish NPM Package + +on: + push: + branches: + - main + +jobs: + publish: + name: Publish Job + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + registry-url: "https://registry.npmjs.org" + + - name: Install protoc + run: sudo apt-get update && sudo apt-get install -y protobuf-compiler + + - name: Install yarn + run: npm install -g yarn + + - name: Install deps + run: yarn install --frozen-lockfile + + - name: Generate TS Protobuf + run: yarn run generate + + - name: Publish package + run: npm publish + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fa52e45 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +node_modules/ +dist/ +build/ +pnpm-lock.yaml +.env +.DS_Store +.vscode/ +.log \ No newline at end of file diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..7a840d8 --- /dev/null +++ b/.npmignore @@ -0,0 +1,10 @@ +.github/ +*.log +pnpm-lock.yaml +yarn.lock +package-lock.json +node_modules/ +.vscode/ +.idea/ +.DS_Store +Thumbs.db \ No newline at end of file diff --git a/gen/glifa/auth/v1/service.ts b/gen/glifa/auth/v1/service.ts new file mode 100644 index 0000000..5e9c817 --- /dev/null +++ b/gen/glifa/auth/v1/service.ts @@ -0,0 +1,518 @@ +// Code generated by protoc-gen-ts_proto. DO NOT EDIT. +// versions: +// protoc-gen-ts_proto v2.11.8 +// protoc v4.25.9 +// source: glifa/auth/v1/service.proto + +/* eslint-disable */ +import { GrpcMethod, GrpcStreamMethod } from "@nestjs/microservices"; +import { Observable } from "rxjs"; +import { Timestamp } from "../../../google/protobuf/timestamp"; +import { SubjectContext } from "../../common/v1/authz"; +import { PageRequest, PageResponse, RequestMeta } from "../../common/v1/types"; +import { + AuthChallenge, + AuthChallengeDeliveryChannel, + AuthChallengePurpose, + DeviceSession, + DeviceSessionStatus, + LoginChallenge, + QrLoginRequest, + SecurityEvent, + TokenPair, +} from "./types"; + +export const protobufPackage = "glifa.auth.v1"; + +export interface RegisterRequest { + /** Метаданные запроса, такие как идентификатор корреляции, язык и т.д. */ + meta: + | RequestMeta + | undefined; + /** Уникальное имя пользователя, которое будет использоваться для входа в систему */ + username: string; + /** Электронная почта пользователя, которая может использоваться для входа в систему и получения уведомлений */ + email: string; + /** Номер телефона пользователя, который может использоваться для входа в систему и получения уведомлений */ + phone: string; + /** Пароль пользователя, который будет использоваться для аутентификации при входе в систему */ + password: string; + /** Отображаемое имя пользователя, которое будет показываться другим пользователям в системе */ + displayName: string; + /** UUID устройства, с которого пользователь регистрируется, для отслеживания и управления сессиями на разных устройствах */ + deviceId: string; + /** Человекочитаемое название устройства, с которого пользователь регистрируется (например, "iPhone 12", "Windows PC"), для удобства отображения в интерфейсе управления сессиями */ + deviceName: string; + /** Платформа устройства, с которого пользователь регистрируется (например, "iOS", "Android", "Web"), для аналитики и оптимизации работы сессий на разных платформах */ + platform: string; + /** Версия приложения, с которого пользователь регистрируется, для аналитики и оптимизации работы сессий на разных версиях приложения */ + appVersion: string; +} + +export interface RegisterResponse { + /** UUID нового пользователя, который был зарегистрирован */ + userId: string; + /** Пара токенов доступа и обновления, которая может быть использована для аутентификации и управления сессиями */ + tokens: + | TokenPair + | undefined; + /** Данные о сессии, которая была создана для нового пользователя на устройстве, с которого он регистрировался */ + session: DeviceSession | undefined; +} + +export interface LoginWithPasswordRequest { + /** Метаданные запроса, такие как идентификатор корреляции, язык и т.д. */ + meta: + | RequestMeta + | undefined; + /** Имя пользователя, электронная почта или номер телефона, которые пользователь использует для входа в систему */ + login: string; + /** Пароль пользователя, который будет использоваться для аутентификации при входе в систему */ + password: string; + /** UUID устройства, с которого пользователь входит в систему, для отслеживания и управления сессиями на разных устройствах */ + deviceId: string; + /** Человекочитаемое название устройства, с которого пользователь входит в систему (например, "iPhone 12", "Windows PC"), для удобства отображения в интерфейсе управления сессиями */ + deviceName: string; + /** Платформа устройства, с которого пользователь входит в систему (например, "iOS", "Android", "Web"), для аналитики и оптимизации работы сессий на разных платформах */ + platform: string; + /** Версия приложения, с которого пользователь входит в систему, для аналитики и оптимизации работы сессий на разных версиях приложения */ + appVersion: string; +} + +export interface LoginWithPasswordResponse { + /** Пара токенов доступа и обновления, которая может быть использована для аутентификации и управления сессиями, если вход выполнен успешно */ + tokens?: + | TokenPair + | undefined; + /** Данные о вызове второго фактора аутентификации, если он требуется для входа в систему */ + secondFactorRequired?: + | LoginChallenge + | undefined; + /** Данные о сессии, которая была создана для пользователя на устройстве, с которого он входит в систему (может быть полезно для отображения информации о текущей сессии в интерфейсе управления сессиями) */ + session: DeviceSession | undefined; +} + +export interface VerifySecondFactorRequest { + /** Метаданные запроса, такие как идентификатор корреляции, язык и т.д. */ + meta: + | RequestMeta + | undefined; + /** UUID вызова второго фактора аутентификации, который был возвращен при попытке входа в систему */ + loginChallengeId: string; + /** TOTP-код, который пользователь сгенерировал в своем приложении для аутентификации (например, Google Authenticator), для подтверждения второго фактора аутентификации */ + totpCode: string; + /** Код восстановления, который пользователь получил при настройке второго фактора аутентификации, для подтверждения второго фактора аутентификации в случае, если TOTP-коды недоступны */ + recoveryCode: string; +} + +export interface VerifySecondFactorResponse { + /** Пара токенов доступа и обновления, которая может быть использована для аутентификации и управления сессиями, если второй фактор аутентификации был успешно подтвержден */ + tokens: + | TokenPair + | undefined; + /** Данные о сессии, которая была создана для пользователя на устройстве, с которого он входит в систему (может быть полезно для отображения информации о текущей сессии в интерфейсе управления сессиями) */ + session: DeviceSession | undefined; +} + +export interface RefreshSessionRequest { + /** Метаданные запроса, такие как идентификатор корреляции, язык и т.д. */ + meta: + | RequestMeta + | undefined; + /** Токен обновления, который был выдан при аутентификации и может быть использован для получения новой пары токенов доступа и обнов */ + refreshToken: string; +} + +export interface RefreshSessionResponse { + /** Новая пара токенов доступа и обновления, которая может быть использована для аутентификации и управления сессиями, если токен обновления был успешно подтвержден */ + tokens: + | TokenPair + | undefined; + /** Данные о сессии, которая была обновлена для пользователя на устройстве, с которого он входит в систему (может быть полезно для отображения информации о текущей сессии в интерфейсе управления сессиями) */ + session: + | DeviceSession + | undefined; + /** Флаг, указывающий, была ли выполнена ротация всей семьи токенов (т.е. были ли отозваны все другие активные сессии пользователя), что может быть полезно для безопасности и управления сессиями */ + familyRotated: boolean; +} + +export interface LogoutSessionRequest { + /** Метаданные запроса, такие как идентификатор корреляции, язык и т.д. */ + meta: + | RequestMeta + | undefined; + /** UUID сессии, которую пользователь хочет завершить (например, текущая сессия или другая активная сессия на другом устройстве) */ + sessionId: string; +} + +export interface LogoutSessionResponse { + /** Флаг, указывающий, была ли сессия успешно завершена */ + success: boolean; +} + +export interface RevokeSessionRequest { + /** Метаданные запроса, такие как идентификатор корреляции, язык и т.д. */ + meta: + | RequestMeta + | undefined; + /** UUID сессии, которую пользователь хочет отозвать (например, текущая сессия или другая активная сессия на другом устройстве) */ + sessionId: string; + /** Причина отзыва сессии, которая может быть полезна для аудита и безопасности (например, "user_logout", "password_change", "suspicious_activity") */ + reason: string; +} + +export interface RevokeSessionResponse { + /** Данные о сессии, которая была отозвана, включая ее статус и метаданные, что может быть полезно для отображения информации о сессиях в интерфейсе управления сессиями */ + session: DeviceSession | undefined; +} + +export interface LockSessionRequest { + meta: RequestMeta | undefined; + sessionId: string; + reason: string; +} + +export interface LockSessionResponse { + session: DeviceSession | undefined; +} + +export interface UnlockSessionRequest { + /** Метаданные запроса, такие как идентификатор корреляции, язык и т.д. */ + meta: + | RequestMeta + | undefined; + /** UUID сессии, которую пользователь хочет разблок */ + sessionId: string; + /** Пароль пользователя, который будет использоваться для подтверждения личности при разблокировке сессии */ + password?: + | string + | undefined; + /** UUID вызова аутентификационного челленджа, который был отправлен пользователю для подтверждения личности при разблокировке сессии */ + challengeId?: + | string + | undefined; + /** Код из аутентификационного челленджа, который пользователь получил и должен предоставить для подтверждения личности при разблокировке сессии */ + code: string; +} + +export interface UnlockSessionResponse { + /** Данные о сессии, которая была разблокирована, включая ее статус и метаданные, что может быть полезно для отображения информации о сессиях в интерфейсе управления сессиями */ + session: + | DeviceSession + | undefined; + /** Пара токенов доступа и обновления, которая может быть использована для аутентификации и управления сессиями, если разблокировка сессии была успешно подтверждена */ + tokens: TokenPair | undefined; +} + +export interface ValidateAccessTokenRequest { + /** Метаданные запроса, такие как идентификатор корреляции, язык и т.д. */ + meta: + | RequestMeta + | undefined; + /** Токен доступа, который нужно проверить на валидность и получить связанную с ним информацию о сессии и правах доступа */ + accessToken: string; +} + +export interface ValidateAccessTokenResponse { + /** Флаг, указывающий, является ли токен доступа валидным (т.е. не истекшим, не отозванным и правильно подписанным) */ + valid: boolean; + /** UUID пользователя, которому принадлежит этот токен доступа, если он валиден */ + userId: string; + /** UUID сессии, с которой связан этот ток */ + sessionId: string; + /** UUID устройства, с которого был выдан этот токен доступа, если он валиден */ + deviceId: string; + /** Версия токена, которая может быть полезна для управления ротацией токенов и обеспечения безопасности */ + tokenVersion: number; + /** Временная метка истечения срока действия токена доступа, которая может быть полезна для управления сессиями и обеспечения безопасности */ + expiresAt: + | Timestamp + | undefined; + /** Статус сессии, с которой связан этот токен доступа (например, "active", "locked", "revoked"), который может быть полезен для управления сессиями и обеспечения безопасности */ + sessionStatus: DeviceSessionStatus; + /** Контекст субъекта, связанный с этим токеном доступа, который может включать информацию о ролях и правах доступа пользователя для авторизации при доступе к ресурсам системы */ + subject: SubjectContext | undefined; +} + +export interface GetSessionRequest { + /** Метаданные запроса, такие как идентификатор корреляции, язык и т.д. */ + meta: + | RequestMeta + | undefined; + /** UUID сессии, которую пользователь хочет получить */ + sessionId: string; +} + +export interface GetSessionResponse { + /** Данные о запрошенной сессии, включая ее статус и метаданные, что может быть полезно для отображения информации о сессиях в интерфейсе управления сессиями */ + session: DeviceSession | undefined; +} + +export interface ListSessionsRequest { + /** Метаданные запроса, такие как идентификатор корреляции, язык и т.д. */ + meta: + | RequestMeta + | undefined; + /** UUID пользователя, для которого нужно получить список сессий */ + userId: string; +} + +export interface ListSessionsResponse { + /** Список сессий, связанных с указанным пользователем, включая их статус и метаданные, что может быть полезно для отображения информации о сессиях в интерфейсе управления сессиями */ + sessions: DeviceSession[]; +} + +export interface CreateQrLoginRequest { + /** Метаданные запроса, такие как идентификатор корреляции, язык и т.д. */ + meta: + | RequestMeta + | undefined; + /** UUID устройства, с которого пользователь инициирует QR-вход, для отслеживания и управления сессиями на разных устройствах */ + deviceId: string; + /** Человекочитаемое название устройства, с которого пользователь инициирует QR-вход (например, "iPhone 12", "Windows PC"), для удобства отображения в интерфейсе управления сессиями */ + deviceName: string; + /** Платформа устройства, с которого пользователь инициирует QR-вход (например, "iOS", "Android", "Web"), для аналитики и оптимизации работы сессий на разных */ + platform: string; + /** Версия приложения, с которого пользователь инициирует QR-вход, для аналитики и оптимизации работы сессий на разных версиях приложения */ + appVersion: string; +} + +export interface CreateQrLoginResponse { + /** Данные о созданном QR-запросе, включая его UUID и время истечения срока действия, которые могут быть использованы для отображения QR-кода и управления процессом QR-входа */ + request: + | QrLoginRequest + | undefined; + /** Строка, которая может быть сериализована в QR-код и содержит информацию, необходимую для выполнения QR-входа (например, UUID запроса и URL для обмена данными между устройствами) */ + qrPayload: string; +} + +export interface ApproveQrLoginRequest { + /** Метаданные запроса, такие как идентификатор корреляции, язык и т.д. */ + meta: + | RequestMeta + | undefined; + /** UUID QR-запроса, который пользователь хочет одобрить для выполнения QR-входа */ + requestId: string; +} + +export interface ApproveQrLoginResponse { + /** Данные о QR-запросе, который был одобрен, включая его UUID и время истечения срока действия, которые могут быть использованы для управления процессом QR-входа */ + request: QrLoginRequest | undefined; +} + +export interface ExchangeQrLoginRequest { + /** Метаданные запроса, такие как идентификатор корреляции, язык и т.д. */ + meta: + | RequestMeta + | undefined; + /** UUID QR-запроса, который был одобрен и для которого пользователь хочет получить токены доступа и обновления для выполнения QR-входа */ + requestId: string; + /** Доказательство, которое может быть предоставлено пользователем для подтверждения своей личности при обмене QR-запроса на токены доступа и обновления (например, код из аутентификационного челленджа или другой механизм подтверждения) */ + proof: string; +} + +export interface ExchangeQrLoginResponse { + /** Пара токенов доступа и обновления, которая может быть использована для аутентификации и управления сессиями, если обмен QR-запроса был успешно подтвержден */ + tokens: + | TokenPair + | undefined; + /** Данные о сессии, которая была создана для пользователя на устройстве, с которого он выполняет QR-вход (может быть полезно для отображения информации о текущей сессии в интерфейсе управления сессиями) */ + session: DeviceSession | undefined; +} + +export interface SendAuthChallengeRequest { + /** Метаданные запроса, такие как идентификатор корреляции, язык и т.д. */ + meta: + | RequestMeta + | undefined; + /** Цель, на которую должен быть отправлен аутентификационный челлендж (например, электронная почта или номер телефона пользователя) */ + target: string; + /** Цель аутентификационного челленджа, которая может быть полезна для определения типа и содержания челленджа (например, "login", "unlock_session", "verify_identity") */ + purpose: AuthChallengePurpose; + /** Канал доставки аутентификационного челленджа, который может быть полезен для оптимизации процесса доставки и обеспечения безопасности (например, "email", "sms", "push_notification") */ + deliveryChannel: AuthChallengeDeliveryChannel; +} + +export interface SendAuthChallengeResponse { + /** Данные о созданном аутентификационном челлендже, включая его UUID, код и время истечения срока действия, которые могут быть использованы для подтверждения личности пользователя при выполнении различных действий в системе */ + challenge: AuthChallenge | undefined; +} + +export interface VerifyAuthChallengeRequest { + /** Метаданные запроса, такие как идентификатор корреляции, язык и т.д. */ + meta: + | RequestMeta + | undefined; + /** UUID аутентификационного челленджа, который был отправлен пользователю и который он предоставляет для подтверждения своей личности */ + challengeId: string; + /** Код из аутентификационного челленджа, который пользователь получил и должен предоставить для подтверждения своей личности */ + code: string; +} + +export interface VerifyAuthChallengeResponse { + /** Данные о аутентификационном челлендже, который был успешно подтвержден, включая его UUID и время истечения срока действия, которые могут быть использованы для управления процессом подтверждения личности пользователя при выполнении различных действий в системе */ + challenge: + | AuthChallenge + | undefined; + /** Флаг, указывающий, был ли аутентификационный челлендж успешно подтвержден, что может быть полезно для управления процессом подтверждения личности пользователя при выполнении различных действий в системе */ + verified: boolean; +} + +export interface ListSecurityEventsRequest { + /** Метаданные запроса, такие как идентификатор корреляции, язык и т.д. */ + meta: + | RequestMeta + | undefined; + /** UUID пользователя, для которого нужно получить список событий безопасности */ + userId: string; + /** Параметры пагинации (номер страницы и размер страницы) */ + page: PageRequest | undefined; +} + +export interface ListSecurityEventsResponse { + /** Список событий безопасности, связанных с указанным пользователем, включая их тип, время и метаданные, что может быть полезно для отображения информации о безопасности в интерфейсе управления сессиями и обеспечения безопасности */ + events: SecurityEvent[]; + /** Информация о пагинации (номер страницы, размер страницы, общее количество элементов) для списка событий безопасности, что может быть полезно для отображения информации о безопасности в интерфейсе управления сессиями и обеспечения безопасности */ + page: PageResponse | undefined; +} + +export const GLIFA_AUTH_V1_PACKAGE_NAME = "glifa.auth.v1"; + +export interface AuthServiceClient { + register(request: RegisterRequest): Observable; + + loginWithPassword(request: LoginWithPasswordRequest): Observable; + + verifySecondFactor(request: VerifySecondFactorRequest): Observable; + + refreshSession(request: RefreshSessionRequest): Observable; + + logoutSession(request: LogoutSessionRequest): Observable; + + revokeSession(request: RevokeSessionRequest): Observable; + + lockSession(request: LockSessionRequest): Observable; + + unlockSession(request: UnlockSessionRequest): Observable; + + validateAccessToken(request: ValidateAccessTokenRequest): Observable; + + getSession(request: GetSessionRequest): Observable; + + listSessions(request: ListSessionsRequest): Observable; + + createQrLogin(request: CreateQrLoginRequest): Observable; + + approveQrLogin(request: ApproveQrLoginRequest): Observable; + + exchangeQrLogin(request: ExchangeQrLoginRequest): Observable; + + sendAuthChallenge(request: SendAuthChallengeRequest): Observable; + + verifyAuthChallenge(request: VerifyAuthChallengeRequest): Observable; + + listSecurityEvents(request: ListSecurityEventsRequest): Observable; +} + +export interface AuthServiceController { + register(request: RegisterRequest): Promise | Observable | RegisterResponse; + + loginWithPassword( + request: LoginWithPasswordRequest, + ): Promise | Observable | LoginWithPasswordResponse; + + verifySecondFactor( + request: VerifySecondFactorRequest, + ): Promise | Observable | VerifySecondFactorResponse; + + refreshSession( + request: RefreshSessionRequest, + ): Promise | Observable | RefreshSessionResponse; + + logoutSession( + request: LogoutSessionRequest, + ): Promise | Observable | LogoutSessionResponse; + + revokeSession( + request: RevokeSessionRequest, + ): Promise | Observable | RevokeSessionResponse; + + lockSession( + request: LockSessionRequest, + ): Promise | Observable | LockSessionResponse; + + unlockSession( + request: UnlockSessionRequest, + ): Promise | Observable | UnlockSessionResponse; + + validateAccessToken( + request: ValidateAccessTokenRequest, + ): Promise | Observable | ValidateAccessTokenResponse; + + getSession( + request: GetSessionRequest, + ): Promise | Observable | GetSessionResponse; + + listSessions( + request: ListSessionsRequest, + ): Promise | Observable | ListSessionsResponse; + + createQrLogin( + request: CreateQrLoginRequest, + ): Promise | Observable | CreateQrLoginResponse; + + approveQrLogin( + request: ApproveQrLoginRequest, + ): Promise | Observable | ApproveQrLoginResponse; + + exchangeQrLogin( + request: ExchangeQrLoginRequest, + ): Promise | Observable | ExchangeQrLoginResponse; + + sendAuthChallenge( + request: SendAuthChallengeRequest, + ): Promise | Observable | SendAuthChallengeResponse; + + verifyAuthChallenge( + request: VerifyAuthChallengeRequest, + ): Promise | Observable | VerifyAuthChallengeResponse; + + listSecurityEvents( + request: ListSecurityEventsRequest, + ): Promise | Observable | ListSecurityEventsResponse; +} + +export function AuthServiceControllerMethods() { + return function (constructor: Function) { + const grpcMethods: string[] = [ + "register", + "loginWithPassword", + "verifySecondFactor", + "refreshSession", + "logoutSession", + "revokeSession", + "lockSession", + "unlockSession", + "validateAccessToken", + "getSession", + "listSessions", + "createQrLogin", + "approveQrLogin", + "exchangeQrLogin", + "sendAuthChallenge", + "verifyAuthChallenge", + "listSecurityEvents", + ]; + for (const method of grpcMethods) { + const descriptor: any = Reflect.getOwnPropertyDescriptor(constructor.prototype, method); + GrpcMethod("AuthService", method)(constructor.prototype[method], method, descriptor); + } + const grpcStreamMethods: string[] = []; + for (const method of grpcStreamMethods) { + const descriptor: any = Reflect.getOwnPropertyDescriptor(constructor.prototype, method); + GrpcStreamMethod("AuthService", method)(constructor.prototype[method], method, descriptor); + } + }; +} + +export const AUTH_SERVICE_NAME = "AuthService"; diff --git a/gen/glifa/auth/v1/types.ts b/gen/glifa/auth/v1/types.ts new file mode 100644 index 0000000..5dd2eba --- /dev/null +++ b/gen/glifa/auth/v1/types.ts @@ -0,0 +1,288 @@ +// Code generated by protoc-gen-ts_proto. DO NOT EDIT. +// versions: +// protoc-gen-ts_proto v2.11.8 +// protoc v4.25.9 +// source: glifa/auth/v1/types.proto + +/* eslint-disable */ +import { Timestamp } from "../../../google/protobuf/timestamp"; + +export const protobufPackage = "glifa.auth.v1"; + +export enum DeviceSessionStatus { + /** DEVICE_SESSION_STATUS_UNSPECIFIED - Неопределенный статус сессии устройства */ + DEVICE_SESSION_STATUS_UNSPECIFIED = 0, + /** DEVICE_SESSION_STATUS_ACTIVE - Сессия устройства активна и используется */ + DEVICE_SESSION_STATUS_ACTIVE = 1, + /** DEVICE_SESSION_STATUS_LOCKED - Сессия устройства заблокирована (например, из-за подозрительной активности) */ + DEVICE_SESSION_STATUS_LOCKED = 2, + /** DEVICE_SESSION_STATUS_REQUIRES_2FA - Сессия устройства требует двухфакторной аутентификации для продолжения */ + DEVICE_SESSION_STATUS_REQUIRES_2FA = 3, + /** DEVICE_SESSION_STATUS_REQUIRES_REAUTH - Сессия устройства требует повторной аутентификации (например, после длительного периода неактивности) */ + DEVICE_SESSION_STATUS_REQUIRES_REAUTH = 4, + /** DEVICE_SESSION_STATUS_REVOKED - Сессия устройства отозвана (например, из-за нарушения безопасности) */ + DEVICE_SESSION_STATUS_REVOKED = 5, + /** DEVICE_SESSION_STATUS_EXPIRED - Сессия устройства истекла (например, после определенного периода времени) */ + DEVICE_SESSION_STATUS_EXPIRED = 6, + /** DEVICE_SESSION_STATUS_COMPROMISED - Сессия устройства скомпрометирована (например, обнаружена утечка учетных данных) */ + DEVICE_SESSION_STATUS_COMPROMISED = 7, + UNRECOGNIZED = -1, +} + +export enum AuthChallengePurpose { + /** AUTH_CHALLENGE_PURPOSE_UNSPECIFIED - Неопределенная цель аутентификационного вызова */ + AUTH_CHALLENGE_PURPOSE_UNSPECIFIED = 0, + /** AUTH_CHALLENGE_PURPOSE_LOGIN - Вызов для аутентификации при входе в систему */ + AUTH_CHALLENGE_PURPOSE_LOGIN = 1, + /** AUTH_CHALLENGE_PURPOSE_PASSWORD_RESET - Вызов для аутентификации при сбросе пароля */ + AUTH_CHALLENGE_PURPOSE_PASSWORD_RESET = 2, + /** AUTH_CHALLENGE_PURPOSE_EMAIL_VERIFICATION - Вызов для аутентификации при подтверждении электронной почты */ + AUTH_CHALLENGE_PURPOSE_EMAIL_VERIFICATION = 3, + /** AUTH_CHALLENGE_PURPOSE_PHONE_VERIFICATION - Вызов для аутентификации при подтверждении номера телефона */ + AUTH_CHALLENGE_PURPOSE_PHONE_VERIFICATION = 4, + /** AUTH_CHALLENGE_PURPOSE_SESSION_UNLOCK - Вызов для аутентификации при разблокировке сессии */ + AUTH_CHALLENGE_PURPOSE_SESSION_UNLOCK = 5, + /** AUTH_CHALLENGE_PURPOSE_REAUTH - Вызов для аутентификации при повторной аутентификации (например, после длительного периода неактивности) */ + AUTH_CHALLENGE_PURPOSE_REAUTH = 6, + /** AUTH_CHALLENGE_PURPOSE_QR_APPROVAL - Вызов для аутентификации при одобрении входа через QR-код на другом устройстве */ + AUTH_CHALLENGE_PURPOSE_QR_APPROVAL = 7, + UNRECOGNIZED = -1, +} + +export enum AuthChallengeDeliveryChannel { + /** AUTH_CHALLENGE_DELIVERY_CHANNEL_UNSPECIFIED - Неопределенный канал доставки аутентификационного вызова */ + AUTH_CHALLENGE_DELIVERY_CHANNEL_UNSPECIFIED = 0, + /** AUTH_CHALLENGE_DELIVERY_CHANNEL_EMAIL - Канал доставки - электронная почта */ + AUTH_CHALLENGE_DELIVERY_CHANNEL_EMAIL = 1, + /** AUTH_CHALLENGE_DELIVERY_CHANNEL_SMS - Канал доставки - SMS */ + AUTH_CHALLENGE_DELIVERY_CHANNEL_SMS = 2, + /** AUTH_CHALLENGE_DELIVERY_CHANNEL_TOTP - Канал доставки - TOTP (например, Google Authenticator) */ + AUTH_CHALLENGE_DELIVERY_CHANNEL_TOTP = 3, + /** AUTH_CHALLENGE_DELIVERY_CHANNEL_INTERNAL - Канал доставки - внутренний (например, push-уведомление в мобильном приложении) */ + AUTH_CHALLENGE_DELIVERY_CHANNEL_INTERNAL = 4, + UNRECOGNIZED = -1, +} + +export enum AuthChallengeType { + /** AUTH_CHALLENGE_TYPE_UNSPECIFIED - Неопределенный тип аутентификационного вызова */ + AUTH_CHALLENGE_TYPE_UNSPECIFIED = 0, + /** AUTH_CHALLENGE_TYPE_CODE - Вызов с кодом подтверждения (например, 6-значный код из SMS или TOTP) */ + AUTH_CHALLENGE_TYPE_CODE = 1, + /** AUTH_CHALLENGE_TYPE_LINK - Вызов с ссылкой для подтверждения (например, magic link в электронной почте) */ + AUTH_CHALLENGE_TYPE_LINK = 2, + /** AUTH_CHALLENGE_TYPE_TOTP - Вызов с TOTP (например, код из Google Authenticator) */ + AUTH_CHALLENGE_TYPE_TOTP = 3, + /** AUTH_CHALLENGE_TYPE_APPROVAL - Вызов с запросом на одобрение (например, push-уведомление для одобрения входа на другом устройстве) */ + AUTH_CHALLENGE_TYPE_APPROVAL = 4, + UNRECOGNIZED = -1, +} + +export enum AuthChallengeStatus { + /** AUTH_CHALLENGE_STATUS_UNSPECIFIED - Неопределенный статус аутентификационного вызова */ + AUTH_CHALLENGE_STATUS_UNSPECIFIED = 0, + /** AUTH_CHALLENGE_STATUS_PENDING - Вызов создан и ожидает подтверждения пользователем */ + AUTH_CHALLENGE_STATUS_PENDING = 1, + /** AUTH_CHALLENGE_STATUS_VERIFIED - Вызов успешно подтвержден пользователем */ + AUTH_CHALLENGE_STATUS_VERIFIED = 2, + /** AUTH_CHALLENGE_STATUS_CONSUMED - Вызов уже был использован для подтверждения и больше не действителен */ + AUTH_CHALLENGE_STATUS_CONSUMED = 3, + /** AUTH_CHALLENGE_STATUS_EXPIRED - Вызов истек и больше не действителен (например, после определенного периода времени) */ + AUTH_CHALLENGE_STATUS_EXPIRED = 4, + /** AUTH_CHALLENGE_STATUS_BLOCKED - Вызов заблокирован (например, из-за подозрительной активности) */ + AUTH_CHALLENGE_STATUS_BLOCKED = 5, + UNRECOGNIZED = -1, +} + +export enum QrLoginRequestStatus { + /** QR_LOGIN_REQUEST_STATUS_UNSPECIFIED - Неопределенный статус запроса на вход через QR-код */ + QR_LOGIN_REQUEST_STATUS_UNSPECIFIED = 0, + /** QR_LOGIN_REQUEST_STATUS_PENDING - Запрос на вход через QR-код создан и ожидает сканирования пользователем */ + QR_LOGIN_REQUEST_STATUS_PENDING = 1, + /** QR_LOGIN_REQUEST_STATUS_APPROVED - Запрос на вход через QR-код одобрен пользователем (например, через мобильное приложение) */ + QR_LOGIN_REQUEST_STATUS_APPROVED = 2, + /** QR_LOGIN_REQUEST_STATUS_CONSUMED - Запрос на вход через QR-код уже был использован для входа и больше не действителен */ + QR_LOGIN_REQUEST_STATUS_CONSUMED = 3, + /** QR_LOGIN_REQUEST_STATUS_EXPIRED - Запрос на вход через QR-код истек и больше не действителен (например, после определенного периода времени) */ + QR_LOGIN_REQUEST_STATUS_EXPIRED = 4, + /** QR_LOGIN_REQUEST_STATUS_REJECTED - Запрос на вход через QR-код отклонен пользователем (например, через мобильное приложение) */ + QR_LOGIN_REQUEST_STATUS_REJECTED = 5, + UNRECOGNIZED = -1, +} + +export enum SecurityEventType { + /** SECURITY_EVENT_TYPE_UNSPECIFIED - Неопределенный тип события безопасности */ + SECURITY_EVENT_TYPE_UNSPECIFIED = 0, + /** SECURITY_EVENT_TYPE_LOGIN_SUCCESS - Событие успешного входа в систему */ + SECURITY_EVENT_TYPE_LOGIN_SUCCESS = 1, + /** SECURITY_EVENT_TYPE_LOGIN_FAILED - Событие неудачного входа в систему (например, из-за неправильного пароля) */ + SECURITY_EVENT_TYPE_LOGIN_FAILED = 2, + /** SECURITY_EVENT_TYPE_CHALLENGE_SEND - Событие отправки аутентификационного вызова пользователю (например, отправка SMS с кодом подтверждения) */ + SECURITY_EVENT_TYPE_CHALLENGE_SEND = 3, + /** SECURITY_EVENT_TYPE_CHALLENGE_VERIFIED - Событие успешного подтверждения аутентификационного вызова пользователем (например, пользователь ввел правильный код подтверждения) */ + SECURITY_EVENT_TYPE_CHALLENGE_VERIFIED = 4, + /** SECURITY_EVENT_TYPE_TWO_FACTOR_ENABLED - Событие включения двухфакторной аутентификации пользователем */ + SECURITY_EVENT_TYPE_TWO_FACTOR_ENABLED = 5, + /** SECURITY_EVENT_TYPE_TWO_FACTOR_DISABLED - Событие отключения двухфакторной аутентификации пользователем */ + SECURITY_EVENT_TYPE_TWO_FACTOR_DISABLED = 6, + /** SECURITY_EVENT_TYPE_SESSION_CREATED - Событие создания новой сессии пользователя */ + SECURITY_EVENT_TYPE_SESSION_CREATED = 7, + /** SECURITY_EVENT_TYPE_SESSION_LOCKED - Событие блокировки сессии пользователя (например, из-за подозрительной активности) */ + SECURITY_EVENT_TYPE_SESSION_LOCKED = 8, + /** SECURITY_EVENT_TYPE_SESSION_UNLOCKED - Событие разблокировки сессии пользователя (например, после успешной аутентификации) */ + SECURITY_EVENT_TYPE_SESSION_UNLOCKED = 9, + /** SECURITY_EVENT_TYPE_SESSION_REVOKED - Событие отзыва сессии пользователя (например, из-за нарушения безопасности) */ + SECURITY_EVENT_TYPE_SESSION_REVOKED = 10, + /** SECURITY_EVENT_TYPE_SESSION_COMPROMISED - Событие компрометации сессии пользователя (например, обнаружена утечка учетных данных) */ + SECURITY_EVENT_TYPE_SESSION_COMPROMISED = 11, + /** SECURITY_EVENT_TYPE_QR_APPROVED - Событие одобрения входа через QR-код на другом устройстве */ + SECURITY_EVENT_TYPE_QR_APPROVED = 12, + /** SECURITY_EVENT_TYPE_QR_CONSUMED - Событие использования запроса на вход через QR-код для входа в систему */ + SECURITY_EVENT_TYPE_QR_CONSUMED = 13, + /** SECURITY_EVENT_TYPE_QR_EXPIRED - Событие истечения срока действия запроса на вход через QR-код */ + SECURITY_EVENT_TYPE_QR_EXPIRED = 14, + UNRECOGNIZED = -1, +} + +export interface DeviceSession { + /** UUID сессии устройства */ + id: string; + /** UUID пользователя, которому принадлежит сессия устройства */ + userId: string; + /** UUID устройства, с которого была создана сесс */ + deviceId: string; + /** Человеко-читаемое имя устройства (например, "iPhone 12 Pro") */ + deviceName: string; + /** Платформа устройства (например, "iOS", "Android", "Web") */ + platform: string; + /** Версия приложения, с которого была создана сессия устройства */ + appVersion: string; + /** Статус сессии устройства */ + status: DeviceSessionStatus; + /** Последний IP-адрес, с которого была активна сессия устройства */ + lastIp: string; + /** User-Agent устройства, с которого была создана сессия */ + userAgent: string; + /** Время последней активности сессии устройства */ + lastSeenAt: + | Timestamp + | undefined; + /** Время, когда сессия устройства была мягко заблокирована (например, из-за подозрительной активности, но еще не отозвана) */ + softLockAt: + | Timestamp + | undefined; + /** Время истечения срока действия сессии устройства (например, после определенного периода времени неактивности) */ + expiresAt: + | Timestamp + | undefined; + /** Время создания сессии устройства */ + createdAt: + | Timestamp + | undefined; + /** Время последнего обновления сессии устройства */ + updatedAt: Timestamp | undefined; +} + +export interface TokenPair { + /** JWT access token для аутентификации API-запросов */ + accessToken: string; + /** Время истечения срока действия access token */ + accessTokenExpiresAt: + | Timestamp + | undefined; + /** JWT refresh token для получения нового access token после истечения срока действия */ + refreshToken: string; + /** Время истечения срока действия refresh token (например, через 30 дней) */ + refreshTokenExpiresAt: + | Timestamp + | undefined; + /** UUID сессии, для которой был выдан токен */ + sessionId: string; + /** UUID пользователя, которому принадлежит сессия и токен */ + userId: string; +} + +export interface LoginChallenge { + /** UUID аутентификационного вызова, который может быть использован для отслеживания и управления процессом аутентификации */ + challengeId: string; + /** Временная метка, указывающая, когда этот аутентификационный вызов истекает и больше не может быть использован для подтверждения входа */ + expiresAt: Timestamp | undefined; +} + +export interface AuthChallenge { + /** UUID аутентификационного вызова */ + id: string; + /** Цель аутентификационного вызова (например, "login", "password_reset") */ + target: string; + /** Цель аутентификационного вызова (например, "login", "password_reset") */ + purpose: AuthChallengePurpose; + /** Канал доставки аутентификационного вызова (например, "email", "sms") */ + deliveryChannel: AuthChallengeDeliveryChannel; + /** Тип аутентификационного вызова (например, "code", "link") */ + challengeType: AuthChallengeType; + /** Статус аутентификационного вызова (например, "pending", "verified") */ + status: AuthChallengeStatus; + /** Количество попыток подтверждения аутентификационного вызова */ + attemptCount: number; + /** Количество повторных отправок аутентификационного вызова */ + resendCount: number; + /** Максимально допустимое количество попыток подтверждения аутентификационного вызова (например, 5) */ + maxAttempts: number; + /** Время истечения срока действия аутентификационного вызова (например, через 10 минут) */ + expiresAt: + | Timestamp + | undefined; + /** Время, когда аутентификационный вызов был успешно подтвержден и использован */ + consumedAt: + | Timestamp + | undefined; + /** Время создания аутентификационного вызова */ + createdAt: + | Timestamp + | undefined; + /** Время последнего обновления аутентификационного вызова (например, при каждой попытке подтверждения или повторной отправке) */ + updatedAt: Timestamp | undefined; +} + +export interface QrLoginRequest { + /** UUID запроса на вход через QR-код */ + requestId: string; + /** Случайная строка для обеспечения безопасности QR-кода */ + nonce: string; + /** Статус запроса на вход через QR-код (например, "pending", "approved") */ + status: QrLoginRequestStatus; + /** Время истечения срока действия запроса на вход через QR-код (например, через 5 минут) */ + expiresAt: + | Timestamp + | undefined; + /** Время, когда запрос на вход через QR-код был одобрен пользователем (например, через мобильное приложение) */ + approvedAt: + | Timestamp + | undefined; + /** Время, когда запрос на вход через QR-код был использован для входа в систему */ + consumedAt: + | Timestamp + | undefined; + /** Время создания запроса на вход через QR-код */ + createdAt: Timestamp | undefined; +} + +export interface SecurityEvent { + /** UUID события безопасности */ + id: string; + /** UUID пользователя, которому относится событие безопасности */ + userId: string; + /** UUID сессии, если событие безопасности связано с конкретной сессией пользователя */ + sessionId: string; + /** Тип события безопасности (например, "login_success", "challenge_verified") */ + eventType: SecurityEventType; + /** IP-адрес, с которого произошло событие безопасности */ + ipAddress: string; + /** User-Agent, с которого произошло событие безопасности */ + userAgent: string; + /** Дополнительные детали события безопасности в формате JSON (например, информация о вызове аутентификационного вызова, который был подтвержден) */ + detailsJson: string; + /** Время создания события безопасности */ + createdAt: Timestamp | undefined; +} + +export const GLIFA_AUTH_V1_PACKAGE_NAME = "glifa.auth.v1"; diff --git a/gen/glifa/channel/v1/service.ts b/gen/glifa/channel/v1/service.ts new file mode 100644 index 0000000..a35dba9 --- /dev/null +++ b/gen/glifa/channel/v1/service.ts @@ -0,0 +1,307 @@ +// Code generated by protoc-gen-ts_proto. DO NOT EDIT. +// versions: +// protoc-gen-ts_proto v2.11.8 +// protoc v4.25.9 +// source: glifa/channel/v1/service.proto + +/* eslint-disable */ +import { GrpcMethod, GrpcStreamMethod } from "@nestjs/microservices"; +import { wrappers } from "protobufjs"; +import { Observable } from "rxjs"; +import { Struct } from "../../../google/protobuf/struct"; +import { MessageContentType } from "../../common/v1/enums"; +import { PageRequest, PageResponse, RequestMeta } from "../../common/v1/types"; +import { Channel, ChannelPost, ChannelReadOffset, ChannelSubscriber } from "./types"; + +export const protobufPackage = "glifa.channel.v1"; + +export interface CreateChannelRequest { + /** Метаданные запроса (например, для аутентификации и трассировки) */ + meta: + | RequestMeta + | undefined; + /** UUID пользователя, который создает канал */ + ownerUserId: string; + /** Уникальный идентификатор канала (например, "general", "random") */ + handle: string; + /** Название канала */ + title: string; + /** Описание канала */ + description: string; + /** Флаг, указывающий, является ли канал приватным (только по приглашениям) */ + isPrivate: boolean; +} + +export interface CreateChannelResponse { + /** Данные созданного канала */ + channel: Channel | undefined; +} + +export interface GetChannelRequest { + /** Метаданные запроса (например, для аутентификации и трассировки) */ + meta: + | RequestMeta + | undefined; + /** UUID пользователя, который создал канал */ + ownerUserId: string; + /** Уникальный идентификатор канала (например, "general", "random") */ + handle: string; + /** Название канала */ + title: string; + /** Описание канала */ + description: string; + /** Флаг, указывающий, является ли канал приватным (только по приглашениям) */ + isPrivate: boolean; +} + +export interface GetChannelResponse { + /** Данные запрошенного канала */ + channel: Channel | undefined; +} + +export interface SubscribeRequest { + /** Метаданные запроса (например, для аутентификации и трассировки) */ + meta: + | RequestMeta + | undefined; + /** UUID канала, в который пользователь хочет подписаться */ + channelId: string; + /** UUID пользователя, который хочет подписаться на канал */ + userId: string; +} + +export interface SubscribeResponse { + /** Данные о новом подписчике канала */ + subscriber: ChannelSubscriber | undefined; +} + +export interface UnsubscribeRequest { + /** Метаданные запроса (например, для аутентификации и трассировки) */ + meta: + | RequestMeta + | undefined; + /** UUID канала, из которого пользователь хочет отписаться */ + channelId: string; + /** UUID пользователя, который хочет отписаться от канала */ + userId: string; +} + +export interface UnsubscribeResponse { + /** Флаг, указывающий, была ли операция отписки успешной */ + success: boolean; +} + +export interface CreatePostRequest { + /** Метаданные запроса (например, для аутентификации и трассировки) */ + meta: + | RequestMeta + | undefined; + /** UUID канала, в котором пользователь хочет создать пост */ + channelId: string; + /** Идентификатор поста, сгенерированный на клиенте (для обеспечения идемпотентности при повторной отправке) */ + clientPostId: string; + /** Тип контента поста (например, "text", "image", "file") */ + messageType: MessageContentType; + /** Текст поста (если message_type == "text") */ + text: string; + /** UUID файла, прикрепленного к посту (если message_type == "file") */ + fileId: string; + /** Дополнительные метаданные поста в виде произвольной JSON-структуры (например, для хранения информации о медиа-контенте) */ + metadata: { [key: string]: any } | undefined; +} + +export interface CreatePostResponse { + /** Данные созданного поста */ + post: ChannelPost | undefined; +} + +export interface EditPostRequest { + /** Метаданные запроса (например, для аутентификации и трассировки) */ + meta: + | RequestMeta + | undefined; + /** UUID поста, который пользователь хочет отредактировать */ + postId: string; + /** Новый текст поста (если message_type == "text") */ + text: string; + /** Новые дополнительные метаданные поста в виде произвольной JSON-структуры (например, для обновления информации о медиа-контенте) */ + metadata: { [key: string]: any } | undefined; +} + +export interface EditPostResponse { + /** Данные отредактированного поста */ + post: ChannelPost | undefined; +} + +export interface DeletePostRequest { + /** Метаданные запроса (например, для аутентификации и трассировки) */ + meta: + | RequestMeta + | undefined; + /** UUID поста, который пользователь хочет удалить */ + postId: string; +} + +export interface DeletePostResponse { + /** Флаг, указывающий, была ли операция удаления успешной */ + success: boolean; +} + +export interface GetPostRequest { + /** Метаданные запроса (например, для аутентификации и трассировки) */ + meta: + | RequestMeta + | undefined; + /** UUID поста, который пользователь хочет получить */ + postId: string; +} + +export interface GetPostResponse { + /** Данные запрошенного поста */ + post: ChannelPost | undefined; +} + +export interface GetFeedRequest { + /** Метаданные запроса (например, для аутентификации и трассировки) */ + meta: + | RequestMeta + | undefined; + /** UUID канала, для которого пользователь хочет получить ленту постов */ + channelId: string; + /** Параметры пагинации (номер страницы и размер страницы) */ + page: PageRequest | undefined; +} + +export interface GetFeedResponse { + /** Список постов в запрошенной странице ленты */ + items: ChannelPost[]; + /** Информация о пагинации (номер страницы, размер страницы, общее количество элементов) */ + page: PageResponse | undefined; +} + +export interface UpdateReadOffsetRequest { + /** Метаданные запроса (например, для аутентификации и трассировки) */ + meta: + | RequestMeta + | undefined; + /** UUID канала, для которого пользователь хочет обновить оффсет прочтения */ + channelId: string; + /** Максимальный последовательный номер поста, который пользователь прочитал в канале (включительно) */ + readPostSeq: string; +} + +export interface UpdateReadOffsetResponse { + /** Данные обновленного оффсета прочтения пользователя в канале */ + offset: ChannelReadOffset | undefined; +} + +export interface GetReadOffsetRequest { + /** Метаданные запроса (например, для аутентификации и трассировки) */ + meta: + | RequestMeta + | undefined; + /** UUID канала, для которого пользователь хочет получить оффсет прочтения */ + channelId: string; + /** UUID пользователя, для которого нужно получить оффсет прочтения */ + userId: string; +} + +export interface GetReadOffsetResponse { + /** Данные оффсета прочтения пользователя в канале */ + offset: ChannelReadOffset | undefined; +} + +export const GLIFA_CHANNEL_V1_PACKAGE_NAME = "glifa.channel.v1"; + +wrappers[".google.protobuf.Struct"] = { fromObject: Struct.wrap, toObject: Struct.unwrap } as any; + +export interface ChannelServiceClient { + createChannel(request: CreateChannelRequest): Observable; + + getChannel(request: GetChannelRequest): Observable; + + subscribe(request: SubscribeRequest): Observable; + + unsubscribe(request: UnsubscribeRequest): Observable; + + createPost(request: CreatePostRequest): Observable; + + editPost(request: EditPostRequest): Observable; + + deletePost(request: DeletePostRequest): Observable; + + getPost(request: GetPostRequest): Observable; + + getFeed(request: GetFeedRequest): Observable; + + updateReadOffset(request: UpdateReadOffsetRequest): Observable; + + getReadOffset(request: GetReadOffsetRequest): Observable; +} + +export interface ChannelServiceController { + createChannel( + request: CreateChannelRequest, + ): Promise | Observable | CreateChannelResponse; + + getChannel( + request: GetChannelRequest, + ): Promise | Observable | GetChannelResponse; + + subscribe(request: SubscribeRequest): Promise | Observable | SubscribeResponse; + + unsubscribe( + request: UnsubscribeRequest, + ): Promise | Observable | UnsubscribeResponse; + + createPost( + request: CreatePostRequest, + ): Promise | Observable | CreatePostResponse; + + editPost(request: EditPostRequest): Promise | Observable | EditPostResponse; + + deletePost( + request: DeletePostRequest, + ): Promise | Observable | DeletePostResponse; + + getPost(request: GetPostRequest): Promise | Observable | GetPostResponse; + + getFeed(request: GetFeedRequest): Promise | Observable | GetFeedResponse; + + updateReadOffset( + request: UpdateReadOffsetRequest, + ): Promise | Observable | UpdateReadOffsetResponse; + + getReadOffset( + request: GetReadOffsetRequest, + ): Promise | Observable | GetReadOffsetResponse; +} + +export function ChannelServiceControllerMethods() { + return function (constructor: Function) { + const grpcMethods: string[] = [ + "createChannel", + "getChannel", + "subscribe", + "unsubscribe", + "createPost", + "editPost", + "deletePost", + "getPost", + "getFeed", + "updateReadOffset", + "getReadOffset", + ]; + for (const method of grpcMethods) { + const descriptor: any = Reflect.getOwnPropertyDescriptor(constructor.prototype, method); + GrpcMethod("ChannelService", method)(constructor.prototype[method], method, descriptor); + } + const grpcStreamMethods: string[] = []; + for (const method of grpcStreamMethods) { + const descriptor: any = Reflect.getOwnPropertyDescriptor(constructor.prototype, method); + GrpcStreamMethod("ChannelService", method)(constructor.prototype[method], method, descriptor); + } + }; +} + +export const CHANNEL_SERVICE_NAME = "ChannelService"; diff --git a/gen/glifa/channel/v1/types.ts b/gen/glifa/channel/v1/types.ts new file mode 100644 index 0000000..b5ba40f --- /dev/null +++ b/gen/glifa/channel/v1/types.ts @@ -0,0 +1,99 @@ +// Code generated by protoc-gen-ts_proto. DO NOT EDIT. +// versions: +// protoc-gen-ts_proto v2.11.8 +// protoc v4.25.9 +// source: glifa/channel/v1/types.proto + +/* eslint-disable */ +import { wrappers } from "protobufjs"; +import { Struct } from "../../../google/protobuf/struct"; +import { Timestamp } from "../../../google/protobuf/timestamp"; +import { MessageContentType } from "../../common/v1/enums"; + +export const protobufPackage = "glifa.channel.v1"; + +export interface Channel { + /** UUID канала */ + id: string; + /** Идентификатор обработчика канала (например, "websocket", "mqtt") */ + handler: string; + /** Название канала */ + title: string; + /** Описание канала */ + description: string; + /** UUID пользователя, который создал канал */ + ownerUserId: string; + /** Последовательный номер последнего поста в канале (для генерации новых последовательных номеров) */ + lastPostSeq: number; + /** UUID последнего поста в канале (для оптимистичной блокировки при добавлении новых постов) */ + lastPostId: string; + /** Флаг, указывающий, является ли канал приватным (только по приглашениям) */ + isPrivate: boolean; + /** Время создания канала */ + createdAt: + | Timestamp + | undefined; + /** Время последнего обновления канала (например, при изменении названия или описания) */ + updatedAt: Timestamp | undefined; +} + +export interface ChannelSubscriber { + /** UUID канала, на который подписан пользователь */ + channelId: string; + /** UUID пользователя, который подписан на канал */ + userId: string; + /** Время подписки пользователя на канал */ + subscribedAt: Timestamp | undefined; +} + +export interface ChannelPost { + /** UUID поста */ + id: string; + /** UUID канала, в котором опубликован пост */ + channelId: string; + /** Последовательный номер поста в канале (для упорядочивания постов) */ + postSeq: string; + /** Идентификатор поста, сгенерированный на клиенте (для обеспечения идемпотентности при повторной отправке) */ + clientPostId: string; + /** UUID пользователя, который создал пост */ + authorUserId: string; + /** Тип контента поста (например, "text", "image", "file") */ + messageType: MessageContentType; + /** Текст поста (если message_type == "text") */ + text: string; + /** UUID файла, прикрепленного к посту (если message_type == "file") */ + fileId: string; + /** Дополнительные метаданные поста в виде произвольной JSON-структуры (например, для хранения информации о медиа-контент */ + metadata: + | { [key: string]: any } + | undefined; + /** Флаг, указывающий, был ли пост отредактирован после создания */ + isEdited: boolean; + /** Версия редактирования поста, которая увеличивается при каждом редактировании (для оптимистичной блокировки при редактировании) */ + editVersion: number; + /** Время удаления поста (если пост был удален) */ + deletedAt: + | Timestamp + | undefined; + /** Время создания поста */ + createdAt: + | Timestamp + | undefined; + /** Время последнего обновления поста */ + updatedAt: Timestamp | undefined; +} + +export interface ChannelReadOffset { + /** UUID канала, для которого сохраняется смещение прочтения */ + channelId: string; + /** UUID пользователя, для которого сохраняется смещение прочтения */ + userId: string; + /** Последовательный номер последнего прочитанного поста в канале (для определения новых постов, которые пользователь еще не прочитал) */ + readPostSeq: string; + /** Время последнего обновления смещения прочтения (например, при открытии канала пользователем) */ + updatedAt: Timestamp | undefined; +} + +export const GLIFA_CHANNEL_V1_PACKAGE_NAME = "glifa.channel.v1"; + +wrappers[".google.protobuf.Struct"] = { fromObject: Struct.wrap, toObject: Struct.unwrap } as any; diff --git a/gen/glifa/common/v1/authz.ts b/gen/glifa/common/v1/authz.ts new file mode 100644 index 0000000..1ee1a86 --- /dev/null +++ b/gen/glifa/common/v1/authz.ts @@ -0,0 +1,42 @@ +// Code generated by protoc-gen-ts_proto. DO NOT EDIT. +// versions: +// protoc-gen-ts_proto v2.11.8 +// protoc v4.25.9 +// source: glifa/common/v1/authz.proto + +/* eslint-disable */ + +export const protobufPackage = "glifa.common.v1"; + +export interface SubjectContext { + /** UUID пользователя, которому принадлежат права */ + userId: string; + /** UUID устройства, с которого пришел запрос (если есть) */ + deviceId: string; + /** UUID сессии, если пользователь авторизован */ + sessionId: string; + /** Глобальные роли пользователя (например, "admin", "moderator") */ + globalRoles: string[]; + /** Глобальные права пользователя (например, "read_all", "write_all") */ + globalPermissions: string[]; +} + +export interface PermissionCheck { + /** Тип ресурса (например, "user", "device", "session") */ + resourceType: string; + /** UUID ресурса, к которому запрашиваются права */ + resourceId: string; + /** Запрашиваемое право (например, "read", "write", "delete") */ + permission: string; +} + +export interface PermissionDecision { + /** Запрашиваемое право (например, "read", "write", "delete") */ + permission: string; + /** Разрешено ли запрашиваемое право */ + allowed: boolean; + /** Причина решения (например, "user_is_owner", "user_has_role_admin") */ + reason: string; +} + +export const GLIFA_COMMON_V1_PACKAGE_NAME = "glifa.common.v1"; diff --git a/gen/glifa/common/v1/enums.ts b/gen/glifa/common/v1/enums.ts new file mode 100644 index 0000000..8df96da --- /dev/null +++ b/gen/glifa/common/v1/enums.ts @@ -0,0 +1,63 @@ +// Code generated by protoc-gen-ts_proto. DO NOT EDIT. +// versions: +// protoc-gen-ts_proto v2.11.8 +// protoc v4.25.9 +// source: glifa/common/v1/enums.proto + +/* eslint-disable */ + +export const protobufPackage = "glifa.common.v1"; + +export enum SortDirection { + /** SORT_DIRECTION_UNSPECIFIED - Не указано */ + SORT_DIRECTION_UNSPECIFIED = 0, + /** SORT_DIRECTION_ASC - По возрастанию */ + SORT_DIRECTION_ASC = 1, + /** SORT_DIRECTION_DESC - По убыванию */ + SORT_DIRECTION_DESC = 2, + UNRECOGNIZED = -1, +} + +export enum Visibility { + /** VISIBILITY_UNSPECIFIED - Не указано */ + VISIBILITY_UNSPECIFIED = 0, + /** VISIBILITY_PUBLIC - Публичный ресурс, доступный всем */ + VISIBILITY_PUBLIC = 1, + /** VISIBILITY_PRIVATE - Приватный ресурс, доступный только владельцу */ + VISIBILITY_PRIVATE = 2, + /** VISIBILITY_INTERNAL - Внутренний ресурс, доступный только внутри системы */ + VISIBILITY_INTERNAL = 3, + UNRECOGNIZED = -1, +} + +export enum MessageContentType { + /** MESSAGE_CONTENT_TYPE_UNSPECIFIED - Не указано */ + MESSAGE_CONTENT_TYPE_UNSPECIFIED = 0, + /** MESSAGE_CONTENT_TYPE_TEXT - Текстовое сообщение */ + MESSAGE_CONTENT_TYPE_TEXT = 1, + /** MESSAGE_CONTENT_TYPE_IMAGE - Изображение */ + MESSAGE_CONTENT_TYPE_IMAGE = 2, + /** MESSAGE_CONTENT_TYPE_VIDEO - Видео */ + MESSAGE_CONTENT_TYPE_VIDEO = 3, + /** MESSAGE_CONTENT_TYPE_AUDIO - Аудио */ + MESSAGE_CONTENT_TYPE_AUDIO = 4, + /** MESSAGE_CONTENT_TYPE_FILE - Файл */ + MESSAGE_CONTENT_TYPE_FILE = 5, + /** MESSAGE_CONTENT_TYPE_SYSTEM - Системное сообщение (например, уведомление о входе пользователя) */ + MESSAGE_CONTENT_TYPE_SYSTEM = 6, + UNRECOGNIZED = -1, +} + +export enum EncryptionMode { + /** ENCRYPTION_MODE_UNSPECIFIED - Не указано */ + ENCRYPTION_MODE_UNSPECIFIED = 0, + /** ENCRYPTION_MODE_NONE - Без шифрования */ + ENCRYPTION_MODE_NONE = 1, + /** ENCRYPTION_MODE_SERVER - Шифрование на стороне сервера */ + ENCRYPTION_MODE_SERVER = 2, + /** ENCRYPTION_MODE_E2EE - End-to-End шифрование */ + ENCRYPTION_MODE_E2EE = 3, + UNRECOGNIZED = -1, +} + +export const GLIFA_COMMON_V1_PACKAGE_NAME = "glifa.common.v1"; diff --git a/gen/glifa/common/v1/types.ts b/gen/glifa/common/v1/types.ts new file mode 100644 index 0000000..99b90f4 --- /dev/null +++ b/gen/glifa/common/v1/types.ts @@ -0,0 +1,102 @@ +// Code generated by protoc-gen-ts_proto. DO NOT EDIT. +// versions: +// protoc-gen-ts_proto v2.11.8 +// protoc v4.25.9 +// source: glifa/common/v1/types.proto + +/* eslint-disable */ +import { Timestamp } from "../../../google/protobuf/timestamp"; + +export const protobufPackage = "glifa.common.v1"; + +export interface Empty { +} + +export interface RequestMeta { + /** UUID4 для трассировки запроса */ + requestId: string; + /** UUID4 для распределенного трейсинга */ + traceId: string; + /** UUID4 для корреляции логов */ + correlationId: string; + /** UUID4 для идемпотентности операций */ + idempotencyKey: string; + /** UUID пользователя, инициировавшего запрос (если есть) */ + actorUserId: string; + /** UUID устройства, с которого пришел запрос ( */ + actorDeviceId: string; + /** UUID сессии, если пользователь авторизован */ + actorSessionId: string; + /** IP-адрес клиента, от которого пришел запрос */ + clientIp: string; + /** User-Agent клиента */ + userAgent: string; + /** Локаль клиента (например, "en-US") */ + locale: string; +} + +export interface PageRequest { + /** Количество элементов на странице */ + limit: number; + /** Курсор для пагинации (например, ID последнего элемента на предыдущей странице) */ + cursor: string; +} + +export interface PageResponse { + /** Курсор для следующей страницы (например, ID последнего элемента на текущей странице) */ + nextCursor: string; + /** Флаг, указывающий, есть ли еще страницы */ + hasMore: boolean; +} + +export interface StringValue { + value: string; +} + +export interface BoolValue { + value: boolean; +} + +export interface Int64Value { + value: number; +} + +export interface ErrorDetail { + /** Код ошибки (например, "USER_NOT_FOUND") */ + code: string; + /** Человеко-читаемое сообщение об ошибке */ + message: string; + /** Дополнительные данные об ошибке */ + fields: { [key: string]: string }; +} + +export interface ErrorDetail_FieldsEntry { + key: string; + value: string; +} + +export interface ResourceRef { + /** UUID ресурса */ + id: string; + /** Тип ресурса (например, "user", "device", "session") */ + type: string; +} + +export interface AuditStamp { + /** Время создания ресурса */ + createdAt: + | Timestamp + | undefined; + /** Ссылка на ресурс, который создал этот ресурс */ + createdBy: + | ResourceRef + | undefined; + /** Время последнего обновления ресурса */ + updatedAt: + | Timestamp + | undefined; + /** Ссылка на ресурс, который последний обновил этот ресурс */ + updatedBy: ResourceRef | undefined; +} + +export const GLIFA_COMMON_V1_PACKAGE_NAME = "glifa.common.v1"; diff --git a/gen/glifa/core/v1/service.ts b/gen/glifa/core/v1/service.ts new file mode 100644 index 0000000..7e9d8c9 --- /dev/null +++ b/gen/glifa/core/v1/service.ts @@ -0,0 +1,393 @@ +// Code generated by protoc-gen-ts_proto. DO NOT EDIT. +// versions: +// protoc-gen-ts_proto v2.11.8 +// protoc v4.25.9 +// source: glifa/core/v1/service.proto + +/* eslint-disable */ +import { GrpcMethod, GrpcStreamMethod } from "@nestjs/microservices"; +import { wrappers } from "protobufjs"; +import { Observable } from "rxjs"; +import { Struct } from "../../../google/protobuf/struct"; +import { PermissionCheck, PermissionDecision, SubjectContext } from "../../common/v1/authz"; +import { EncryptionMode, MessageContentType } from "../../common/v1/enums"; +import { PageRequest, PageResponse, RequestMeta } from "../../common/v1/types"; +import { Chat, ChatMember, ChatMessage, ChatReadCursor, MessageSendStatus, UserProfile } from "./types"; + +export const protobufPackage = "glifa.core.v1"; + +export interface CreateDirectChatRequest { + meta: + | RequestMeta + | undefined; + /** UUID пользователя, который инициирует создание чата */ + initiatorUserId: string; + /** UUID другого пользователя, с которым будет создан прямой чат */ + peerUserId: string; +} + +export interface CreateDirectChatResponse { + /** Информация о созданном чате */ + chat: Chat | undefined; +} + +export interface CreateGroupChatRequest { + meta: + | RequestMeta + | undefined; + /** UUID пользователя, который инициирует создание чата */ + createdByUserId: string; + /** Название группового чата */ + title: string; + /** Список UUID пользователей, которые будут добавлены в групповой чат (может быть пустым, тогда чат будет создан без участников, кроме создателя) */ + memberUserIds: string[]; +} + +export interface CreateGroupChatResponse { + /** Информация о созданном чате */ + chat: Chat | undefined; +} + +export interface AddChatMemberRequest { + meta: + | RequestMeta + | undefined; + /** UUID чата, в который нужно добавить участника */ + chatId: string; + /** UUID пользователя, которого нужно добавить в чат */ + userId: string; +} + +export interface AddChatMemberResponse { + /** Информация о добавленном участнике чата */ + member: ChatMember | undefined; +} + +export interface RemoveChatMemberRequest { + meta: + | RequestMeta + | undefined; + /** UUID чата, из которого нужно удалить участника */ + chatId: string; + /** UUID пользователя, которого нужно удалить из чата */ + userId: string; +} + +export interface RemoveChatMemberResponse { + /** Флаг, указывающий, был ли участник успешно удален из чата */ + success: boolean; +} + +export interface SendMessageRequest { + meta: + | RequestMeta + | undefined; + /** UUID чата, в который нужно отправить сообщение */ + chatId: string; + /** Идентификатор сообщения, сгенерированный на клиенте (для обеспечения идемпотентности при повторной отправке) */ + clientMessageId: string; + /** Тип контента сообщения (например, "text", "image", "file") */ + messageType: MessageContentType; + /** Текст сообщения (если message_type == "text") */ + text: string; + /** UUID файла, прикрепленного к сообщению (если message_type == "file") */ + fileId: string; + /** UUID сообщения, на которое был дан ответ (если это */ + replyToMessageId: string; + /** Режим шифрования сообщения (например, "none", "client_side") */ + encryptionMode: EncryptionMode; + /** Дополнительные метаданные сообщения в виде произвольной JSON-структуры (например, для хранения информации о медиа-контенте) */ + metadata: { [key: string]: any } | undefined; +} + +export interface SendMessageResponse { + /** Информация о созданном сообщении */ + message: + | ChatMessage + | undefined; + /** Статус отправки сообщения (например, "sent", "delivered", "read") */ + status: MessageSendStatus; +} + +export interface EditMessageRequest { + meta: + | RequestMeta + | undefined; + /** UUID сообщения, которое нужно отредактировать */ + messageId: string; + /** Новый текст сообщения (если message_type == "text") */ + text: string; + /** Новые дополнительные метаданные сообщения в виде произвольной JSON-структуры (например, для обновления информации о медиа-контенте) */ + metadata: { [key: string]: any } | undefined; +} + +export interface EditMessageResponse { + /** Информация об отредактированном сообщении */ + message: ChatMessage | undefined; +} + +export interface DeleteMessageRequest { + meta: + | RequestMeta + | undefined; + /** UUID сообщения, которое нужно удалить */ + messageId: string; +} + +export interface DeleteMessageResponse { + /** Флаг, указывающий, было ли сообщение успешно удалено */ + success: boolean; +} + +export interface GetChatRequest { + meta: + | RequestMeta + | undefined; + /** UUID чата, информацию о котором нужно получить */ + chatId: string; +} + +export interface GetChatResponse { + /** Информация о запрошенном чате */ + chat: + | Chat + | undefined; + /** Список участников чата */ + members: ChatMember[]; +} + +export interface GetMessageRequest { + meta: + | RequestMeta + | undefined; + /** UUID сообщения, информацию о котором нужно получить */ + messageId: string; +} + +export interface GetMessageResponse { + /** Информация о запрошенном сообщении */ + message: ChatMessage | undefined; +} + +export interface GetHistoryRequest { + meta: + | RequestMeta + | undefined; + /** UUID чата, историю которого нужно получить */ + chatId: string; + /** Параметры пагинации для получения истории сообщений */ + page: PageRequest | undefined; +} + +export interface GetHistoryResponse { + /** Список сообщений в запрошенной истории */ + messages: ChatMessage[]; + /** Информация о пагинации (номер страницы, размер страницы, общее количество сообщений) */ + page: PageResponse | undefined; +} + +export interface UpdateReadCursorRequest { + meta: + | RequestMeta + | undefined; + /** UUID чата, для которого нужно обновить курсор прочтения */ + chatId: string; + /** Последовательный номер сообщения, до которого пользователь прочитал чат (включительно) */ + readChatSeq: number; +} + +export interface UpdateReadCursorResponse { + /** Информация об обновленном курсоре прочтения */ + cursor: ChatReadCursor | undefined; +} + +export interface GetReadCursorRequest { + meta: + | RequestMeta + | undefined; + /** UUID чата, для которого нужно получить курсор прочтения */ + chatId: string; + /** UUID пользователя, для которого нужно получить курсор прочтения */ + userId: string; +} + +export interface GetReadCursorResponse { + /** Информация о курсоре прочтения, включая последний прочитанный последовательный номер сообщения в чате */ + cursor: ChatReadCursor | undefined; +} + +export interface GetUserProfileRequest { + meta: + | RequestMeta + | undefined; + /** UUID пользователя, профиль которого нужно получить */ + userId: string; +} + +export interface GetUserProfileResponse { + /** Информация о запрошенном профиле пользователя */ + profile: UserProfile | undefined; +} + +export interface SearchUserProfilesRequest { + meta: + | RequestMeta + | undefined; + /** Строка поиска, которая может соответствовать имени пользователя, отображаемому имени или биографии */ + query: string; + /** Параметры пагинации для получения результатов поиска */ + page: PageRequest | undefined; +} + +export interface SearchUserProfilesResponse { + /** Список профилей пользователей, которые соответствуют строке поиска */ + items: UserProfile[]; + /** Информация о пагинации (номер страницы, размер страницы, общее количество результатов) */ + page: PageResponse | undefined; +} + +export interface CheckPermissionsRequest { + meta: + | RequestMeta + | undefined; + /** Контекст субъекта, для которого нужно проверить права (например, идентификатор пользователя, его роли и т.д.) */ + subject: + | SubjectContext + | undefined; + /** Список прав, которые нужно проверить для данного субъекта (например, "read" право на ресурс "chat" с */ + checks: PermissionCheck[]; +} + +export interface CheckPermissionsResponse { + /** Список решений по каждому запрашиваемому праву, указывающий, разрешено ли это право для данного субъекта и причину решения */ + decisions: PermissionDecision[]; +} + +export const GLIFA_CORE_V1_PACKAGE_NAME = "glifa.core.v1"; + +wrappers[".google.protobuf.Struct"] = { fromObject: Struct.wrap, toObject: Struct.unwrap } as any; + +export interface CoreServiceClient { + createDirectChat(request: CreateDirectChatRequest): Observable; + + createGroupChat(request: CreateGroupChatRequest): Observable; + + addChatMember(request: AddChatMemberRequest): Observable; + + removeChatMember(request: RemoveChatMemberRequest): Observable; + + sendMessage(request: SendMessageRequest): Observable; + + editMessage(request: EditMessageRequest): Observable; + + deleteMessage(request: DeleteMessageRequest): Observable; + + getChat(request: GetChatRequest): Observable; + + getMessage(request: GetMessageRequest): Observable; + + getHistory(request: GetHistoryRequest): Observable; + + updateReadCursor(request: UpdateReadCursorRequest): Observable; + + getReadCursor(request: GetReadCursorRequest): Observable; + + getUserProfile(request: GetUserProfileRequest): Observable; + + searchUserProfiles(request: SearchUserProfilesRequest): Observable; + + checkPermissions(request: CheckPermissionsRequest): Observable; +} + +export interface CoreServiceController { + createDirectChat( + request: CreateDirectChatRequest, + ): Promise | Observable | CreateDirectChatResponse; + + createGroupChat( + request: CreateGroupChatRequest, + ): Promise | Observable | CreateGroupChatResponse; + + addChatMember( + request: AddChatMemberRequest, + ): Promise | Observable | AddChatMemberResponse; + + removeChatMember( + request: RemoveChatMemberRequest, + ): Promise | Observable | RemoveChatMemberResponse; + + sendMessage( + request: SendMessageRequest, + ): Promise | Observable | SendMessageResponse; + + editMessage( + request: EditMessageRequest, + ): Promise | Observable | EditMessageResponse; + + deleteMessage( + request: DeleteMessageRequest, + ): Promise | Observable | DeleteMessageResponse; + + getChat(request: GetChatRequest): Promise | Observable | GetChatResponse; + + getMessage( + request: GetMessageRequest, + ): Promise | Observable | GetMessageResponse; + + getHistory( + request: GetHistoryRequest, + ): Promise | Observable | GetHistoryResponse; + + updateReadCursor( + request: UpdateReadCursorRequest, + ): Promise | Observable | UpdateReadCursorResponse; + + getReadCursor( + request: GetReadCursorRequest, + ): Promise | Observable | GetReadCursorResponse; + + getUserProfile( + request: GetUserProfileRequest, + ): Promise | Observable | GetUserProfileResponse; + + searchUserProfiles( + request: SearchUserProfilesRequest, + ): Promise | Observable | SearchUserProfilesResponse; + + checkPermissions( + request: CheckPermissionsRequest, + ): Promise | Observable | CheckPermissionsResponse; +} + +export function CoreServiceControllerMethods() { + return function (constructor: Function) { + const grpcMethods: string[] = [ + "createDirectChat", + "createGroupChat", + "addChatMember", + "removeChatMember", + "sendMessage", + "editMessage", + "deleteMessage", + "getChat", + "getMessage", + "getHistory", + "updateReadCursor", + "getReadCursor", + "getUserProfile", + "searchUserProfiles", + "checkPermissions", + ]; + for (const method of grpcMethods) { + const descriptor: any = Reflect.getOwnPropertyDescriptor(constructor.prototype, method); + GrpcMethod("CoreService", method)(constructor.prototype[method], method, descriptor); + } + const grpcStreamMethods: string[] = []; + for (const method of grpcStreamMethods) { + const descriptor: any = Reflect.getOwnPropertyDescriptor(constructor.prototype, method); + GrpcStreamMethod("CoreService", method)(constructor.prototype[method], method, descriptor); + } + }; +} + +export const CORE_SERVICE_NAME = "CoreService"; diff --git a/gen/glifa/core/v1/types.ts b/gen/glifa/core/v1/types.ts new file mode 100644 index 0000000..e6cef3f --- /dev/null +++ b/gen/glifa/core/v1/types.ts @@ -0,0 +1,170 @@ +// Code generated by protoc-gen-ts_proto. DO NOT EDIT. +// versions: +// protoc-gen-ts_proto v2.11.8 +// protoc v4.25.9 +// source: glifa/core/v1/types.proto + +/* eslint-disable */ +import { wrappers } from "protobufjs"; +import { Struct } from "../../../google/protobuf/struct"; +import { Timestamp } from "../../../google/protobuf/timestamp"; +import { EncryptionMode, MessageContentType } from "../../common/v1/enums"; + +export const protobufPackage = "glifa.core.v1"; + +export enum ChatType { + CHAT_TYPE_UNSPECIFIED = 0, + /** CHAT_TYPE_DIRECT - Прямой чат между двумя пользователями */ + CHAT_TYPE_DIRECT = 1, + /** CHAT_TYPE_GROUP - Групповой чат с несколькими участниками */ + CHAT_TYPE_GROUP = 2, + UNRECOGNIZED = -1, +} + +export enum ChatMemberStatus { + CHAT_MEMBER_STATUS_UNSPECIFIED = 0, + /** CHAT_MEMBER_STATUS_ACTIVE - Участник активно участвует в чате */ + CHAT_MEMBER_STATUS_ACTIVE = 1, + /** CHAT_MEMBER_STATUS_LEFT - Участник покинул чат */ + CHAT_MEMBER_STATUS_LEFT = 2, + /** CHAT_MEMBER_STATUS_REMOVED - Участник был удален из чата */ + CHAT_MEMBER_STATUS_REMOVED = 3, + /** CHAT_MEMBER_STATUS_BANNED - Участник был заблокирован в чате */ + CHAT_MEMBER_STATUS_BANNED = 4, + UNRECOGNIZED = -1, +} + +export enum MessageSendStatus { + MESSAGE_SEND_STATUS_UNSPECIFIED = 0, + /** MESSAGE_SEND_STATUS_ACCEPTED - Сообщение принято в обработку */ + MESSAGE_SEND_STATUS_ACCEPTED = 1, + /** MESSAGE_SEND_STATUS_DEDUPLICATED - Сообщение является дубликатом (например, повторная отправка с тем же client_message_id) */ + MESSAGE_SEND_STATUS_DEDUPLICATED = 2, + UNRECOGNIZED = -1, +} + +export interface UserProfile { + /** UUID пользователя */ + userId: string; + /** Уникальное имя пользователя (например, "john_doe") */ + username: string; + /** Отображаемое имя пользователя (например, "John Doe") */ + displayName: string; + /** Биография пользователя */ + bio: string; + /** UUID медиа-объекта, который используется в качестве аватара пользователя */ + avatarMediaObjectId: string; + /** Время создания профиля пользователя */ + createdAt: + | Timestamp + | undefined; + /** Время последнего обновления профиля пользователя */ + updatedAt: Timestamp | undefined; +} + +export interface Chat { + /** UUID чата */ + id: string; + /** Тип чата (прямой или групповой) */ + type: ChatType; + /** Название чата (для группового чата) */ + title: string; + /** UUID пользователя, который создал чат */ + createdByUserId: string; + /** Последовательный номер последнего сообщения в чате (начинается с 0, увеличивается на 1 для каждого нового сообщения) */ + lastChatSeq: number; + /** UUID последнего сообщения в чате */ + lastMessageId: string; + /** Время создания чата */ + createdAt: + | Timestamp + | undefined; + /** Время последнего обновления чата */ + updatedAt: Timestamp | undefined; +} + +export interface ChatMember { + /** UUID чата, к которому относится этот участник */ + chatId: string; + /** UUID пользователя, который является участником чата */ + userId: string; + /** Статус участника в чате (активный, покинувший, удаленный, заблокированный) */ + status: ChatMemberStatus; + /** Время, когда пользователь присоединился к чату */ + joinedAt: + | Timestamp + | undefined; + /** Время последнего обновления статуса участника в чате */ + updatedAt: Timestamp | undefined; +} + +export interface ChatRole { + /** UUID роли в чате */ + id: string; + /** UUID чата, к которому относится эта роль */ + chatId: string; + /** Уникальный ключ роли (например, "admin", "member") */ + key: string; + /** Человекочитаемое название роли (например, "Администратор", "Участник") */ + title: string; + /** Является ли роль встроенной (например, "admin" и "member" могут быть встроенными ролями, которые нельзя удалить) */ + builtin: boolean; +} + +export interface ChatMessage { + /** UUID сообщения */ + id: string; + /** UUID чата, к которому относится это сообщение */ + chatId: string; + /** Последовательный номер сообщения в рамках чата (начинается с 1 и увеличивается на 1 для каждого нового сообщения в этом чате) */ + chatSeq: number; + /** Уникальный идентификатор сообщения, сгенерированный на клиенте (например, для обеспечения идемпотентности при отправке сообщений) */ + clientMessageId: string; + /** UUID пользователя, который отправил сообщение */ + senderUserId: string; + /** UUID сессии устройства, с которого было отправлено сообщение */ + senderDeviceSessionId: string; + /** Тип содержимого сообщения (например, text, image, file) */ + messageType: MessageContentType; + /** Текст сообщения (используется, если message_type == text) */ + text: string; + /** Имя файла (используется, если message_type == file) */ + fileName: string; + /** UUID сообщения, на которое данное сообщение является ответом (может быть пустым, если это не ответ на другое сообщение) */ + replyToMessageId: string; + /** Режим шифрования сообщения (например, none, client_side) */ + encryptionMode: EncryptionMode; + /** Дополнительные метаданные сообщения в виде */ + metadata: + | { [key: string]: any } + | undefined; + /** Флаг, указывающий, было ли сообщение отредактировано после отправки */ + isEdited: boolean; + /** Версия редактирования сообщения (увеличивается на 1 при каждом редактировании) */ + editVersion: number; + /** Время удаления сообщения (устанавливается, если сообщение было удалено) */ + deletedAt: + | Timestamp + | undefined; + /** Время создания сообщения */ + createdAt: + | Timestamp + | undefined; + /** Время последнего обновления сообщения ( */ + updatedAt: Timestamp | undefined; +} + +export interface ChatReadCursor { + /** UUID чата */ + chatId: string; + /** UUID пользователя */ + userId: string; + /** Последовательный номер сообщения, до которого пользователь прочитал чат (включительно) */ + readChatSeq: number; + /** Время последнего обновления курсора */ + updatedAt: Timestamp | undefined; +} + +export const GLIFA_CORE_V1_PACKAGE_NAME = "glifa.core.v1"; + +wrappers[".google.protobuf.Struct"] = { fromObject: Struct.wrap, toObject: Struct.unwrap } as any; diff --git a/gen/glifa/edge/v1/service.ts b/gen/glifa/edge/v1/service.ts new file mode 100644 index 0000000..01cf5fd --- /dev/null +++ b/gen/glifa/edge/v1/service.ts @@ -0,0 +1,65 @@ +// Code generated by protoc-gen-ts_proto. DO NOT EDIT. +// versions: +// protoc-gen-ts_proto v2.11.8 +// protoc v4.25.9 +// source: glifa/edge/v1/service.proto + +/* eslint-disable */ +import { GrpcMethod, GrpcStreamMethod } from "@nestjs/microservices"; +import { Observable } from "rxjs"; +import { RequestMeta } from "../../common/v1/types"; + +export const protobufPackage = "glifa.edge.v1"; + +export interface HealthRequest { + /** Метаданные запроса, такие как идентификатор корреляции, язык и т.д. */ + meta: RequestMeta | undefined; +} + +export interface HealthResponse { + /** Статус здоровья сервиса, например, "healthy", "degraded", "unhealthy" */ + status: string; +} + +export interface ReadinessRequest { + /** Метаданные запроса, такие как идентификатор корреляции, язык и т.д. */ + meta: RequestMeta | undefined; +} + +export interface ReadinessResponse { + /** Статус готовности сервиса, например, "ready", "not_ready" */ + status: string; + /** Список проверок, которые были выполнены для определения готовности сервиса, и их результаты (например, "database: ok", "cache: ok", "external_api: timeout") */ + checks: string[]; +} + +export const GLIFA_EDGE_V1_PACKAGE_NAME = "glifa.edge.v1"; + +export interface EdgeGagewayServiceClient { + health(request: HealthRequest): Observable; + + readiness(request: ReadinessRequest): Observable; +} + +export interface EdgeGagewayServiceController { + health(request: HealthRequest): Promise | Observable | HealthResponse; + + readiness(request: ReadinessRequest): Promise | Observable | ReadinessResponse; +} + +export function EdgeGagewayServiceControllerMethods() { + return function (constructor: Function) { + const grpcMethods: string[] = ["health", "readiness"]; + for (const method of grpcMethods) { + const descriptor: any = Reflect.getOwnPropertyDescriptor(constructor.prototype, method); + GrpcMethod("EdgeGagewayService", method)(constructor.prototype[method], method, descriptor); + } + const grpcStreamMethods: string[] = []; + for (const method of grpcStreamMethods) { + const descriptor: any = Reflect.getOwnPropertyDescriptor(constructor.prototype, method); + GrpcStreamMethod("EdgeGagewayService", method)(constructor.prototype[method], method, descriptor); + } + }; +} + +export const EDGE_GAGEWAY_SERVICE_NAME = "EdgeGagewayService"; diff --git a/gen/glifa/events/v1/auth_events.ts b/gen/glifa/events/v1/auth_events.ts new file mode 100644 index 0000000..c1e0365 --- /dev/null +++ b/gen/glifa/events/v1/auth_events.ts @@ -0,0 +1,127 @@ +// Code generated by protoc-gen-ts_proto. DO NOT EDIT. +// versions: +// protoc-gen-ts_proto v2.11.8 +// protoc v4.25.9 +// source: glifa/events/v1/auth_events.proto + +/* eslint-disable */ +import { Timestamp } from "../../../google/protobuf/timestamp"; + +export const protobufPackage = "glifa.events.v1"; + +export interface AuthUserCreated { + /** UUID нового пользователя */ + userId: string; + /** Имя пользователя */ + username: string; + /** Электронная почта пользователя */ + email: string; + /** Номер телефона пользователя */ + phone: string; + /** Время создания пользователя */ + createdAt: Timestamp | undefined; +} + +export interface AuthUserUpdated { + /** UUID пользователя */ + userId: string; + /** Новое имя пользователя (если изменилось) */ + username: string; + /** Новое отображаемое имя пользователя (если изменилось) */ + displayName: string; + /** UUID нового аватара пользователя (если изменился) */ + avatarMediaObjectId: string; + /** Время обновления пользователя */ + updatedAt: Timestamp | undefined; +} + +export interface AuthUserBlocked { + /** UUID заблокированного пользователя */ + userId: string; + /** Причина блокировки пользователя */ + reason: string; + /** Время блокировки пользователя */ + blockedAt: Timestamp | undefined; +} + +export interface AuthSessionCreated { + /** UUID новой сессии */ + sessionId: string; + /** UUID пользователя, которому принадлежит сессия */ + userId: string; + /** UUID устройства, с которого была создана сессия */ + deviceId: string; + /** Статус сессии (например, "active", "inactive") */ + status: string; + /** Время создания сессии */ + createdAt: Timestamp | undefined; +} + +export interface AuthSessionLocked { + /** UUID заблокированной сессии */ + sessionId: string; + /** UUID пользователя, которому принадлежит сессия */ + userId: string; + /** Причина блокировки сессии */ + reason: string; + /** Время блокировки сессии */ + lockedAt: Timestamp | undefined; +} + +export interface AuthSessionUnlocked { + /** UUID разблокированной сессии */ + sessionId: string; + /** UUID пользователя, которому принадлежит сессия */ + userId: string; + /** Время разблокировки сессии */ + unlockedAt: Timestamp | undefined; +} + +export interface AuthSessionRevoked { + /** UUID отозванной сессии */ + sessionId: string; + /** UUID пользователя, которому принадлежит сессия */ + userId: string; + /** Причина отзыва сессии */ + reason: string; + /** Время отзыва сессии */ + revokedAt: Timestamp | undefined; +} + +export interface AuthSessionCompromised { + /** UUID скомпрометированной сессии */ + sessionId: string; + /** UUID пользователя, которому принадлежит сессия */ + userId: string; + /** Причина компрометации сессии */ + reason: string; + /** Время компрометации сессии */ + compromisedAt: Timestamp | undefined; +} + +export interface AuthQrRequestCreated { + /** UUID нового QR-запроса */ + requestId: string; + /** Время истечения срока действия QR-запроса */ + expiresAt: Timestamp | undefined; +} + +export interface AuthQrRequestApproved { + /** UUID одобренного QR-запроса */ + requestId: string; + /** UUID пользователя, который одобрил QR-запрос */ + approvingUserId: string; + /** UUID сессии, с которой был одобрен QR-запрос */ + approvingSessionId: string; + /** Время одобрения QR-запроса */ + approvedAt: Timestamp | undefined; +} + +export interface AuthQrRequestExpired { + /** UUID истекшего QR-запроса */ + requestId: string; + /** Время истечения срока действия QR-запроса */ + expiredAt: Timestamp | undefined; +} + +export const GLIFA_EVENTS_V1_PACKAGE_NAME = "glifa.events.v1"; diff --git a/gen/glifa/events/v1/channel_events.ts b/gen/glifa/events/v1/channel_events.ts new file mode 100644 index 0000000..7e57189 --- /dev/null +++ b/gen/glifa/events/v1/channel_events.ts @@ -0,0 +1,87 @@ +// Code generated by protoc-gen-ts_proto. DO NOT EDIT. +// versions: +// protoc-gen-ts_proto v2.11.8 +// protoc v4.25.9 +// source: glifa/events/v1/channel_events.proto + +/* eslint-disable */ +import { Timestamp } from "../../../google/protobuf/timestamp"; +import { MessageContentType } from "../../common/v1/enums"; + +export const protobufPackage = "glifa.events.v1"; + +export interface ChannelCreated { + /** UUID канала, который был создан */ + channelId: string; + /** Уникальный идентификатор канала (например, "general", "random") */ + handle: string; + /** Название канала */ + title: string; + /** UUID пользователя, который создал канал */ + ownerUserId: string; + /** Время создания канала */ + createdAt: Timestamp | undefined; +} + +export interface ChannelSubscriberAdded { + /** UUID канала, в который был добавлен подписчик */ + channelId: string; + /** UUID пользователя, который был добавлен в канал */ + userId: string; + /** Время добавления подписчика в канал */ + addedAt: Timestamp | undefined; +} + +export interface ChannelSubscriberRemoved { + /** UUID канала, из которого был удален подписчик */ + channelId: string; + /** UUID пользователя, который был удален из канала */ + userId: string; + /** Время удаления подписчика из канала */ + removedAt: Timestamp | undefined; +} + +export interface ChannelPostCreated { + /** UUID созданного поста */ + postId: string; + /** UUID канала, в котором был создан пост */ + channelId: string; + /** Последовательный номер поста в рамках канала (начинается с 1 и увеличивается на 1 для каждого нового поста в канале) */ + postSeq: number; + /** Идентификатор поста, сгенерированный на клиенте (для обеспечения идемпотентности при повторной отправке) */ + clientPostId: string; + /** UUID пользователя, который создал пост */ + authorUserId: string; + /** Тип контента поста (например, "text", "image", "file") */ + messageType: MessageContentType; + /** Текст поста (если message_type == "text") */ + text: string; + /** UUID файла, прикрепленного к посту (если message_type == "file") */ + fileId: string; + /** Время создания поста */ + createdAt: Timestamp | undefined; +} + +export interface ChannelPostEdited { + /** UUID отредактированного поста */ + postId: string; + /** UUID канала, в котором был создан пост */ + channelId: string; + /** Версия редактирования поста (начинается с 1 и увеличивается на 1 для каждого редактирования поста) */ + editVersion: string; + /** Новый текст поста (если message_type == "text") */ + text: string; + /** Время редактирования поста */ + updatedAt: Timestamp | undefined; +} + +export interface ChannelPostDeleted { + /** UUID удаленного поста */ + postId: string; + /** UUID канала, в котором был создан пост */ + channelId: string; + /** Время удаления поста */ + deletedAt: Timestamp | undefined; +} + +export const GLIFA_EVENTS_V1_PACKAGE_NAME = "glifa.events.v1"; diff --git a/gen/glifa/events/v1/core_events.ts b/gen/glifa/events/v1/core_events.ts new file mode 100644 index 0000000..41bb8c4 --- /dev/null +++ b/gen/glifa/events/v1/core_events.ts @@ -0,0 +1,126 @@ +// Code generated by protoc-gen-ts_proto. DO NOT EDIT. +// versions: +// protoc-gen-ts_proto v2.11.8 +// protoc v4.25.9 +// source: glifa/events/v1/core_events.proto + +/* eslint-disable */ +import { Timestamp } from "../../../google/protobuf/timestamp"; +import { EncryptionMode, MessageContentType } from "../../common/v1/enums"; + +export const protobufPackage = "glifa.events.v1"; + +export interface CoreUserProfileCreated { + /** UUID пользователя, для которого создан профиль */ + userId: string; + /** Имя пользователя */ + username: string; + /** Отображаемое имя пользователя */ + displayName: string; + /** Время создания профиля пользователя */ + createdAt: Timestamp | undefined; +} + +export interface CoreUserProfileUpdated { + /** UUID пользователя, чей профиль был обновлен */ + userId: string; + /** Новое отображаемое имя пользователя (если изменилось) */ + displayName: string; + /** Новая биография пользователя (если изменилось) */ + bio: string; + /** UUID нового аватара пользователя (если изменился) */ + avatarMediaObjectId: string; + /** Время обновления профиля пользователя */ + updatedAt: Timestamp | undefined; +} + +export interface CoreChatMemberAdded { + /** UUID чата, в который был добавлен участник */ + chatId: string; + /** UUID пользователя, который был добавлен в чат */ + userId: string; + /** Время добавления участника в чат */ + addedAt: Timestamp | undefined; +} + +export interface CoreChatMemberRemoved { + /** UUID чата, из которого был удален участник */ + chatId: string; + /** UUID пользователя, который был удален из чата */ + userId: string; + /** Время удаления участника из чата */ + removedAt: Timestamp | undefined; +} + +export interface CoreChatRoleAssigned { + /** UUID чата, в котором была назначена роль */ + chatId: string; + /** UUID пользователя, которому была назначена роль */ + userId: string; + /** Ключ роли, которая была назначена пользователю (например, "admin", "moderator") */ + roleKey: string; + /** Время назначения роли пользователю в ч */ + assignedAt: Timestamp | undefined; +} + +export interface CoreMessageCreated { + /** UUID созданного сообщения */ + messageId: string; + /** UUID чата, в котором было создано сообщение */ + chatId: string; + /** Последовательный номер сообщения в рамках чата (начинается с 1 и увеличивается на 1 для каждого нового сообщения в чате) */ + chatSeq: string; + /** Идентификатор сообщения, сгенерированный на клиенте (для обеспечения идемпотентности при повторной отправке) */ + clientMessageId: string; + /** UUID пользователя, который отправил сообщение */ + senderUserId: string; + /** UUID сессии, с которой было отправлено сообщение */ + senderSessionId: string; + /** Тип контента сообщения (например, "text", "image", "file") */ + messageType: MessageContentType; + /** Режим шифрования сообщения (например, "none", "end-to-end") */ + encryptionMode: EncryptionMode; + /** Текст сообщения (если message_type == "text") */ + text: string; + /** UUID файла, прикрепленного к сообщению (если message_type == "file") */ + fileId: string; + /** UUID сообщения, на которое был дан ответ (если это сообщение является ответом) */ + replyToMessageId: string; + /** Время создания сообщения */ + createdAt: Timestamp | undefined; +} + +export interface CoreMessageEdited { + /** UUID отредактированного сообщения */ + messageId: string; + /** UUID чата, в котором было отредактировано сообщение */ + chatId: string; + /** Версия редактирования сообщения (начинается с 1 и увеличивается на 1 для каждого нового редактирования) */ + editVersion: string; + /** Новый текст сообщения (если message_type == "text") */ + text: string; + /** Время редактирования сообщения */ + updatedAt: Timestamp | undefined; +} + +export interface CoreMessageDeleted { + /** UUID удаленного сообщения */ + messageId: string; + /** UUID чата, в котором было удалено сообщение */ + chatId: string; + /** Время удаления сообщения */ + deletedAt: Timestamp | undefined; +} + +export interface CoreMessageReadUpdated { + /** UUID чата, в котором было обновлено состояние прочтения сообщений */ + chatId: string; + /** UUID пользователя, который прочитал сообщения */ + userId: string; + /** Максимальный последовательный номер сообщения, который пользователь прочитал в чате (включительно) */ + readChatSeq: number; + /** Время обновления состояния прочтения */ + updatedAt: Timestamp | undefined; +} + +export const GLIFA_EVENTS_V1_PACKAGE_NAME = "glifa.events.v1"; diff --git a/gen/glifa/events/v1/eventlope.ts b/gen/glifa/events/v1/eventlope.ts new file mode 100644 index 0000000..82f8a41 --- /dev/null +++ b/gen/glifa/events/v1/eventlope.ts @@ -0,0 +1,42 @@ +// Code generated by protoc-gen-ts_proto. DO NOT EDIT. +// versions: +// protoc-gen-ts_proto v2.11.8 +// protoc v4.25.9 +// source: glifa/events/v1/eventlope.proto + +/* eslint-disable */ +import { Any } from "../../../google/protobuf/any"; +import { Timestamp } from "../../../google/protobuf/timestamp"; + +export const protobufPackage = "glifa.events.v1"; + +export interface DurableEventEventlope { + /** UUID события */ + eventId: string; + /** Тип события (например, "user.created", " */ + eventType: string; + /** Версия схемы данных события */ + eventVersion: number; + /** Идентификатор системы, которая сгенерировала событие */ + producer: string; + /** Тип агрегата, к которому относится событие (например, "user", "order") */ + aggregateType: string; + /** UUID агрегата, к которому относится событие */ + aggregateId: string; + /** Ключ для партиционирования (например, "user_id" или "order_id") */ + partitionKey: string; + /** Время возникновения события */ + occurredAt: + | Timestamp + | undefined; + /** UUID для распределенного трейсинга */ + traceId: string; + /** UUID для корреляции логов */ + correlationId: string; + /** UUID для идемпотентности операций */ + idempotencyKey: string; + /** Данные события в виде сериализованного protobuf-сообщения (может быть любым типом, в зависимости от event_type) */ + payload: Any | undefined; +} + +export const GLIFA_EVENTS_V1_PACKAGE_NAME = "glifa.events.v1"; diff --git a/gen/glifa/events/v1/media_events.ts b/gen/glifa/events/v1/media_events.ts new file mode 100644 index 0000000..2221c2b --- /dev/null +++ b/gen/glifa/events/v1/media_events.ts @@ -0,0 +1,61 @@ +// Code generated by protoc-gen-ts_proto. DO NOT EDIT. +// versions: +// protoc-gen-ts_proto v2.11.8 +// protoc v4.25.9 +// source: glifa/events/v1/media_events.proto + +/* eslint-disable */ +import { Timestamp } from "../../../google/protobuf/timestamp"; + +export const protobufPackage = "glifa.events.v1"; + +export interface MediaUploadInitiated { + /** UUID намерения загрузки, который будет использоваться для идентификации процесса загрузки */ + uploadIntentId: string; + /** UUID пользователя, который инициализировал загрузку */ + ownerUserId: string; + /** Время инициализации загрузки медиа */ + initiatedAt: Timestamp | undefined; +} + +export interface MediaUploadFinalized { + /** UUID намерения загрузки, который был использован для идентификации процесса загрузки */ + uploadIntentId: string; + /** UUID созданного медиа-объекта после успешной загрузки */ + mediaObjectId: string; + /** Время финализации загрузки медиа */ + finalizedAt: Timestamp | undefined; +} + +export interface MediaObjectActivated { + /** UUID медиа-объекта, который был активирован */ + mediaObjectId: string; + /** UUID пользователя, который активировал медиа-объект */ + ownerUserId: string; + /** Видимость медиа-объекта (например, "public", "private", "unlisted") */ + visibility: string; + /** Время активации медиа-объекта (когда он стал доступен для использования) */ + activatedAt: Timestamp | undefined; +} + +export interface MediaObjectQuarantined { + /** UUID медиа-объекта, который был помещен в карантин */ + mediaObjectId: string; + /** Причина помещения медиа-объекта в карантин (например, "inappropriate_content", "copyright_violation") */ + reason: string; + /** Время помещения медиа-объекта в карантин */ + quarantinedAt: Timestamp | undefined; +} + +export interface MediaVariantCreated { + /** UUID созданного варианта медиа-объекта */ + mediaVariantId: string; + /** UUID медиа-объекта, для которого был создан вариант */ + mediaObjectId: string; + /** Тип варианта (например, "thumbnail", "preview", "full") */ + variantKind: string; + /** Время создания варианта медиа-объекта */ + createdAt: Timestamp | undefined; +} + +export const GLIFA_EVENTS_V1_PACKAGE_NAME = "glifa.events.v1"; diff --git a/gen/glifa/media/v1/service.ts b/gen/glifa/media/v1/service.ts new file mode 100644 index 0000000..df8150c --- /dev/null +++ b/gen/glifa/media/v1/service.ts @@ -0,0 +1,249 @@ +// Code generated by protoc-gen-ts_proto. DO NOT EDIT. +// versions: +// protoc-gen-ts_proto v2.11.8 +// protoc v4.25.9 +// source: glifa/media/v1/service.proto + +/* eslint-disable */ +import { GrpcMethod, GrpcStreamMethod } from "@nestjs/microservices"; +import { Observable } from "rxjs"; +import { RequestMeta } from "../../common/v1/types"; +import { MediaAccessGrant, MediaObject, MediaVisibility, UploadIntent, UploadPart } from "./types"; + +export const protobufPackage = "glifa.media.v1"; + +export interface InitiateUploadRequest { + /** Метаданные запроса, такие как идентификатор корреляции, язык и т.д. */ + meta: + | RequestMeta + | undefined; + /** Исходное имя файла, который будет загружен */ + fileName: string; + /** MIME-тип файла, который будет загружен (например, "image/jpeg", "video/mp4") */ + declaredMimeType: string; + /** Ожидаемый размер файла в байтах, который будет загружен */ + expectedSize: number; + /** Флаг, указывающий, будет ли загрузка выполняться в несколько частей (multipart upload) */ + multipart: boolean; + /** Видимость медиа-объекта (публичный или приватный) */ + visibility: MediaVisibility; +} + +export interface InitiateUploadResponse { + /** Намерение загрузки, содержащее информацию о процессе загрузки и его статусе */ + uploadIntent: UploadIntent | undefined; +} + +export interface PresignPartUploadRequest { + /** Метаданные запроса, такие как идентификатор корреляции, язык и т.д. */ + meta: + | RequestMeta + | undefined; + /** UUID намерения загрузки, к которому относится эта часть */ + uploadIntentId: string; + /** Номер части в последовательности загрузки (начинается с 1) */ + partNumber: number; +} + +export interface PresignPartUploadResponse { + /** Предварительно подписанный URL для загрузки части файла в хранилище */ + url: string; + /** Дополнительные заголовки, которые должны быть включены в запрос загрузки части (например, для аутентификации или указания типа контента) */ + headers: { [key: string]: string }; +} + +export interface PresignPartUploadResponse_HeadersEntry { + key: string; + value: string; +} + +export interface CompletePartRequest { + /** Метаданные запроса, такие как идентификатор корреляции, язык и т.д. */ + meta: + | RequestMeta + | undefined; + /** UUID намерения загрузки, к которому относится эта часть */ + uploadIntentId: string; + /** Номер части в последовательности загрузки (начинается с 1) */ + partNumber: number; + /** ETag, возвращаемый хранилищем после успешной загрузки части, который будет использоваться для финализации загрузки */ + etag: string; + /** Размер части в байтах */ + size: number; +} + +export interface CompletePartResponse { + /** Информация о загруженной части, включая номер части, ETag и размер */ + part: UploadPart | undefined; +} + +export interface FinalizeUploadRequest { + /** Метаданные запроса, такие как идентификатор корреляции, язык и т.д. */ + meta: + | RequestMeta + | undefined; + /** UUID намерения загрузки, который будет финализирован */ + uploadIntentId: string; + /** Контрольная сумма (например, MD5 или SHA-256) всего файла, который был загружен, для проверки целостности данных */ + checksum: string; +} + +export interface FinalizeUploadResponse { + /** Намерение загрузки с обновленным статусом, указывающим, что загрузка была успешно завершена */ + uploadIntent: + | UploadIntent + | undefined; + /** Информация о созданном медиа-объекте, включая его UUID, размер, MIME-тип и т.д. */ + mediaObject: MediaObject | undefined; +} + +export interface AbortUploadRequest { + /** Метаданные запроса, такие как идентификатор корреляции, язык и т.д. */ + meta: + | RequestMeta + | undefined; + /** UUID намерения загрузки, который будет прерван */ + uploadIntentId: string; +} + +export interface AbortUploadResponse { + /** Флаг, указывающий, была ли операция прерывания успешной */ + success: boolean; +} + +export interface GetMediaObjectRequest { + /** Метаданные запроса, такие как идентификатор корреляции, язык и т.д. */ + meta: + | RequestMeta + | undefined; + /** UUID медиа-объекта, который пользователь хочет получить */ + mediaObjectId: string; +} + +export interface GetMediaObjectResponse { + /** Информация о запрошенном медиа-объекте, включая его UUID, размер, MIME-тип, статус и т.д. */ + mediaObject: MediaObject | undefined; +} + +export interface CreateAccessGrantRequest { + /** Метаданные запроса, такие как идентификатор корреляции, язык и т.д. */ + meta: + | RequestMeta + | undefined; + /** UUID медиа-объекта, для которого создается грант доступа */ + mediaObjectId: string; + /** UUID пользователя, которому предоставляется доступ к медиа-объекту */ + subjectUserId: string; + /** Флаг, указывающий, является ли грант доступа одноразовым (может быть использован только один раз для доступа к медиа-объекту) */ + singleUse: boolean; +} + +export interface CreateAccessGrantResponse { + /** Информация о созданном гранте доступа, включая его UUID, связанный медиа-объект, субъект доступа и т.д. */ + grant: MediaAccessGrant | undefined; +} + +export interface ResolveDownloadRequest { + /** Метаданные запроса, такие как идентификатор корреляции, язык и т.д. */ + meta: + | RequestMeta + | undefined; + /** UUID медиа-объекта, который пользователь хочет скачать */ + mediaObjectId: string; + /** UUID гранта доступа, который будет использоваться для авторизации доступа к медиа-объекту при скачивании */ + accessGrantId: string; +} + +export interface ResolveDownloadResponse { + /** Предварительно подписанный URL для скачивания файла медиа-объекта из хранилища */ + url: string; + /** Дополнительные заголовки, которые должны быть включены в запрос скачивания файла (например, для аутентификации или указания типа контента) */ + headers: { [key: string]: string }; + /** HTTP-метод, который должен быть использован для скачивания файла (например, "GET", "POST") */ + method: string; +} + +export interface ResolveDownloadResponse_HeadersEntry { + key: string; + value: string; +} + +export const GLIFA_MEDIA_V1_PACKAGE_NAME = "glifa.media.v1"; + +export interface MediaServiceClient { + initiateUpload(request: InitiateUploadRequest): Observable; + + presignPartUpload(request: PresignPartUploadRequest): Observable; + + completePart(request: CompletePartRequest): Observable; + + finalizeUpload(request: FinalizeUploadRequest): Observable; + + abortUpload(request: AbortUploadRequest): Observable; + + getMediaObject(request: GetMediaObjectRequest): Observable; + + createAccessGrant(request: CreateAccessGrantRequest): Observable; + + resolveDownload(request: ResolveDownloadRequest): Observable; +} + +export interface MediaServiceController { + initiateUpload( + request: InitiateUploadRequest, + ): Promise | Observable | InitiateUploadResponse; + + presignPartUpload( + request: PresignPartUploadRequest, + ): Promise | Observable | PresignPartUploadResponse; + + completePart( + request: CompletePartRequest, + ): Promise | Observable | CompletePartResponse; + + finalizeUpload( + request: FinalizeUploadRequest, + ): Promise | Observable | FinalizeUploadResponse; + + abortUpload( + request: AbortUploadRequest, + ): Promise | Observable | AbortUploadResponse; + + getMediaObject( + request: GetMediaObjectRequest, + ): Promise | Observable | GetMediaObjectResponse; + + createAccessGrant( + request: CreateAccessGrantRequest, + ): Promise | Observable | CreateAccessGrantResponse; + + resolveDownload( + request: ResolveDownloadRequest, + ): Promise | Observable | ResolveDownloadResponse; +} + +export function MediaServiceControllerMethods() { + return function (constructor: Function) { + const grpcMethods: string[] = [ + "initiateUpload", + "presignPartUpload", + "completePart", + "finalizeUpload", + "abortUpload", + "getMediaObject", + "createAccessGrant", + "resolveDownload", + ]; + for (const method of grpcMethods) { + const descriptor: any = Reflect.getOwnPropertyDescriptor(constructor.prototype, method); + GrpcMethod("MediaService", method)(constructor.prototype[method], method, descriptor); + } + const grpcStreamMethods: string[] = []; + for (const method of grpcStreamMethods) { + const descriptor: any = Reflect.getOwnPropertyDescriptor(constructor.prototype, method); + GrpcStreamMethod("MediaService", method)(constructor.prototype[method], method, descriptor); + } + }; +} + +export const MEDIA_SERVICE_NAME = "MediaService"; diff --git a/gen/glifa/media/v1/types.ts b/gen/glifa/media/v1/types.ts new file mode 100644 index 0000000..e81fa33 --- /dev/null +++ b/gen/glifa/media/v1/types.ts @@ -0,0 +1,144 @@ +// Code generated by protoc-gen-ts_proto. DO NOT EDIT. +// versions: +// protoc-gen-ts_proto v2.11.8 +// protoc v4.25.9 +// source: glifa/media/v1/types.proto + +/* eslint-disable */ +import { Timestamp } from "../../../google/protobuf/timestamp"; + +export const protobufPackage = "glifa.media.v1"; + +export enum UploadIntentStatus { + /** UPLOAD_INTENT_STATUS_UNSPECIFIED - Неопределенный статус намерения загрузки */ + UPLOAD_INTENT_STATUS_UNSPECIFIED = 0, + /** UPLOAD_INTENT_STATUS_INITIATED - Намерение загрузки было инициализировано, но загрузка еще не началась */ + UPLOAD_INTENT_STATUS_INITIATED = 1, + /** UPLOAD_INTENT_STATUS_UPLOADING - Процесс загрузки медиа-объекта начался, но еще не завершился */ + UPLOAD_INTENT_STATUS_UPLOADING = 2, + /** UPLOAD_INTENT_STATUS_FINALIZED - Процесс загрузки медиа-объекта успешно завершился, и медиа-объект был создан */ + UPLOAD_INTENT_STATUS_FINALIZED = 3, + /** UPLOAD_INTENT_STATUS_ABORTED - Процесс загрузки был прерван или отменен до его завершения */ + UPLOAD_INTENT_STATUS_ABORTED = 4, + /** UPLOAD_INTENT_STATUS_EXPIRED - Намерение загрузки истекло, и загрузка не может быть завершена */ + UPLOAD_INTENT_STATUS_EXPIRED = 5, + UNRECOGNIZED = -1, +} + +export enum MediaObjectStatus { + /** MEDIA_OBJECT_STATUS_UNSPECIFIED - Неопределенный статус медиа-объекта */ + MEDIA_OBJECT_STATUS_UNSPECIFIED = 0, + /** MEDIA_OBJECT_STATUS_PENDING - Медиа-объект находится в ожидании обработки (например, конвертации или проверки) */ + MEDIA_OBJECT_STATUS_PENDING = 1, + /** MEDIA_OBJECT_STATUS_ACTIVE - Медиа-объект активен и доступен для использования */ + MEDIA_OBJECT_STATUS_ACTIVE = 2, + /** MEDIA_OBJECT_STATUS_QUARANTINED - Медиа-объект помещен в карантин из-за подозрения на нарушение правил (например, неподобающий контент) */ + MEDIA_OBJECT_STATUS_QUARANTINED = 3, + /** MEDIA_OBJECT_STATUS_DELETED - Медиа-объект удален и больше не доступен */ + MEDIA_OBJECT_STATUS_DELETED = 4, + UNRECOGNIZED = -1, +} + +export enum MediaVisibility { + /** MEDIA_VISIBILITY_UNSPECIFIED - Неопределенная видимость медиа-объекта */ + MEDIA_VISIBILITY_UNSPECIFIED = 0, + /** MEDIA_VISIBILITY_PUBLIC - Медиа-объект публичный и доступен всем пользователям */ + MEDIA_VISIBILITY_PUBLIC = 1, + /** MEDIA_VISIBILITY_PRIVATE - Медиа-объект приватный и доступен только владельцу */ + MEDIA_VISIBILITY_PRIVATE = 2, + UNRECOGNIZED = -1, +} + +export interface UploadIntent { + /** UUID намерения загрузки, который будет использоваться для идентификации процесса загрузки */ + id: string; + /** UUID пользователя, который инициализировал */ + ownerUserId: string; + /** Исходное имя файла, который будет загружен */ + fileName: string; + /** MIME-тип файла, который будет загружен (например, "image/jpeg", "video/mp4") */ + declaredMimeType: string; + /** Ожидаемый размер файла в байтах, который будет загружен */ + expectedSize: number; + /** Флаг, указывающий, будет ли загрузка выполняться в несколько частей (multipart upload) */ + multipart: boolean; + /** Текущий статус намерения загрузки */ + status: UploadIntentStatus; + /** Временная метка, указывающая, когда намерение загрузки истекает и больше не может быть использовано для загрузки файла */ + expiresAt: + | Timestamp + | undefined; + /** Временная метка создания намерения загрузки */ + createdAt: + | Timestamp + | undefined; + /** Временная метка последнего обновления намерения загрузки */ + updatedAt: Timestamp | undefined; +} + +export interface UploadPart { + /** UUID намерения загрузки, к которому относится эта часть */ + uploadIntentId: string; + /** Номер части в последовательности загрузки (начинается с 1) */ + partNumber: number; + /** ETag, возвращаемый хранилищем после успешной загрузки части, который будет использоваться для финализации загрузки */ + etag: string; + /** Размер части в байтах */ + size: number; + /** Временная метка, указывающая, когда эта часть была успешно загружена */ + completedAt: Timestamp | undefined; +} + +export interface MediaObject { + /** UUID медиа-объекта, который будет использоваться для идентификации и доступа к медиа-объекту */ + id: string; + /** UUID пользователя, которому принадлежит этот медиа-объект */ + ownerUserId: string; + /** Ключ объекта в хранилище, который указывает на местоположение файла медиа-объекта */ + objectKey: string; + /** Контрольная сумма (например, MD5 или SHA-256) файла медиа-объекта, которая может использоваться для проверки целостности данных */ + checksum: string; + /** Размер файла медиа-объекта в бай */ + size: number; + /** MIME-тип, определенный после загрузки и анализа файла медиа-объекта */ + detectedMimeType: string; + /** Видимость медиа-объекта (публичный или приватный) */ + visibility: MediaVisibility; + /** Текущий статус медиа-объекта (например, ожидает обработки, активен, в карантине, удален) */ + status: MediaObjectStatus; + /** Ссылка на ключ шифрования, если медиа-объект зашифрован */ + encryptionKeyRef: string; + /** Тип ресурса, с которым связан этот медиа-объект (например, "post", "profile_picture", "document") */ + linkResourceType: string; + /** UUID ресурса, с которым связан этот медиа-объект (например, идентификатор поста, идентификатор профиля пользователя, идентификатор документа) */ + linkResourceId: string; + /** Временная метка создания медиа-объекта */ + createdAt: + | Timestamp + | undefined; + /** Временная метка последнего обновления медиа-объекта */ + updatedAt: Timestamp | undefined; +} + +export interface MediaAccessGrant { + /** UUID разрешения доступа, который будет использоваться для идентификации и управления разрешением доступа */ + id: string; + /** UUID медиа-объекта, к */ + mediaObjectId: string; + /** UUID пользователя, которому предоставлено разрешение доступа к медиа-объекту */ + subjectUserId: string; + /** Флаг, указывающий, является ли это разрешение одноразовым (single-use), которое может быть использовано только один раз для доступа к медиа-объекту */ + singleUse: boolean; + /** Временная метка, указывающая, когда разрешение доступа истекает и больше не может быть использовано для доступа к медиа-объекту */ + expiresAt: + | Timestamp + | undefined; + /** Временная метка, указывающая, когда это разрешение доступа было использовано для доступа к медиа-объекту (для одноразовых разрешений) */ + consumedAt: + | Timestamp + | undefined; + /** Временная метка создания разрешения доступа */ + createdAt: Timestamp | undefined; +} + +export const GLIFA_MEDIA_V1_PACKAGE_NAME = "glifa.media.v1"; diff --git a/gen/glifa/ws/v1/service.ts b/gen/glifa/ws/v1/service.ts new file mode 100644 index 0000000..53b6ef5 --- /dev/null +++ b/gen/glifa/ws/v1/service.ts @@ -0,0 +1,173 @@ +// Code generated by protoc-gen-ts_proto. DO NOT EDIT. +// versions: +// protoc-gen-ts_proto v2.11.8 +// protoc v4.25.9 +// source: glifa/ws/v1/service.proto + +/* eslint-disable */ +import { GrpcMethod, GrpcStreamMethod } from "@nestjs/microservices"; +import { Observable } from "rxjs"; +import { RequestMeta } from "../../common/v1/types"; +import { ConnectionInfo, PresenceState, RealtimeEnvelope, TypingState } from "./types"; + +export const protobufPackage = "glifa.ws.v1"; + +export interface RegisterConnectionRequest { + /** Метаданные запроса, такие как идентификатор корреляции, язык и т.д. */ + meta: + | RequestMeta + | undefined; + /** Токен доступа, который будет использоваться для аутентификации и авторизации соединения */ + accessToken: string; + /** Уникальный идентификатор соединения, который может быть сгенерирован клиентом или сервером для отслеживания этого соединения */ + connectionId: string; + /** Идентификатор узла, к которому подключается это соединение, если используется распределенная архитектура с несколькими узлами */ + nodeId: string; +} + +export interface RegisterConnectionResponse { + /** Информация о зарегистрированном соединении, включая его статус и метаданные */ + connection: ConnectionInfo | undefined; +} + +export interface UnregisterConnectionRequest { + /** Метаданные запроса, такие как идентификатор корреляции, язык и т.д. */ + meta: + | RequestMeta + | undefined; + /** Уникальный идентификатор соединения, которое должно быть удалено или разорвано */ + connectionId: string; +} + +export interface UnregisterConnectionResponse { + /** Флаг, указывающий, было ли соединение успешно удалено или разорвано */ + success: boolean; +} + +export interface PublishEnvelopeRequest { + /** Метаданные запроса, такие как идентификатор корреляции, язык и т.д. */ + meta: + | RequestMeta + | undefined; + /** Список UUID пользователей, которые являются целевыми получателями этого сообщения, и которым должно быть доставлено это сообщение */ + targetUserIds: string[]; + /** Список UUID сессий, которые являются целевыми получателями этого сообщения, и которым должно быть доставлено это сообщение */ + targetSessionIds: string[]; + /** Список UUID каналов или тем, на которые подписаны получатели, которым должно быть доставлено это сообщение */ + targetChannelIds: string[]; + /** Конверт в реальном времени, который содержит данные и метаданные сообщения, которое должно быть доставлено получателям */ + envelope: RealtimeEnvelope | undefined; +} + +export interface PublishEnvelopeResponse { + /** Количество целевых получателей, которым было принято это сообщение для доставки (например, количество пользователей, сессий или каналов, которым было отправлено это сообщение) */ + acceptedTargets: number; +} + +export interface PublishPresenceRequest { + /** Метаданные запроса, такие как идентификатор корреляции, язык и т.д. */ + meta: + | RequestMeta + | undefined; + /** Состояние присутствия пользователя, которое должно быть опубликовано и доставлено подписчикам */ + presence: PresenceState | undefined; +} + +export interface PublishPresenceResponse { + /** Флаг, указывающий, было ли состояние присутствия успешно опубликовано и доставлено подписчикам */ + success: boolean; +} + +export interface PublishTypingRequest { + /** Метаданные запроса, такие как идентификатор корреляции, язык и т.д. */ + meta: + | RequestMeta + | undefined; + /** Состояние печати пользователя, которое должно быть опубликовано и доставлено подписчикам */ + typing: TypingState | undefined; +} + +export interface PublishTypingResponse { + /** Флаг, указывающий, было ли состояние печати успешно опубликовано и доставлено подписчикам */ + success: boolean; +} + +export interface ListUserConnectionsRequest { + /** Метаданные запроса, такие как идентификатор корреляции, язык и т.д. */ + meta: + | RequestMeta + | undefined; + /** UUID пользователя, для которого нужно получить список активных соединений */ + userId: string; +} + +export interface ListUserConnectionsResponse { + /** Список активных соединений, связанных с указанным пользователем, включая их статус и метаданные */ + items: ConnectionInfo[]; +} + +export const GLIFA_WS_V1_PACKAGE_NAME = "glifa.ws.v1"; + +export interface WsGatewayServiceClient { + registerConnection(request: RegisterConnectionRequest): Observable; + + unregisterConnection(request: UnregisterConnectionRequest): Observable; + + publishEnvelope(request: PublishEnvelopeRequest): Observable; + + publishPresence(request: PublishPresenceRequest): Observable; + + publishTyping(request: PublishTypingRequest): Observable; + + listUserConnections(request: ListUserConnectionsRequest): Observable; +} + +export interface WsGatewayServiceController { + registerConnection( + request: RegisterConnectionRequest, + ): Promise | Observable | RegisterConnectionResponse; + + unregisterConnection( + request: UnregisterConnectionRequest, + ): Promise | Observable | UnregisterConnectionResponse; + + publishEnvelope( + request: PublishEnvelopeRequest, + ): Promise | Observable | PublishEnvelopeResponse; + + publishPresence( + request: PublishPresenceRequest, + ): Promise | Observable | PublishPresenceResponse; + + publishTyping( + request: PublishTypingRequest, + ): Promise | Observable | PublishTypingResponse; + + listUserConnections( + request: ListUserConnectionsRequest, + ): Promise | Observable | ListUserConnectionsResponse; +} + +export function WsGatewayServiceControllerMethods() { + return function (constructor: Function) { + const grpcMethods: string[] = [ + "registerConnection", + "unregisterConnection", + "publishEnvelope", + "publishPresence", + "publishTyping", + "listUserConnections", + ]; + for (const method of grpcMethods) { + const descriptor: any = Reflect.getOwnPropertyDescriptor(constructor.prototype, method); + GrpcMethod("WsGatewayService", method)(constructor.prototype[method], method, descriptor); + } + const grpcStreamMethods: string[] = []; + for (const method of grpcStreamMethods) { + const descriptor: any = Reflect.getOwnPropertyDescriptor(constructor.prototype, method); + GrpcStreamMethod("WsGatewayService", method)(constructor.prototype[method], method, descriptor); + } + }; +} + +export const WS_GATEWAY_SERVICE_NAME = "WsGatewayService"; diff --git a/gen/glifa/ws/v1/types.ts b/gen/glifa/ws/v1/types.ts new file mode 100644 index 0000000..d0acf3a --- /dev/null +++ b/gen/glifa/ws/v1/types.ts @@ -0,0 +1,101 @@ +// Code generated by protoc-gen-ts_proto. DO NOT EDIT. +// versions: +// protoc-gen-ts_proto v2.11.8 +// protoc v4.25.9 +// source: glifa/ws/v1/types.proto + +/* eslint-disable */ +import { Any } from "../../../google/protobuf/any"; +import { Timestamp } from "../../../google/protobuf/timestamp"; + +export const protobufPackage = "glifa.ws.v1"; + +export enum ConnectionStatus { + /** CONNECTION_STATUS_UNSPECIFIED - Неопределенный статус соединения */ + CONNECTION_STATUS_UNSPECIFIED = 0, + /** CONNECTION_STATUS_CONNECTED - Соединение установлено и активно */ + CONNECTION_STATUS_CONNECTED = 1, + /** CONNECTION_STATUS_DRAINING - Соединение находится в процессе завершения, и новые сообщения не принимаются, но существующие сообщения могут быть доставлены */ + CONNECTION_STATUS_DRAINING = 2, + /** CONNECTION_STATUS_DISCONNECTED - Соединение было разорвано или потеряно */ + CONNECTION_STATUS_DISCONNECTED = 3, + UNRECOGNIZED = -1, +} + +export enum RealtimeEnvelopeKind { + /** REALTIME_ENVELOPE_KIND_UNSPECIFIED - Неопределенный тип конверта в реальном времени */ + REALTIME_ENVELOPE_KIND_UNSPECIFIED = 0, + /** REALTIME_ENVELOPE_KIND_DURABLE - Конверт в реальном времени, который гарантирует доставку сообщения получателю, даже если он временно недоступен (например, из-за отключения от сети) */ + REALTIME_ENVELOPE_KIND_DURABLE = 1, + /** REALTIME_ENVELOPE_KIND_EPHEMERAL - Конверт в реальном времени, который не гарантирует доставку сообщения получателю, если он временно недоступен (например, из-за отключения от сети), и может быть потерян в таких случаях */ + REALTIME_ENVELOPE_KIND_EPHEMERAL = 2, + UNRECOGNIZED = -1, +} + +export interface ConnectionInfo { + /** Уникальный идентификатор соединения, который может использоваться для отслеживания и управления соединением */ + connectionId: string; + /** UUID пользователя, которому принадлежит это соединение */ + userId: string; + /** UUID сессии, которая связана с этим соединением */ + sessionId: string; + /** UUID устройства, с которого установлено это соединение */ + deviceId: string; + /** Идентификатор узла, к которому подключено это соединение, если используется распределенная архитектура с несколькими узлами */ + nodeId: string; + /** Текущий статус соединения (например, подключено, в процессе завершения, отключено) */ + status: ConnectionStatus; + /** Временная метка, указывающая, когда это соединение было установлено */ + connectedAt: + | Timestamp + | undefined; + /** Временная метка, указывающая, когда это соединение в последний раз было активно или получало сообщения */ + lastSeenAt: + | Timestamp + | undefined; + /** Список подписок, на которые подписано это соединение, например, идентификаторы каналов или тем, на которые оно подписано для получения сообщений */ + subscriptions: string[]; +} + +export interface RealtimeEnvelope { + /** Уникальный идентификатор конверта в реальном времени, который может использоваться для отслеживания и управления сообщениями */ + envelopeId: string; + /** Тип конверта в реальном времени, который определяет гарантии доставки сообщения (например, долговременный или эфемерный) */ + kind: RealtimeEnvelopeKind; + /** Тема или канал, на который это сообщение предназначено, и на который подписаны получатели, которые должны получить это сообщение */ + topic: string; + /** Идентификатор агрегата, который может использоваться для группировки связанных сообщений вместе (например, все сообщения, относящиеся к одному чату или разговору) */ + aggregateId: string; + /** Тип события, который описывает содержание или действие, связанное с этим сообщением (например, "message.created", "user.typing", "notification.new") */ + eventType: string; + /** Версия схемы события, которая может использоваться для управления изменениями в структуре данных события с течением времени */ + eventVersion: string; + /** Временная метка, указывающая, когда это событие произошло или было создано, что может использоваться для упорядочивания сообщений и управления временем жизни сообщений */ + occurredAt: + | Timestamp + | undefined; + /** Полезная нагрузка сообщения, которая может содержать любые данные, связанные с этим событием, и может быть сериализована в формате JSON */ + payload: Any | undefined; +} + +export interface PresenceState { + /** UUID пользователя, чье присутствие отслеживается */ + userId: string; + /** Статус присутствия пользователя (true - онлайн, false - офлайн) */ + online: boolean; + /** Временная метка, указывающая, когда пользователь в последний раз был онлайн или активен */ + lastSeenAt: Timestamp | undefined; +} + +export interface TypingState { + /** UUID чата или канала, в котором пользователь печатает */ + chatId: string; + /** UUID пользователя, который печатает */ + userId: string; + /** UUID сессии пользователя, который печатает */ + sessionId: string; + /** Временная метка, указывающая, когда статус печати должен истечь (например, если пользователь перестал печатать и не отправил сообщение в течение определенного времени) */ + expiresAt: Timestamp | undefined; +} + +export const GLIFA_WS_V1_PACKAGE_NAME = "glifa.ws.v1"; diff --git a/gen/google/protobuf/any.ts b/gen/google/protobuf/any.ts new file mode 100644 index 0000000..1ef6bc8 --- /dev/null +++ b/gen/google/protobuf/any.ts @@ -0,0 +1,134 @@ +// Code generated by protoc-gen-ts_proto. DO NOT EDIT. +// versions: +// protoc-gen-ts_proto v2.11.8 +// protoc v4.25.9 +// source: google/protobuf/any.proto + +/* eslint-disable */ + +export const protobufPackage = "google.protobuf"; + +/** + * `Any` contains an arbitrary serialized protocol buffer message along with a + * URL that describes the type of the serialized message. + * + * Protobuf library provides support to pack/unpack Any values in the form + * of utility functions or additional generated methods of the Any type. + * + * Example 1: Pack and unpack a message in C++. + * + * Foo foo = ...; + * Any any; + * any.PackFrom(foo); + * ... + * if (any.UnpackTo(&foo)) { + * ... + * } + * + * Example 2: Pack and unpack a message in Java. + * + * Foo foo = ...; + * Any any = Any.pack(foo); + * ... + * if (any.is(Foo.class)) { + * foo = any.unpack(Foo.class); + * } + * // or ... + * if (any.isSameTypeAs(Foo.getDefaultInstance())) { + * foo = any.unpack(Foo.getDefaultInstance()); + * } + * + * Example 3: Pack and unpack a message in Python. + * + * foo = Foo(...) + * any = Any() + * any.Pack(foo) + * ... + * if any.Is(Foo.DESCRIPTOR): + * any.Unpack(foo) + * ... + * + * Example 4: Pack and unpack a message in Go + * + * foo := &pb.Foo{...} + * any, err := anypb.New(foo) + * if err != nil { + * ... + * } + * ... + * foo := &pb.Foo{} + * if err := any.UnmarshalTo(foo); err != nil { + * ... + * } + * + * The pack methods provided by protobuf library will by default use + * 'type.googleapis.com/full.type.name' as the type URL and the unpack + * methods only use the fully qualified type name after the last '/' + * in the type URL, for example "foo.bar.com/x/y.z" will yield type + * name "y.z". + * + * JSON + * ==== + * The JSON representation of an `Any` value uses the regular + * representation of the deserialized, embedded message, with an + * additional field `@type` which contains the type URL. Example: + * + * package google.profile; + * message Person { + * string first_name = 1; + * string last_name = 2; + * } + * + * { + * "@type": "type.googleapis.com/google.profile.Person", + * "firstName": , + * "lastName": + * } + * + * If the embedded message type is well-known and has a custom JSON + * representation, that representation will be embedded adding a field + * `value` which holds the custom JSON in addition to the `@type` + * field. Example (for message [google.protobuf.Duration][]): + * + * { + * "@type": "type.googleapis.com/google.protobuf.Duration", + * "value": "1.212s" + * } + */ +export interface Any { + /** + * A URL/resource name that uniquely identifies the type of the serialized + * protocol buffer message. This string must contain at least + * one "/" character. The last segment of the URL's path must represent + * the fully qualified name of the type (as in + * `path/google.protobuf.Duration`). The name should be in a canonical form + * (e.g., leading "." is not accepted). + * + * In practice, teams usually precompile into the binary all types that they + * expect it to use in the context of Any. However, for URLs which use the + * scheme `http`, `https`, or no scheme, one can optionally set up a type + * server that maps type URLs to message definitions as follows: + * + * * If no scheme is provided, `https` is assumed. + * * An HTTP GET on the URL must yield a [google.protobuf.Type][] + * value in binary format, or produce an error. + * * Applications are allowed to cache lookup results based on the + * URL, or have them precompiled into a binary to avoid any + * lookup. Therefore, binary compatibility needs to be preserved + * on changes to types. (Use versioned type names to manage + * breaking changes.) + * + * Note: this functionality is not currently available in the official + * protobuf release, and it is not used for type URLs beginning with + * type.googleapis.com. As of May 2023, there are no widely used type server + * implementations and no plans to implement one. + * + * Schemes other than `http`, `https` (or the empty scheme) might be + * used with implementation specific semantics. + */ + typeUrl: string; + /** Must be a valid serialized protocol buffer of the above specified type. */ + value: Uint8Array; +} + +export const GOOGLE_PROTOBUF_PACKAGE_NAME = "google.protobuf"; diff --git a/gen/google/protobuf/struct.ts b/gen/google/protobuf/struct.ts new file mode 100644 index 0000000..72e8db0 --- /dev/null +++ b/gen/google/protobuf/struct.ts @@ -0,0 +1,197 @@ +// Code generated by protoc-gen-ts_proto. DO NOT EDIT. +// versions: +// protoc-gen-ts_proto v2.11.8 +// protoc v4.25.9 +// source: google/protobuf/struct.proto + +/* eslint-disable */ +import { wrappers } from "protobufjs"; + +export const protobufPackage = "google.protobuf"; + +/** + * `NullValue` is a singleton enumeration to represent the null value for the + * `Value` type union. + * + * The JSON representation for `NullValue` is JSON `null`. + */ +export enum NullValue { + /** NULL_VALUE - Null value. */ + NULL_VALUE = 0, + UNRECOGNIZED = -1, +} + +/** + * `Struct` represents a structured data value, consisting of fields + * which map to dynamically typed values. In some languages, `Struct` + * might be supported by a native representation. For example, in + * scripting languages like JS a struct is represented as an + * object. The details of that representation are described together + * with the proto support for the language. + * + * The JSON representation for `Struct` is JSON object. + */ +export interface Struct { + /** Unordered map of dynamically typed values. */ + fields: { [key: string]: any | undefined }; +} + +export interface Struct_FieldsEntry { + key: string; + value: any | undefined; +} + +/** + * `Value` represents a dynamically typed value which can be either + * null, a number, a string, a boolean, a recursive struct value, or a + * list of values. A producer of value is expected to set one of these + * variants. Absence of any variant indicates an error. + * + * The JSON representation for `Value` is JSON value. + */ +export interface Value { + /** Represents a null value. */ + nullValue?: + | NullValue + | undefined; + /** Represents a double value. */ + numberValue?: + | number + | undefined; + /** Represents a string value. */ + stringValue?: + | string + | undefined; + /** Represents a boolean value. */ + boolValue?: + | boolean + | undefined; + /** Represents a structured value. */ + structValue?: + | { [key: string]: any } + | undefined; + /** Represents a repeated `Value`. */ + listValue?: Array | undefined; +} + +/** + * `ListValue` is a wrapper around a repeated field of values. + * + * The JSON representation for `ListValue` is JSON array. + */ +export interface ListValue { + /** Repeated field of dynamically typed values. */ + values: any[]; +} + +export const GOOGLE_PROTOBUF_PACKAGE_NAME = "google.protobuf"; + +function createBaseStruct(): Struct { + return { fields: {} }; +} + +export const Struct: MessageFns & StructWrapperFns = { + wrap(object: { [key: string]: any } | undefined): Struct { + const struct = createBaseStruct(); + + if (object !== undefined) { + for (const key of globalThis.Object.keys(object)) { + struct.fields[key] = Value.wrap(object[key]); + } + } + return struct; + }, + + unwrap(message: Struct): { [key: string]: any } { + const object: { [key: string]: any } = {}; + if (message.fields) { + for (const key of globalThis.Object.keys(message.fields)) { + object[key] = Value.unwrap(message.fields[key]); + } + } + return object; + }, +}; + +function createBaseValue(): Value { + return {}; +} + +export const Value: MessageFns & AnyValueWrapperFns = { + wrap(value: any): Value { + const result = {} as any; + if (value === null) { + result.nullValue = NullValue.NULL_VALUE; + } else if (typeof value === "boolean") { + result.boolValue = value; + } else if (typeof value === "number") { + result.numberValue = value; + } else if (typeof value === "string") { + result.stringValue = value; + } else if (globalThis.Array.isArray(value)) { + result.listValue = ListValue.wrap(value); + } else if (typeof value === "object") { + result.structValue = Struct.wrap(value); + } else if (typeof value !== "undefined") { + throw new globalThis.Error("Unsupported any value type: " + typeof value); + } + return result; + }, + + unwrap(message: any): string | number | boolean | Object | null | Array | undefined { + if (message?.hasOwnProperty("stringValue") && message.stringValue !== undefined) { + return message.stringValue; + } else if (message?.hasOwnProperty("numberValue") && message?.numberValue !== undefined) { + return message.numberValue; + } else if (message?.hasOwnProperty("boolValue") && message?.boolValue !== undefined) { + return message.boolValue; + } else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) { + return Struct.unwrap(message.structValue as any); + } else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) { + return ListValue.unwrap(message.listValue); + } else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) { + return null; + } + return undefined; + }, +}; + +function createBaseListValue(): ListValue { + return { values: [] }; +} + +export const ListValue: MessageFns & ListValueWrapperFns = { + wrap(array: Array | undefined): ListValue { + const result = createBaseListValue(); + result.values = (array ?? []).map(Value.wrap); + return result; + }, + + unwrap(message: ListValue): Array { + if (message?.hasOwnProperty("values") && globalThis.Array.isArray(message.values)) { + return message.values.map(Value.unwrap); + } else { + return message as any; + } + }, +}; + +wrappers[".google.protobuf.Struct"] = { fromObject: Struct.wrap, toObject: Struct.unwrap } as any; + +export interface MessageFns { +} + +export interface StructWrapperFns { + wrap(object: { [key: string]: any } | undefined): Struct; + unwrap(message: Struct): { [key: string]: any }; +} + +export interface AnyValueWrapperFns { + wrap(value: any): Value; + unwrap(message: any): string | number | boolean | Object | null | Array | undefined; +} + +export interface ListValueWrapperFns { + wrap(array: Array | undefined): ListValue; + unwrap(message: ListValue): Array; +} diff --git a/gen/google/protobuf/timestamp.ts b/gen/google/protobuf/timestamp.ts new file mode 100644 index 0000000..6e0d262 --- /dev/null +++ b/gen/google/protobuf/timestamp.ts @@ -0,0 +1,118 @@ +// Code generated by protoc-gen-ts_proto. DO NOT EDIT. +// versions: +// protoc-gen-ts_proto v2.11.8 +// protoc v4.25.9 +// source: google/protobuf/timestamp.proto + +/* eslint-disable */ + +export const protobufPackage = "google.protobuf"; + +/** + * A Timestamp represents a point in time independent of any time zone or local + * calendar, encoded as a count of seconds and fractions of seconds at + * nanosecond resolution. The count is relative to an epoch at UTC midnight on + * January 1, 1970, in the proleptic Gregorian calendar which extends the + * Gregorian calendar backwards to year one. + * + * All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + * second table is needed for interpretation, using a [24-hour linear + * smear](https://developers.google.com/time/smear). + * + * The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + * restricting to that range, we ensure that we can convert to and from [RFC + * 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + * + * # Examples + * + * Example 1: Compute Timestamp from POSIX `time()`. + * + * Timestamp timestamp; + * timestamp.set_seconds(time(NULL)); + * timestamp.set_nanos(0); + * + * Example 2: Compute Timestamp from POSIX `gettimeofday()`. + * + * struct timeval tv; + * gettimeofday(&tv, NULL); + * + * Timestamp timestamp; + * timestamp.set_seconds(tv.tv_sec); + * timestamp.set_nanos(tv.tv_usec * 1000); + * + * Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + * + * FILETIME ft; + * GetSystemTimeAsFileTime(&ft); + * UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + * + * // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + * // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + * Timestamp timestamp; + * timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + * timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + * + * Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + * + * long millis = System.currentTimeMillis(); + * + * Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + * .setNanos((int) ((millis % 1000) * 1000000)).build(); + * + * Example 5: Compute Timestamp from Java `Instant.now()`. + * + * Instant now = Instant.now(); + * + * Timestamp timestamp = + * Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + * .setNanos(now.getNano()).build(); + * + * Example 6: Compute Timestamp from current time in Python. + * + * timestamp = Timestamp() + * timestamp.GetCurrentTime() + * + * # JSON Mapping + * + * In JSON format, the Timestamp type is encoded as a string in the + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the + * format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" + * where {year} is always expressed using four digits while {month}, {day}, + * {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional + * seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution), + * are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone + * is required. A proto3 JSON serializer should always use UTC (as indicated by + * "Z") when printing the Timestamp type and a proto3 JSON parser should be + * able to accept both UTC and other timezones (as indicated by an offset). + * + * For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past + * 01:30 UTC on January 15, 2017. + * + * In JavaScript, one can convert a Date object to this format using the + * standard + * [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + * method. In Python, a standard `datetime.datetime` object can be converted + * to this format using + * [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with + * the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use + * the Joda Time's [`ISODateTimeFormat.dateTime()`]( + * http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime() + * ) to obtain a formatter capable of generating timestamps in this format. + */ +export interface Timestamp { + /** + * Represents seconds of UTC time since Unix epoch + * 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to + * 9999-12-31T23:59:59Z inclusive. + */ + seconds: number; + /** + * Non-negative fractions of a second at nanosecond resolution. Negative + * second values with fractions must still have non-negative nanos values + * that count forward in time. Must be from 0 to 999,999,999 + * inclusive. + */ + nanos: number; +} + +export const GOOGLE_PROTOBUF_PACKAGE_NAME = "google.protobuf"; diff --git a/package.json b/package.json new file mode 100644 index 0000000..e7ab165 --- /dev/null +++ b/package.json @@ -0,0 +1,27 @@ +{ + "name": "@glifaspace/contracts", + "version": "1.0.0", + "description": "Определение proto-контрактов и генерация типов TypeScript.", + "scripts": { + "generate": "node scripts/generate-proto.mjs" + }, + "files": [ + "proto", + "gen" + ], + "author": { + "name": "lendry", + "email": "admin@glifa.space" + }, + "publishConfig": { + "access": "public" + }, + "dependencies": { + "@nestjs/microservices": "^11.1.23", + "protobufjs": "^8.4.0", + "rxjs": "^7.8.2" + }, + "devDependencies": { + "ts-proto": "^2.11.8" + } +} diff --git a/proto/glifa/auth/v1/service.proto b/proto/glifa/auth/v1/service.proto new file mode 100644 index 0000000..b2cd2e1 --- /dev/null +++ b/proto/glifa/auth/v1/service.proto @@ -0,0 +1,235 @@ +syntax = "proto3"; + +package glifa.auth.v1; + +import "google/protobuf/timestamp.proto"; +import "glifa/common/v1/types.proto"; +import "glifa/common/v1/authz.proto"; +import "glifa/auth/v1/types.proto"; + +option go_package = "glifa/contracts/gen/go/auth/v1;authv1"; + +service AuthService { + rpc Register(RegisterRequest) returns (RegisterResponse); + rpc LoginWithPassword(LoginWithPasswordRequest) returns (LoginWithPasswordResponse); + rpc VerifySecondFactor(VerifySecondFactorRequest) returns (VerifySecondFactorResponse); + rpc RefreshSession(RefreshSessionRequest) returns (RefreshSessionResponse); + rpc LogoutSession(LogoutSessionRequest) returns (LogoutSessionResponse); + rpc RevokeSession(RevokeSessionRequest) returns (RevokeSessionResponse); + rpc LockSession(LockSessionRequest) returns (LockSessionResponse); + rpc UnlockSession(UnlockSessionRequest) returns (UnlockSessionResponse); + rpc ValidateAccessToken(ValidateAccessTokenRequest) returns (ValidateAccessTokenResponse); + rpc GetSession(GetSessionRequest) returns (GetSessionResponse); + rpc ListSessions(ListSessionsRequest) returns (ListSessionsResponse); + rpc CreateQrLogin(CreateQrLoginRequest) returns (CreateQrLoginResponse); + rpc ApproveQrLogin(ApproveQrLoginRequest) returns (ApproveQrLoginResponse); + rpc ExchangeQrLogin(ExchangeQrLoginRequest) returns (ExchangeQrLoginResponse); + rpc SendAuthChallenge(SendAuthChallengeRequest) returns (SendAuthChallengeResponse); + rpc VerifyAuthChallenge(VerifyAuthChallengeRequest) returns (VerifyAuthChallengeResponse); + rpc ListSecurityEvents(ListSecurityEventsRequest) returns (ListSecurityEventsResponse); +} + +message RegisterRequest { + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса, такие как идентификатор корреляции, язык и т.д. + string username = 2; // Уникальное имя пользователя, которое будет использоваться для входа в систему + string email = 3; // Электронная почта пользователя, которая может использоваться для входа в систему и получения уведомлений + string phone = 4; // Номер телефона пользователя, который может использоваться для входа в систему и получения уведомлений + string password = 5; // Пароль пользователя, который будет использоваться для аутентификации при входе в систему + string display_name = 6; // Отображаемое имя пользователя, которое будет показываться другим пользователям в системе + string device_id = 7; // UUID устройства, с которого пользователь регистрируется, для отслеживания и управления сессиями на разных устройствах + string device_name = 8; // Человекочитаемое название устройства, с которого пользователь регистрируется (например, "iPhone 12", "Windows PC"), для удобства отображения в интерфейсе управления сессиями + string platform = 9; // Платформа устройства, с которого пользователь регистрируется (например, "iOS", "Android", "Web"), для аналитики и оптимизации работы сессий на разных платформах + string app_version = 10; // Версия приложения, с которого пользователь регистрируется, для аналитики и оптимизации работы сессий на разных версиях приложения +} + +message RegisterResponse { + string user_id = 1; // UUID нового пользователя, который был зарегистрирован + TokenPair tokens = 2; // Пара токенов доступа и обновления, которая может быть использована для аутентификации и управления сессиями + DeviceSession session = 3; // Данные о сессии, которая была создана для нового пользователя на устройстве, с которого он регистрировался +} + +message LoginWithPasswordRequest { + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса, такие как идентификатор корреляции, язык и т.д. + string login = 2; // Имя пользователя, электронная почта или номер телефона, которые пользователь использует для входа в систему + string password = 3; // Пароль пользователя, который будет использоваться для аутентификации при входе в систему + string device_id = 4; // UUID устройства, с которого пользователь входит в систему, для отслеживания и управления сессиями на разных устройствах + string device_name = 5; // Человекочитаемое название устройства, с которого пользователь входит в систему (например, "iPhone 12", "Windows PC"), для удобства отображения в интерфейсе управления сессиями + string platform = 6; // Платформа устройства, с которого пользователь входит в систему (например, "iOS", "Android", "Web"), для аналитики и оптимизации работы сессий на разных платформах + string app_version = 7; // Версия приложения, с которого пользователь входит в систему, для аналитики и оптимизации работы сессий на разных версиях приложения +} + +message LoginWithPasswordResponse { + oneof result { + TokenPair tokens = 1; // Пара токенов доступа и обновления, которая может быть использована для аутентификации и управления сессиями, если вход выполнен успешно + LoginChallenge second_factor_required = 2; // Данные о вызове второго фактора аутентификации, если он требуется для входа в систему + } + DeviceSession session = 3; // Данные о сессии, которая была создана для пользователя на устройстве, с которого он входит в систему (может быть полезно для отображения информации о текущей сессии в интерфейсе управления сессиями) +} + +message VerifySecondFactorRequest { + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса, такие как идентификатор корреляции, язык и т.д. + string login_challenge_id = 2; // UUID вызова второго фактора аутентификации, который был возвращен при попытке входа в систему + string totp_code = 3; // TOTP-код, который пользователь сгенерировал в своем приложении для аутентификации (например, Google Authenticator), для подтверждения второго фактора аутентификации + string recovery_code = 4; // Код восстановления, который пользователь получил при настройке второго фактора аутентификации, для подтверждения второго фактора аутентификации в случае, если TOTP-коды недоступны +} + +message VerifySecondFactorResponse { + TokenPair tokens = 1; // Пара токенов доступа и обновления, которая может быть использована для аутентификации и управления сессиями, если второй фактор аутентификации был успешно подтвержден + DeviceSession session = 2; // Данные о сессии, которая была создана для пользователя на устройстве, с которого он входит в систему (может быть полезно для отображения информации о текущей сессии в интерфейсе управления сессиями) +} + +message RefreshSessionRequest{ + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса, такие как идентификатор корреляции, язык и т.д. + string refresh_token = 2; // Токен обновления, который был выдан при аутентификации и может быть использован для получения новой пары токенов доступа и обнов +} + +message RefreshSessionResponse{ + TokenPair tokens = 1; // Новая пара токенов доступа и обновления, которая может быть использована для аутентификации и управления сессиями, если токен обновления был успешно подтвержден + DeviceSession session = 2; // Данные о сессии, которая была обновлена для пользователя на устройстве, с которого он входит в систему (может быть полезно для отображения информации о текущей сессии в интерфейсе управления сессиями) + bool family_rotated = 3; // Флаг, указывающий, была ли выполнена ротация всей семьи токенов (т.е. были ли отозваны все другие активные сессии пользователя), что может быть полезно для безопасности и управления сессиями +} + +message LogoutSessionRequest { + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса, такие как идентификатор корреляции, язык и т.д. + string session_id = 2; // UUID сессии, которую пользователь хочет завершить (например, текущая сессия или другая активная сессия на другом устройстве) +} + +message LogoutSessionResponse { + bool success = 1; // Флаг, указывающий, была ли сессия успешно завершена +} + +message RevokeSessionRequest { + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса, такие как идентификатор корреляции, язык и т.д. + string session_id = 2; // UUID сессии, которую пользователь хочет отозвать (например, текущая сессия или другая активная сессия на другом устройстве) + string reason = 3; // Причина отзыва сессии, которая может быть полезна для аудита и безопасности (например, "user_logout", "password_change", "suspicious_activity") +} + +message RevokeSessionResponse { + DeviceSession session = 1; // Данные о сессии, которая была отозвана, включая ее статус и метаданные, что может быть полезно для отображения информации о сессиях в интерфейсе управления сессиями +} + +message LockSessionRequest{ + glifa.common.v1.RequestMeta meta = 1; + string session_id = 2; + string reason = 3; +} + +message LockSessionResponse{ + DeviceSession session = 1; +} + +message UnlockSessionRequest { + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса, такие как идентификатор корреляции, язык и т.д. + string session_id = 2; // UUID сессии, которую пользователь хочет разблок + oneof proof { + string password = 3; // Пароль пользователя, который будет использоваться для подтверждения личности при разблокировке сессии + string challenge_id = 4; // UUID вызова аутентификационного челленджа, который был отправлен пользователю для подтверждения личности при разблокировке сессии + } + + string code = 5; // Код из аутентификационного челленджа, который пользователь получил и должен предоставить для подтверждения личности при разблокировке сессии +} + +message UnlockSessionResponse { + DeviceSession session = 1; // Данные о сессии, которая была разблокирована, включая ее статус и метаданные, что может быть полезно для отображения информации о сессиях в интерфейсе управления сессиями + TokenPair tokens = 2; // Пара токенов доступа и обновления, которая может быть использована для аутентификации и управления сессиями, если разблокировка сессии была успешно подтверждена +} + +message ValidateAccessTokenRequest { + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса, такие как идентификатор корреляции, язык и т.д. + string access_token = 2; // Токен доступа, который нужно проверить на валидность и получить связанную с ним информацию о сессии и правах доступа +} + +message ValidateAccessTokenResponse { + bool valid = 1; // Флаг, указывающий, является ли токен доступа валидным (т.е. не истекшим, не отозванным и правильно подписанным) + string user_id = 2; // UUID пользователя, которому принадлежит этот токен доступа, если он валиден + string session_id = 3; // UUID сессии, с которой связан этот ток + string device_id = 4; // UUID устройства, с которого был выдан этот токен доступа, если он валиден + uint64 token_version = 5; // Версия токена, которая может быть полезна для управления ротацией токенов и обеспечения безопасности + google.protobuf.Timestamp expires_at = 6; // Временная метка истечения срока действия токена доступа, которая может быть полезна для управления сессиями и обеспечения безопасности + DeviceSessionStatus session_status = 7; // Статус сессии, с которой связан этот токен доступа (например, "active", "locked", "revoked"), который может быть полезен для управления сессиями и обеспечения безопасности + glifa.common.v1.SubjectContext subject = 8; // Контекст субъекта, связанный с этим токеном доступа, который может включать информацию о ролях и правах доступа пользователя для авторизации при доступе к ресурсам системы +} + +message GetSessionRequest { + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса, такие как идентификатор корреляции, язык и т.д. + string session_id = 2; // UUID сессии, которую пользователь хочет получить +} + +message GetSessionResponse { + DeviceSession session = 1; // Данные о запрошенной сессии, включая ее статус и метаданные, что может быть полезно для отображения информации о сессиях в интерфейсе управления сессиями +} + +message ListSessionsRequest { + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса, такие как идентификатор корреляции, язык и т.д. + string user_id = 2; // UUID пользователя, для которого нужно получить список сессий +} + +message ListSessionsResponse { + repeated DeviceSession sessions = 1; // Список сессий, связанных с указанным пользователем, включая их статус и метаданные, что может быть полезно для отображения информации о сессиях в интерфейсе управления сессиями +} + +message CreateQrLoginRequest { + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса, такие как идентификатор корреляции, язык и т.д. + string device_id = 2; // UUID устройства, с которого пользователь инициирует QR-вход, для отслеживания и управления сессиями на разных устройствах + string device_name = 3; // Человекочитаемое название устройства, с которого пользователь инициирует QR-вход (например, "iPhone 12", "Windows PC"), для удобства отображения в интерфейсе управления сессиями + string platform = 4; // Платформа устройства, с которого пользователь инициирует QR-вход (например, "iOS", "Android", "Web"), для аналитики и оптимизации работы сессий на разных + string app_version = 5; // Версия приложения, с которого пользователь инициирует QR-вход, для аналитики и оптимизации работы сессий на разных версиях приложения +} + +message CreateQrLoginResponse{ + QrLoginRequest request = 1; // Данные о созданном QR-запросе, включая его UUID и время истечения срока действия, которые могут быть использованы для отображения QR-кода и управления процессом QR-входа + string qr_payload = 2; // Строка, которая может быть сериализована в QR-код и содержит информацию, необходимую для выполнения QR-входа (например, UUID запроса и URL для обмена данными между устройствами) +} + +message ApproveQrLoginRequest { + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса, такие как идентификатор корреляции, язык и т.д. + string request_id = 2; // UUID QR-запроса, который пользователь хочет одобрить для выполнения QR-входа +} + +message ApproveQrLoginResponse { + QrLoginRequest request = 1; // Данные о QR-запросе, который был одобрен, включая его UUID и время истечения срока действия, которые могут быть использованы для управления процессом QR-входа +} + +message ExchangeQrLoginRequest { + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса, такие как идентификатор корреляции, язык и т.д. + string request_id = 2; // UUID QR-запроса, который был одобрен и для которого пользователь хочет получить токены доступа и обновления для выполнения QR-входа + string proof = 3; // Доказательство, которое может быть предоставлено пользователем для подтверждения своей личности при обмене QR-запроса на токены доступа и обновления (например, код из аутентификационного челленджа или другой механизм подтверждения) +} + +message ExchangeQrLoginResponse { + TokenPair tokens = 1; // Пара токенов доступа и обновления, которая может быть использована для аутентификации и управления сессиями, если обмен QR-запроса был успешно подтвержден + DeviceSession session = 2; // Данные о сессии, которая была создана для пользователя на устройстве, с которого он выполняет QR-вход (может быть полезно для отображения информации о текущей сессии в интерфейсе управления сессиями) +} + +message SendAuthChallengeRequest{ + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса, такие как идентификатор корреляции, язык и т.д. + string target = 2; // Цель, на которую должен быть отправлен аутентификационный челлендж (например, электронная почта или номер телефона пользователя) + AuthChallengePurpose purpose = 3; // Цель аутентификационного челленджа, которая может быть полезна для определения типа и содержания челленджа (например, "login", "unlock_session", "verify_identity") + AuthChallengeDeliveryChannel delivery_channel = 4; // Канал доставки аутентификационного челленджа, который может быть полезен для оптимизации процесса доставки и обеспечения безопасности (например, "email", "sms", "push_notification") +} + +message SendAuthChallengeResponse{ + AuthChallenge challenge = 1; // Данные о созданном аутентификационном челлендже, включая его UUID, код и время истечения срока действия, которые могут быть использованы для подтверждения личности пользователя при выполнении различных действий в системе +} + +message VerifyAuthChallengeRequest{ + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса, такие как идентификатор корреляции, язык и т.д. + string challenge_id = 2; // UUID аутентификационного челленджа, который был отправлен пользователю и который он предоставляет для подтверждения своей личности + string code = 3; // Код из аутентификационного челленджа, который пользователь получил и должен предоставить для подтверждения своей личности +} + +message VerifyAuthChallengeResponse{ + AuthChallenge challenge = 1; // Данные о аутентификационном челлендже, который был успешно подтвержден, включая его UUID и время истечения срока действия, которые могут быть использованы для управления процессом подтверждения личности пользователя при выполнении различных действий в системе + bool verified = 2; // Флаг, указывающий, был ли аутентификационный челлендж успешно подтвержден, что может быть полезно для управления процессом подтверждения личности пользователя при выполнении различных действий в системе +} + +message ListSecurityEventsRequest { + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса, такие как идентификатор корреляции, язык и т.д. + string user_id = 2; // UUID пользователя, для которого нужно получить список событий безопасности + glifa.common.v1.PageRequest page = 3; // Параметры пагинации (номер страницы и размер страницы) +} + +message ListSecurityEventsResponse { + repeated SecurityEvent events = 1; // Список событий безопасности, связанных с указанным пользователем, включая их тип, время и метаданные, что может быть полезно для отображения информации о безопасности в интерфейсе управления сессиями и обеспечения безопасности + glifa.common.v1.PageResponse page = 2; // Информация о пагинации (номер страницы, размер страницы, общее количество элементов) для списка событий безопасности, что может быть полезно для отображения информации о безопасности в интерфейсе управления сессиями и обеспечения безопасности +} diff --git a/proto/glifa/auth/v1/types.proto b/proto/glifa/auth/v1/types.proto new file mode 100644 index 0000000..1bad90f --- /dev/null +++ b/proto/glifa/auth/v1/types.proto @@ -0,0 +1,150 @@ +syntax = "proto3"; + +package glifa.auth.v1; + +import "google/protobuf/timestamp.proto"; + +option go_package = "glifa/contracts/gen/go/glifa/auth/v1;authv1"; + +enum DeviceSessionStatus{ + DEVICE_SESSION_STATUS_UNSPECIFIED = 0; // Неопределенный статус сессии устройства + DEVICE_SESSION_STATUS_ACTIVE = 1; // Сессия устройства активна и используется + DEVICE_SESSION_STATUS_LOCKED = 2; // Сессия устройства заблокирована (например, из-за подозрительной активности) + DEVICE_SESSION_STATUS_REQUIRES_2FA = 3; // Сессия устройства требует двухфакторной аутентификации для продолжения + DEVICE_SESSION_STATUS_REQUIRES_REAUTH = 4; // Сессия устройства требует повторной аутентификации (например, после длительного периода неактивности) + DEVICE_SESSION_STATUS_REVOKED = 5; // Сессия устройства отозвана (например, из-за нарушения безопасности) + DEVICE_SESSION_STATUS_EXPIRED = 6; // Сессия устройства истекла (например, после определенного периода времени) + DEVICE_SESSION_STATUS_COMPROMISED = 7; // Сессия устройства скомпрометирована (например, обнаружена утечка учетных данных) +} + +enum AuthChallengePurpose { + AUTH_CHALLENGE_PURPOSE_UNSPECIFIED = 0; // Неопределенная цель аутентификационного вызова + AUTH_CHALLENGE_PURPOSE_LOGIN = 1; // Вызов для аутентификации при входе в систему + AUTH_CHALLENGE_PURPOSE_PASSWORD_RESET = 2; // Вызов для аутентификации при сбросе пароля + AUTH_CHALLENGE_PURPOSE_EMAIL_VERIFICATION = 3; // Вызов для аутентификации при подтверждении электронной почты + AUTH_CHALLENGE_PURPOSE_PHONE_VERIFICATION = 4; // Вызов для аутентификации при подтверждении номера телефона + AUTH_CHALLENGE_PURPOSE_SESSION_UNLOCK = 5; // Вызов для аутентификации при разблокировке сессии + AUTH_CHALLENGE_PURPOSE_REAUTH = 6; // Вызов для аутентификации при повторной аутентификации (например, после длительного периода неактивности) + AUTH_CHALLENGE_PURPOSE_QR_APPROVAL = 7; // Вызов для аутентификации при одобрении входа через QR-код на другом устройстве +} + +enum AuthChallengeDeliveryChannel { + AUTH_CHALLENGE_DELIVERY_CHANNEL_UNSPECIFIED = 0; // Неопределенный канал доставки аутентификационного вызова + AUTH_CHALLENGE_DELIVERY_CHANNEL_EMAIL = 1; // Канал доставки - электронная почта + AUTH_CHALLENGE_DELIVERY_CHANNEL_SMS = 2; // Канал доставки - SMS + AUTH_CHALLENGE_DELIVERY_CHANNEL_TOTP = 3; // Канал доставки - TOTP (например, Google Authenticator) + AUTH_CHALLENGE_DELIVERY_CHANNEL_INTERNAL = 4; // Канал доставки - внутренний (например, push-уведомление в мобильном приложении) +} + +enum AuthChallengeType { + AUTH_CHALLENGE_TYPE_UNSPECIFIED = 0; // Неопределенный тип аутентификационного вызова + AUTH_CHALLENGE_TYPE_CODE = 1; // Вызов с кодом подтверждения (например, 6-значный код из SMS или TOTP) + AUTH_CHALLENGE_TYPE_LINK = 2; // Вызов с ссылкой для подтверждения (например, magic link в электронной почте) + AUTH_CHALLENGE_TYPE_TOTP = 3; // Вызов с TOTP (например, код из Google Authenticator) + AUTH_CHALLENGE_TYPE_APPROVAL = 4; // Вызов с запросом на одобрение (например, push-уведомление для одобрения входа на другом устройстве) +} + +enum AuthChallengeStatus { + AUTH_CHALLENGE_STATUS_UNSPECIFIED = 0; // Неопределенный статус аутентификационного вызова + AUTH_CHALLENGE_STATUS_PENDING = 1; // Вызов создан и ожидает подтверждения пользователем + AUTH_CHALLENGE_STATUS_VERIFIED = 2; // Вызов успешно подтвержден пользователем + AUTH_CHALLENGE_STATUS_CONSUMED = 3; // Вызов уже был использован для подтверждения и больше не действителен + AUTH_CHALLENGE_STATUS_EXPIRED = 4; // Вызов истек и больше не действителен (например, после определенного периода времени) + AUTH_CHALLENGE_STATUS_BLOCKED = 5; // Вызов заблокирован (например, из-за подозрительной активности) +} + +enum QrLoginRequestStatus { + QR_LOGIN_REQUEST_STATUS_UNSPECIFIED = 0; // Неопределенный статус запроса на вход через QR-код + QR_LOGIN_REQUEST_STATUS_PENDING = 1; // Запрос на вход через QR-код создан и ожидает сканирования пользователем + QR_LOGIN_REQUEST_STATUS_APPROVED = 2; // Запрос на вход через QR-код одобрен пользователем (например, через мобильное приложение) + QR_LOGIN_REQUEST_STATUS_CONSUMED = 3; // Запрос на вход через QR-код уже был использован для входа и больше не действителен + QR_LOGIN_REQUEST_STATUS_EXPIRED = 4; // Запрос на вход через QR-код истек и больше не действителен (например, после определенного периода времени) + QR_LOGIN_REQUEST_STATUS_REJECTED = 5; // Запрос на вход через QR-код отклонен пользователем (например, через мобильное приложение) +} + +enum SecurityEventType { + SECURITY_EVENT_TYPE_UNSPECIFIED = 0; // Неопределенный тип события безопасности + SECURITY_EVENT_TYPE_LOGIN_SUCCESS = 1; // Событие успешного входа в систему + SECURITY_EVENT_TYPE_LOGIN_FAILED = 2; // Событие неудачного входа в систему (например, из-за неправильного пароля) + SECURITY_EVENT_TYPE_CHALLENGE_SEND = 3; // Событие отправки аутентификационного вызова пользователю (например, отправка SMS с кодом подтверждения) + SECURITY_EVENT_TYPE_CHALLENGE_VERIFIED = 4; // Событие успешного подтверждения аутентификационного вызова пользователем (например, пользователь ввел правильный код подтверждения) + SECURITY_EVENT_TYPE_TWO_FACTOR_ENABLED = 5; // Событие включения двухфакторной аутентификации пользователем + SECURITY_EVENT_TYPE_TWO_FACTOR_DISABLED = 6; // Событие отключения двухфакторной аутентификации пользователем + SECURITY_EVENT_TYPE_SESSION_CREATED = 7; // Событие создания новой сессии пользователя + SECURITY_EVENT_TYPE_SESSION_LOCKED = 8; // Событие блокировки сессии пользователя (например, из-за подозрительной активности) + SECURITY_EVENT_TYPE_SESSION_UNLOCKED = 9; // Событие разблокировки сессии пользователя (например, после успешной аутентификации) + SECURITY_EVENT_TYPE_SESSION_REVOKED = 10; // Событие отзыва сессии пользователя (например, из-за нарушения безопасности) + SECURITY_EVENT_TYPE_SESSION_COMPROMISED = 11; // Событие компрометации сессии пользователя (например, обнаружена утечка учетных данных) + SECURITY_EVENT_TYPE_QR_APPROVED = 12; // Событие одобрения входа через QR-код на другом устройстве + SECURITY_EVENT_TYPE_QR_CONSUMED = 13; // Событие использования запроса на вход через QR-код для входа в систему + SECURITY_EVENT_TYPE_QR_EXPIRED = 14; // Событие истечения срока действия запроса на вход через QR-код +} + +message DeviceSession { + string id = 1; // UUID сессии устройства + string user_id = 2; // UUID пользователя, которому принадлежит сессия устройства + string device_id = 3; // UUID устройства, с которого была создана сесс + string device_name = 4; // Человеко-читаемое имя устройства (например, "iPhone 12 Pro") + string platform = 5; // Платформа устройства (например, "iOS", "Android", "Web") + string app_version = 6; // Версия приложения, с которого была создана сессия устройства + DeviceSessionStatus status = 7; // Статус сессии устройства + string last_ip = 8; // Последний IP-адрес, с которого была активна сессия устройства + string user_agent = 9; // User-Agent устройства, с которого была создана сессия + google.protobuf.Timestamp last_seen_at = 10; // Время последней активности сессии устройства + google.protobuf.Timestamp soft_lock_at = 11; // Время, когда сессия устройства была мягко заблокирована (например, из-за подозрительной активности, но еще не отозвана) + google.protobuf.Timestamp expires_at = 12; // Время истечения срока действия сессии устройства (например, после определенного периода времени неактивности) + google.protobuf.Timestamp created_at = 13; // Время создания сессии устройства + google.protobuf.Timestamp updated_at = 14; // Время последнего обновления сессии устройства +} + +message TokenPair{ + string access_token = 1; // JWT access token для аутентификации API-запросов + google.protobuf.Timestamp access_token_expires_at = 2; // Время истечения срока действия access token + string refresh_token = 3; // JWT refresh token для получения нового access token после истечения срока действия + google.protobuf.Timestamp refresh_token_expires_at = 4; // Время истечения срока действия refresh token (например, через 30 дней) + string session_id = 5; // UUID сессии, для которой был выдан токен + string user_id = 6; // UUID пользователя, которому принадлежит сессия и токен +} + +message LoginChallenge{ + string challenge_id = 1; // UUID аутентификационного вызова, который может быть использован для отслеживания и управления процессом аутентификации + google.protobuf.Timestamp expires_at = 2; // Временная метка, указывающая, когда этот аутентификационный вызов истекает и больше не может быть использован для подтверждения входа +} + +message AuthChallenge { + string id = 1; // UUID аутентификационного вызова + string target = 2; // Цель аутентификационного вызова (например, "login", "password_reset") + AuthChallengePurpose purpose = 3; // Цель аутентификационного вызова (например, "login", "password_reset") + AuthChallengeDeliveryChannel delivery_channel = 4; // Канал доставки аутентификационного вызова (например, "email", "sms") + AuthChallengeType challenge_type = 5; // Тип аутентификационного вызова (например, "code", "link") + AuthChallengeStatus status = 6; // Статус аутентификационного вызова (например, "pending", "verified") + uint32 attempt_count = 7; // Количество попыток подтверждения аутентификационного вызова + uint32 resend_count = 8; // Количество повторных отправок аутентификационного вызова + uint32 max_attempts = 9; // Максимально допустимое количество попыток подтверждения аутентификационного вызова (например, 5) + google.protobuf.Timestamp expires_at = 10; // Время истечения срока действия аутентификационного вызова (например, через 10 минут) + google.protobuf.Timestamp consumed_at = 11; // Время, когда аутентификационный вызов был успешно подтвержден и использован + google.protobuf.Timestamp created_at = 12; // Время создания аутентификационного вызова + google.protobuf.Timestamp updated_at = 13; // Время последнего обновления аутентификационного вызова (например, при каждой попытке подтверждения или повторной отправке) +} + +message QrLoginRequest { + string request_id = 1; // UUID запроса на вход через QR-код + string nonce = 2; // Случайная строка для обеспечения безопасности QR-кода + QrLoginRequestStatus status = 3; // Статус запроса на вход через QR-код (например, "pending", "approved") + google.protobuf.Timestamp expires_at = 4; // Время истечения срока действия запроса на вход через QR-код (например, через 5 минут) + google.protobuf.Timestamp approved_at = 5; // Время, когда запрос на вход через QR-код был одобрен пользователем (например, через мобильное приложение) + google.protobuf.Timestamp consumed_at = 6; // Время, когда запрос на вход через QR-код был использован для входа в систему + google.protobuf.Timestamp created_at = 7; // Время создания запроса на вход через QR-код +} + +message SecurityEvent { + string id = 1; // UUID события безопасности + string user_id = 2; // UUID пользователя, которому относится событие безопасности + string session_id = 3; // UUID сессии, если событие безопасности связано с конкретной сессией пользователя + SecurityEventType event_type = 4; // Тип события безопасности (например, "login_success", "challenge_verified") + string ip_address = 5; // IP-адрес, с которого произошло событие безопасности + string user_agent = 6; // User-Agent, с которого произошло событие безопасности + string details_json = 7; // Дополнительные детали события безопасности в формате JSON (например, информация о вызове аутентификационного вызова, который был подтвержден) + google.protobuf.Timestamp created_at = 8; // Время создания события безопасности +} + diff --git a/proto/glifa/channel/v1/service.proto b/proto/glifa/channel/v1/service.proto new file mode 100644 index 0000000..5453cc9 --- /dev/null +++ b/proto/glifa/channel/v1/service.proto @@ -0,0 +1,146 @@ +syntax = "proto3"; + +package glifa.channel.v1; + +import "google/protobuf/struct.proto"; +import "glifa/common/v1/types.proto"; +import "glifa/channel/v1/types.proto"; +import "glifa/common/v1/enums.proto"; + +option go_package = "glifa/contracts/gen/go/glifa/channel/v1;channelv1"; + +service ChannelService{ + rpc CreateChannel(CreateChannelRequest) returns (CreateChannelResponse); + rpc GetChannel(GetChannelRequest) returns (GetChannelResponse); + rpc Subscribe(SubscribeRequest) returns (SubscribeResponse); + rpc Unsubscribe(UnsubscribeRequest) returns (UnsubscribeResponse); + rpc CreatePost(CreatePostRequest) returns (CreatePostResponse); + rpc EditPost(EditPostRequest) returns (EditPostResponse); + rpc DeletePost(DeletePostRequest) returns (DeletePostResponse); + rpc GetPost(GetPostRequest) returns (GetPostResponse); + rpc GetFeed(GetFeedRequest) returns (GetFeedResponse); + rpc UpdateReadOffset(UpdateReadOffsetRequest) returns (UpdateReadOffsetResponse); + rpc GetReadOffset(GetReadOffsetRequest) returns (GetReadOffsetResponse); +} + +message CreateChannelRequest { + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса (например, для аутентификации и трассировки) + string owner_user_id = 2; // UUID пользователя, который создает канал + string handle = 3; // Уникальный идентификатор канала (например, "general", "random") + string title = 4; // Название канала + string description = 5; // Описание канала + bool is_private = 6; // Флаг, указывающий, является ли канал приватным (только по приглашениям) +} + +message CreateChannelResponse { + Channel channel = 1; // Данные созданного канала +} + +message GetChannelRequest { + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса (например, для аутентификации и трассировки) + string owner_user_id = 2; // UUID пользователя, который создал канал + string handle = 3; // Уникальный идентификатор канала (например, "general", "random") + string title = 4; // Название канала + string description = 5; // Описание канала + bool is_private = 6; // Флаг, указывающий, является ли канал приватным (только по приглашениям) +} + +message GetChannelResponse { + Channel channel = 1; // Данные запрошенного канала +} + +message SubscribeRequest { + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса (например, для аутентификации и трассировки) + string channel_id = 2; // UUID канала, в который пользователь хочет подписаться + string user_id = 3; // UUID пользователя, который хочет подписаться на канал +} + +message SubscribeResponse { + ChannelSubscriber subscriber = 1; // Данные о новом подписчике канала +} + +message UnsubscribeRequest { + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса (например, для аутентификации и трассировки) + string channel_id = 2; // UUID канала, из которого пользователь хочет отписаться + string user_id = 3; // UUID пользователя, который хочет отписаться от канала +} + +message UnsubscribeResponse { + bool success = 1; // Флаг, указывающий, была ли операция отписки успешной +} + +message CreatePostRequest { + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса (например, для аутентификации и трассировки) + string channel_id = 2; // UUID канала, в котором пользователь хочет создать пост + string client_post_id = 3; // Идентификатор поста, сгенерированный на клиенте (для обеспечения идемпотентности при повторной отправке) + glifa.common.v1.MessageContentType message_type = 4; // Тип контента поста (например, "text", "image", "file") + string text = 5; // Текст поста (если message_type == "text") + string file_id = 6; // UUID файла, прикрепленного к посту (если message_type == "file") + google.protobuf.Struct metadata = 7; // Дополнительные метаданные поста в виде произвольной JSON-структуры (например, для хранения информации о медиа-контенте) +} + +message CreatePostResponse { + ChannelPost post = 1; // Данные созданного поста +} + +message EditPostRequest { + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса (например, для аутентификации и трассировки) + string post_id = 2; // UUID поста, который пользователь хочет отредактировать + string text = 3; // Новый текст поста (если message_type == "text") + google.protobuf.Struct metadata = 4; // Новые дополнительные метаданные поста в виде произвольной JSON-структуры (например, для обновления информации о медиа-контенте) +} + +message EditPostResponse { + ChannelPost post = 1; // Данные отредактированного поста +} + +message DeletePostRequest { + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса (например, для аутентификации и трассировки) + string post_id = 2; // UUID поста, который пользователь хочет удалить +} + +message DeletePostResponse { + bool success = 1; // Флаг, указывающий, была ли операция удаления успешной +} + +message GetPostRequest { + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса (например, для аутентификации и трассировки) + string post_id = 2; // UUID поста, который пользователь хочет получить +} + +message GetPostResponse { + ChannelPost post = 1; // Данные запрошенного поста +} + +message GetFeedRequest { + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса (например, для аутентификации и трассировки) + string channel_id = 2; // UUID канала, для которого пользователь хочет получить ленту постов + glifa.common.v1.PageRequest page = 3; // Параметры пагинации (номер страницы и размер страницы) +} + +message GetFeedResponse { + repeated ChannelPost items = 1; // Список постов в запрошенной странице ленты + glifa.common.v1.PageResponse page = 2; // Информация о пагинации (номер страницы, размер страницы, общее количество элементов) +} + +message UpdateReadOffsetRequest { + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса (например, для аутентификации и трассировки) + string channel_id = 2; // UUID канала, для которого пользователь хочет обновить оффсет прочтения + string read_post_seq = 3; // Максимальный последовательный номер поста, который пользователь прочитал в канале (включительно) +} + +message UpdateReadOffsetResponse { + ChannelReadOffset offset = 1; // Данные обновленного оффсета прочтения пользователя в канале +} + +message GetReadOffsetRequest { + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса (например, для аутентификации и трассировки) + string channel_id = 2; // UUID канала, для которого пользователь хочет получить оффсет прочтения + string user_id = 3; // UUID пользователя, для которого нужно получить оффсет прочтения +} + +message GetReadOffsetResponse { + ChannelReadOffset offset = 1; // Данные оффсета прочтения пользователя в канале +} + + diff --git a/proto/glifa/channel/v1/types.proto b/proto/glifa/channel/v1/types.proto new file mode 100644 index 0000000..08deaf9 --- /dev/null +++ b/proto/glifa/channel/v1/types.proto @@ -0,0 +1,53 @@ +syntax = "proto3"; + +package glifa.channel.v1; + +import "google/protobuf/struct.proto"; +import "google/protobuf/timestamp.proto"; +import "glifa/common/v1/enums.proto"; + +option go_package = "glifa/contracts/get/go/channel/v1;channelv1"; + +message Channel{ + string id = 1; // UUID канала + string handler = 2; // Идентификатор обработчика канала (например, "websocket", "mqtt") + string title = 3; // Название канала + string description = 4; // Описание канала + string owner_user_id = 5; // UUID пользователя, который создал канал + uint64 last_post_seq = 6; // Последовательный номер последнего поста в канале (для генерации новых последовательных номеров) + string last_post_id = 7; // UUID последнего поста в канале (для оптимистичной блокировки при добавлении новых постов) + bool is_private = 8; // Флаг, указывающий, является ли канал приватным (только по приглашениям) + google.protobuf.Timestamp created_at = 9; // Время создания канала + google.protobuf.Timestamp updated_at = 10; // Время последнего обновления канала (например, при изменении названия или описания) +} + +message ChannelSubscriber{ + string channel_id = 1; // UUID канала, на который подписан пользователь + string user_id = 2; // UUID пользователя, который подписан на канал + google.protobuf.Timestamp subscribed_at = 3; // Время подписки пользователя на канал +} + +message ChannelPost{ + string id = 1; // UUID поста + string channel_id = 2; // UUID канала, в котором опубликован пост + string post_seq = 3; // Последовательный номер поста в канале (для упорядочивания постов) + string client_post_id = 4; // Идентификатор поста, сгенерированный на клиенте (для обеспечения идемпотентности при повторной отправке) + string author_user_id = 5; // UUID пользователя, который создал пост + glifa.common.v1.MessageContentType message_type = 6; // Тип контента поста (например, "text", "image", "file") + string text = 7; // Текст поста (если message_type == "text") + string file_id = 8; // UUID файла, прикрепленного к посту (если message_type == "file") + google.protobuf.Struct metadata = 9; // Дополнительные метаданные поста в виде произвольной JSON-структуры (например, для хранения информации о медиа-контент + bool is_edited = 10; // Флаг, указывающий, был ли пост отредактирован после создания + uint32 edit_version = 11; // Версия редактирования поста, которая увеличивается при каждом редактировании (для оптимистичной блокировки при редактировании) + google.protobuf.Timestamp deleted_at = 12; // Время удаления поста (если пост был удален) + google.protobuf.Timestamp created_at = 13; // Время создания поста + google.protobuf.Timestamp updated_at = 14; // Время последнего обновления поста +} + +message ChannelReadOffset{ + string channel_id = 1; // UUID канала, для которого сохраняется смещение прочтения + string user_id = 2; // UUID пользователя, для которого сохраняется смещение прочтения + string read_post_seq = 3; // Последовательный номер последнего прочитанного поста в канале (для определения новых постов, которые пользователь еще не прочитал) + google.protobuf.Timestamp updated_at = 4; // Время последнего обновления смещения прочтения (например, при открытии канала пользователем) +} + diff --git a/proto/glifa/common/v1/authz.proto b/proto/glifa/common/v1/authz.proto new file mode 100644 index 0000000..eb101b7 --- /dev/null +++ b/proto/glifa/common/v1/authz.proto @@ -0,0 +1,26 @@ +syntax = "proto3"; + +package glifa.common.v1; + +option go_package = "glifa/contracts/gen/go/glifa/common/v1;commonv1"; + +message SubjectContext { + string user_id = 1; // UUID пользователя, которому принадлежат права + string device_id = 2; // UUID устройства, с которого пришел запрос (если есть) + string session_id = 3; // UUID сессии, если пользователь авторизован + repeated string global_roles = 4; // Глобальные роли пользователя (например, "admin", "moderator") + repeated string global_permissions = 5; // Глобальные права пользователя (например, "read_all", "write_all") +} + +message PermissionCheck { + string resource_type = 1; // Тип ресурса (например, "user", "device", "session") + string resource_id = 2; // UUID ресурса, к которому запрашиваются права + string permission = 3; // Запрашиваемое право (например, "read", "write", "delete") +} + +message PermissionDecision { + string permission = 1; // Запрашиваемое право (например, "read", "write", "delete") + bool allowed = 2; // Разрешено ли запрашиваемое право + string reason = 3; // Причина решения (например, "user_is_owner", "user_has_role_admin") +} + diff --git a/proto/glifa/common/v1/enums.proto b/proto/glifa/common/v1/enums.proto new file mode 100644 index 0000000..d977ffd --- /dev/null +++ b/proto/glifa/common/v1/enums.proto @@ -0,0 +1,40 @@ +syntax = "proto3"; + +package glifa.common.v1; + +option go_package = "glifa/contracts/gen/go/glifa/common/v1;commonv1"; + +// --- Общие перечисления --- + +enum SortDirection { + SORT_DIRECTION_UNSPECIFIED = 0; // Не указано + SORT_DIRECTION_ASC = 1; // По возрастанию + SORT_DIRECTION_DESC = 2; // По убыванию +} + +enum Visibility { + VISIBILITY_UNSPECIFIED = 0; // Не указано + VISIBILITY_PUBLIC = 1; // Публичный ресурс, доступный всем + VISIBILITY_PRIVATE = 2; // Приватный ресурс, доступный только владельцу + VISIBILITY_INTERNAL = 3; // Внутренний ресурс, доступный только внутри системы +} + +enum MessageContentType { + MESSAGE_CONTENT_TYPE_UNSPECIFIED = 0; // Не указано + MESSAGE_CONTENT_TYPE_TEXT = 1; // Текстовое сообщение + MESSAGE_CONTENT_TYPE_IMAGE = 2; // Изображение + MESSAGE_CONTENT_TYPE_VIDEO = 3; // Видео + MESSAGE_CONTENT_TYPE_AUDIO = 4; // Аудио + MESSAGE_CONTENT_TYPE_FILE = 5; // Файл + MESSAGE_CONTENT_TYPE_SYSTEM = 6; // Системное сообщение (например, уведомление о входе пользователя) +} + +enum EncryptionMode { + ENCRYPTION_MODE_UNSPECIFIED = 0; // Не указано + ENCRYPTION_MODE_NONE = 1; // Без шифрования + ENCRYPTION_MODE_SERVER = 2; // Шифрование на стороне сервера + ENCRYPTION_MODE_E2EE = 3; // End-to-End шифрование +} + + + diff --git a/proto/glifa/common/v1/types.proto b/proto/glifa/common/v1/types.proto new file mode 100644 index 0000000..a578d8a --- /dev/null +++ b/proto/glifa/common/v1/types.proto @@ -0,0 +1,64 @@ +syntax = "proto3"; + +package glifa.common.v1; + +import "google/protobuf/timestamp.proto"; + +option go_package = "glifa/contracts/gen/go/glifa/common/v1;commonv1"; + +// --- Общие структуры --- + +message Empty {} + +message RequestMeta { + string request_id = 1; // UUID4 для трассировки запроса + string trace_id = 2; // UUID4 для распределенного трейсинга + string correlation_id = 3; // UUID4 для корреляции логов + string idempotency_key = 4; // UUID4 для идемпотентности операций + string actor_user_id = 5; // UUID пользователя, инициировавшего запрос (если есть) + string actor_device_id = 6; // UUID устройства, с которого пришел запрос ( + string actor_session_id = 7; // UUID сессии, если пользователь авторизован + string client_ip = 8; // IP-адрес клиента, от которого пришел запрос + string user_agent = 9; // User-Agent клиента + string locale = 10; // Локаль клиента (например, "en-US") +} + +message PageRequest { + uint32 limit = 1; // Количество элементов на странице + string cursor = 2; // Курсор для пагинации (например, ID последнего элемента на предыдущей странице) +} + +message PageResponse { + string next_cursor = 1; // Курсор для следующей страницы (например, ID последнего элемента на текущей странице) + bool has_more = 2; // Флаг, указывающий, есть ли еще страницы +} + +message StringValue { + string value = 1; +} + +message BoolValue { + bool value = 1; +} + +message Int64Value { + int64 value = 1; +} + +message ErrorDetail { + string code = 1; // Код ошибки (например, "USER_NOT_FOUND") + string message = 2; // Человеко-читаемое сообщение об ошибке + map fields = 3; // Дополнительные данные об ошибке +} + +message ResourceRef{ + string id = 1; // UUID ресурса + string type = 2; // Тип ресурса (например, "user", "device", "session") +} + +message AuditStamp { + google.protobuf.Timestamp created_at = 1; // Время создания ресурса + ResourceRef created_by = 2; // Ссылка на ресурс, который создал этот ресурс + google.protobuf.Timestamp updated_at = 3; // Время последнего обновления ресурса + ResourceRef updated_by = 4; // Ссылка на ресурс, который последний обновил этот ресурс +} diff --git a/proto/glifa/core/v1/service.proto b/proto/glifa/core/v1/service.proto new file mode 100644 index 0000000..0a352c8 --- /dev/null +++ b/proto/glifa/core/v1/service.proto @@ -0,0 +1,187 @@ +syntax = "proto3"; + +package glifa.core.v1; + +import "glifa/common/v1/types.proto"; +import "glifa/common/v1/authz.proto"; +import "glifa/core/v1/types.proto"; +import "google/protobuf/struct.proto"; +import "glifa/common/v1/enums.proto"; + +option go_package = "glifa/contracts/gen/go/core/v1;corev1"; + +service CoreService { + rpc CreateDirectChat(CreateDirectChatRequest) returns (CreateDirectChatResponse); + rpc CreateGroupChat(CreateGroupChatRequest) returns (CreateGroupChatResponse); + rpc AddChatMember(AddChatMemberRequest) returns (AddChatMemberResponse); + rpc RemoveChatMember(RemoveChatMemberRequest) returns (RemoveChatMemberResponse); + rpc SendMessage(SendMessageRequest) returns (SendMessageResponse); + rpc EditMessage(EditMessageRequest) returns (EditMessageResponse); + rpc DeleteMessage(DeleteMessageRequest) returns (DeleteMessageResponse); + rpc GetChat(GetChatRequest) returns (GetChatResponse); + rpc GetMessage(GetMessageRequest) returns (GetMessageResponse); + rpc GetHistory(GetHistoryRequest) returns (GetHistoryResponse); + rpc UpdateReadCursor(UpdateReadCursorRequest) returns (UpdateReadCursorResponse); + rpc GetReadCursor(GetReadCursorRequest) returns (GetReadCursorResponse); + rpc GetUserProfile(GetUserProfileRequest) returns (GetUserProfileResponse); + rpc SearchUserProfiles(SearchUserProfilesRequest) returns (SearchUserProfilesResponse); + rpc CheckPermissions(CheckPermissionsRequest) returns (CheckPermissionsResponse); +} + +message CreateDirectChatRequest { + glifa.common.v1.RequestMeta meta = 1; + string initiator_user_id = 2; // UUID пользователя, который инициирует создание чата + string peer_user_id = 3; // UUID другого пользователя, с которым будет создан прямой чат +} + +message CreateDirectChatResponse { + Chat chat = 1; // Информация о созданном чате +} + +message CreateGroupChatRequest { + glifa.common.v1.RequestMeta meta = 1; + string created_by_user_id = 2; // UUID пользователя, который инициирует создание чата + string title = 3; // Название группового чата + repeated string member_user_ids = 4; // Список UUID пользователей, которые будут добавлены в групповой чат (может быть пустым, тогда чат будет создан без участников, кроме создателя) +} + +message CreateGroupChatResponse { + Chat chat = 1; // Информация о созданном чате +} + +message AddChatMemberRequest { + glifa.common.v1.RequestMeta meta = 1; + string chat_id = 2; // UUID чата, в который нужно добавить участника + string user_id = 3; // UUID пользователя, которого нужно добавить в чат +} + +message AddChatMemberResponse { + ChatMember member = 1; // Информация о добавленном участнике чата +} + +message RemoveChatMemberRequest { + glifa.common.v1.RequestMeta meta = 1; + string chat_id = 2; // UUID чата, из которого нужно удалить участника + string user_id = 3; // UUID пользователя, которого нужно удалить из чата +} + +message RemoveChatMemberResponse { + bool success = 1; // Флаг, указывающий, был ли участник успешно удален из чата +} + +message SendMessageRequest { + glifa.common.v1.RequestMeta meta = 1; + string chat_id = 2; // UUID чата, в который нужно отправить сообщение + string client_message_id = 3; // Идентификатор сообщения, сгенерированный на клиенте (для обеспечения идемпотентности при повторной отправке) + glifa.common.v1.MessageContentType message_type = 4; // Тип контента сообщения (например, "text", "image", "file") + string text = 5; // Текст сообщения (если message_type == "text") + string file_id = 6; // UUID файла, прикрепленного к сообщению (если message_type == "file") + string reply_to_message_id = 7; // UUID сообщения, на которое был дан ответ (если это + glifa.common.v1.EncryptionMode encryption_mode = 8; // Режим шифрования сообщения (например, "none", "client_side") + google.protobuf.Struct metadata = 9; // Дополнительные метаданные сообщения в виде произвольной JSON-структуры (например, для хранения информации о медиа-контенте) +} + +message SendMessageResponse { + ChatMessage message = 1; // Информация о созданном сообщении + MessageSendStatus status = 2; // Статус отправки сообщения (например, "sent", "delivered", "read") +} + +message EditMessageRequest { + glifa.common.v1.RequestMeta meta = 1; + string message_id = 2; // UUID сообщения, которое нужно отредактировать + string text = 3; // Новый текст сообщения (если message_type == "text") + google.protobuf.Struct metadata = 4; // Новые дополнительные метаданные сообщения в виде произвольной JSON-структуры (например, для обновления информации о медиа-контенте) +} + +message EditMessageResponse { + ChatMessage message = 1; // Информация об отредактированном сообщении +} + +message DeleteMessageRequest { + glifa.common.v1.RequestMeta meta = 1; + string message_id = 2; // UUID сообщения, которое нужно удалить +} + +message DeleteMessageResponse { + bool success = 1; // Флаг, указывающий, было ли сообщение успешно удалено +} + +message GetChatRequest { + glifa.common.v1.RequestMeta meta = 1; + string chat_id = 2; // UUID чата, информацию о котором нужно получить +} + +message GetChatResponse { + Chat chat = 1; // Информация о запрошенном чате + repeated ChatMember members = 2; // Список участников чата +} + +message GetMessageRequest { + glifa.common.v1.RequestMeta meta = 1; + string message_id = 2; // UUID сообщения, информацию о котором нужно получить +} + +message GetMessageResponse { + ChatMessage message = 1; // Информация о запрошенном сообщении +} + +message GetHistoryRequest { + glifa.common.v1.RequestMeta meta = 1; + string chat_id = 2; // UUID чата, историю которого нужно получить + glifa.common.v1.PageRequest page = 3; // Параметры пагинации для получения истории сообщений +} + +message GetHistoryResponse { + repeated ChatMessage messages = 1; // Список сообщений в запрошенной истории + glifa.common.v1.PageResponse page = 2; // Информация о пагинации (номер страницы, размер страницы, общее количество сообщений) +} + +message UpdateReadCursorRequest { + glifa.common.v1.RequestMeta meta = 1; + string chat_id = 2; // UUID чата, для которого нужно обновить курсор прочтения + uint64 read_chat_seq = 3; // Последовательный номер сообщения, до которого пользователь прочитал чат (включительно) +} + +message UpdateReadCursorResponse { + ChatReadCursor cursor = 1; // Информация об обновленном курсоре прочтения +} + +message GetReadCursorRequest { + glifa.common.v1.RequestMeta meta = 1; + string chat_id = 2; // UUID чата, для которого нужно получить курсор прочтения + string user_id = 3; // UUID пользователя, для которого нужно получить курсор прочтения +} + +message GetReadCursorResponse { + ChatReadCursor cursor = 1; // Информация о курсоре прочтения, включая последний прочитанный последовательный номер сообщения в чате +} + +message GetUserProfileRequest { + glifa.common.v1.RequestMeta meta = 1; + string user_id = 2; // UUID пользователя, профиль которого нужно получить +} + +message GetUserProfileResponse { + UserProfile profile = 1; // Информация о запрошенном профиле пользователя +} + +message SearchUserProfilesRequest { + glifa.common.v1.RequestMeta meta = 1; + string query = 2; // Строка поиска, которая может соответствовать имени пользователя, отображаемому имени или биографии + glifa.common.v1.PageRequest page = 3; // Параметры пагинации для получения результатов поиска +} + +message SearchUserProfilesResponse { + repeated UserProfile items = 1; // Список профилей пользователей, которые соответствуют строке поиска + glifa.common.v1.PageResponse page = 2; // Информация о пагинации (номер страницы, размер страницы, общее количество результатов) +} + +message CheckPermissionsRequest { + glifa.common.v1.RequestMeta meta = 1; + glifa.common.v1.SubjectContext subject = 2; // Контекст субъекта, для которого нужно проверить права (например, идентификатор пользователя, его роли и т.д.) + repeated glifa.common.v1.PermissionCheck checks = 3; // Список прав, которые нужно проверить для данного субъекта (например, "read" право на ресурс "chat" с +} + +message CheckPermissionsResponse { + repeated glifa.common.v1.PermissionDecision decisions = 1; // Список решений по каждому запрашиваемому праву, указывающий, разрешено ли это право для данного субъекта и причину решения +} diff --git a/proto/glifa/core/v1/types.proto b/proto/glifa/core/v1/types.proto new file mode 100644 index 0000000..744d772 --- /dev/null +++ b/proto/glifa/core/v1/types.proto @@ -0,0 +1,93 @@ +syntax = "proto3"; + +package glifa.core.v1; + +import "google/protobuf/struct.proto"; +import "google/protobuf/timestamp.proto"; +import "glifa/common/v1/enums.proto"; + +option go_package = "glifa/contracts/gen/go/core/v1;corev1"; + +enum ChatType{ + CHAT_TYPE_UNSPECIFIED = 0; + CHAT_TYPE_DIRECT = 1; // Прямой чат между двумя пользователями + CHAT_TYPE_GROUP = 2; // Групповой чат с несколькими участниками +} + +enum ChatMemberStatus { + CHAT_MEMBER_STATUS_UNSPECIFIED = 0; + CHAT_MEMBER_STATUS_ACTIVE = 1; // Участник активно участвует в чате + CHAT_MEMBER_STATUS_LEFT = 2; // Участник покинул чат + CHAT_MEMBER_STATUS_REMOVED = 3; // Участник был удален из чата + CHAT_MEMBER_STATUS_BANNED = 4; // Участник был заблокирован в чате +} + +enum MessageSendStatus{ + MESSAGE_SEND_STATUS_UNSPECIFIED = 0; + MESSAGE_SEND_STATUS_ACCEPTED = 1; // Сообщение принято в обработку + MESSAGE_SEND_STATUS_DEDUPLICATED = 2; // Сообщение является дубликатом (например, повторная отправка с тем же client_message_id) +} + +message UserProfile{ + string user_id = 1; // UUID пользователя + string username = 2; // Уникальное имя пользователя (например, "john_doe") + string display_name = 3; // Отображаемое имя пользователя (например, "John Doe") + string bio = 4; // Биография пользователя + string avatar_media_object_id = 5; // UUID медиа-объекта, который используется в качестве аватара пользователя + google.protobuf.Timestamp created_at = 6; // Время создания профиля пользователя + google.protobuf.Timestamp updated_at = 7; // Время последнего обновления профиля пользователя +} + +message Chat { + string id = 1; // UUID чата + ChatType type = 2; // Тип чата (прямой или групповой) + string title = 3; // Название чата (для группового чата) + string created_by_user_id = 4; // UUID пользователя, который создал чат + uint64 last_chat_seq = 5; // Последовательный номер последнего сообщения в чате (начинается с 0, увеличивается на 1 для каждого нового сообщения) + string last_message_id = 6; // UUID последнего сообщения в чате + google.protobuf.Timestamp created_at = 7; // Время создания чата + google.protobuf.Timestamp updated_at = 8; // Время последнего обновления чата +} + +message ChatMember { + string chat_id = 1; // UUID чата, к которому относится этот участник + string user_id = 2; // UUID пользователя, который является участником чата + ChatMemberStatus status = 3; // Статус участника в чате (активный, покинувший, удаленный, заблокированный) + google.protobuf.Timestamp joined_at = 4; // Время, когда пользователь присоединился к чату + google.protobuf.Timestamp updated_at = 5; // Время последнего обновления статуса участника в чате +} + +message ChatRole{ + string id = 1; // UUID роли в чате + string chat_id = 2; // UUID чата, к которому относится эта роль + string key = 3; // Уникальный ключ роли (например, "admin", "member") + string title = 4; // Человекочитаемое название роли (например, "Администратор", "Участник") + bool builtin = 5; // Является ли роль встроенной (например, "admin" и "member" могут быть встроенными ролями, которые нельзя удалить) +} + +message ChatMessage{ + string id = 1; // UUID сообщения + string chat_id = 2; // UUID чата, к которому относится это сообщение + uint64 chat_seq = 3; // Последовательный номер сообщения в рамках чата (начинается с 1 и увеличивается на 1 для каждого нового сообщения в этом чате) + string client_message_id = 4; // Уникальный идентификатор сообщения, сгенерированный на клиенте (например, для обеспечения идемпотентности при отправке сообщений) + string sender_user_id = 5; // UUID пользователя, который отправил сообщение + string sender_device_session_id = 6; // UUID сессии устройства, с которого было отправлено сообщение + glifa.common.v1.MessageContentType message_type = 7; // Тип содержимого сообщения (например, text, image, file) + string text = 8; // Текст сообщения (используется, если message_type == text) + string file_name = 9; // Имя файла (используется, если message_type == file) + string reply_to_message_id = 10; // UUID сообщения, на которое данное сообщение является ответом (может быть пустым, если это не ответ на другое сообщение) + glifa.common.v1.EncryptionMode encryption_mode = 11; // Режим шифрования сообщения (например, none, client_side) + google.protobuf.Struct metadata = 12; // Дополнительные метаданные сообщения в виде + bool is_edited = 13; // Флаг, указывающий, было ли сообщение отредактировано после отправки + uint32 edit_version = 14; // Версия редактирования сообщения (увеличивается на 1 при каждом редактировании) + google.protobuf.Timestamp deleted_at = 15; // Время удаления сообщения (устанавливается, если сообщение было удалено) + google.protobuf.Timestamp created_at = 16; // Время создания сообщения + google.protobuf.Timestamp updated_at = 17; // Время последнего обновления сообщения ( +} + +message ChatReadCursor{ + string chat_id = 1; // UUID чата + string user_id = 2; // UUID пользователя + uint64 read_chat_seq = 3; // Последовательный номер сообщения, до которого пользователь прочитал чат (включительно) + google.protobuf.Timestamp updated_at = 4; // Время последнего обновления курсора +} \ No newline at end of file diff --git a/proto/glifa/edge/v1/service.proto b/proto/glifa/edge/v1/service.proto new file mode 100644 index 0000000..a2cceae --- /dev/null +++ b/proto/glifa/edge/v1/service.proto @@ -0,0 +1,30 @@ +syntax = "proto3"; + +package glifa.edge.v1; + +import "glifa/common/v1/types.proto"; + +option go_package = "glifa/contracts/gen/go/glifa/edge/v1;edgev1"; + +service EdgeGagewayService { + rpc Health(HealthRequest) returns (HealthResponse); + rpc Readiness(ReadinessRequest) returns (ReadinessResponse); +} + +message HealthRequest { + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса, такие как идентификатор корреляции, язык и т.д. +} + +message HealthResponse { + string status = 1; // Статус здоровья сервиса, например, "healthy", "degraded", "unhealthy" +} + +message ReadinessRequest { + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса, такие как идентификатор корреляции, язык и т.д. +} + +message ReadinessResponse { + string status = 1; // Статус готовности сервиса, например, "ready", "not_ready" + repeated string checks = 2; // Список проверок, которые были выполнены для определения готовности сервиса, и их результаты (например, "database: ok", "cache: ok", "external_api: timeout") +} + diff --git a/proto/glifa/events/v1/auth_events.proto b/proto/glifa/events/v1/auth_events.proto new file mode 100644 index 0000000..a0b0f2e --- /dev/null +++ b/proto/glifa/events/v1/auth_events.proto @@ -0,0 +1,82 @@ +syntax = "proto3"; + +package glifa.events.v1; + +import "google/protobuf/timestamp.proto"; + +option go_package = "glifa/contracts/gen/go/glifa/events/v1;eventsv1"; + +message AuthUserCreated{ + string user_id = 1; // UUID нового пользователя + string username = 2; // Имя пользователя + string email = 3; // Электронная почта пользователя + string phone = 4; // Номер телефона пользователя + google.protobuf.Timestamp created_at = 5; // Время создания пользователя +} + +message AuthUserUpdated{ + string user_id = 1; // UUID пользователя + string username = 2; // Новое имя пользователя (если изменилось) + string display_name = 3; // Новое отображаемое имя пользователя (если изменилось) + string avatar_media_object_id = 4; // UUID нового аватара пользователя (если изменился) + google.protobuf.Timestamp updated_at = 5; // Время обновления пользователя +} + +message AuthUserBlocked{ + string user_id = 1; // UUID заблокированного пользователя + string reason = 2; // Причина блокировки пользователя + google.protobuf.Timestamp blocked_at = 3; // Время блокировки пользователя +} + +message AuthSessionCreated{ + string session_id = 1; // UUID новой сессии + string user_id = 2; // UUID пользователя, которому принадлежит сессия + string device_id = 3; // UUID устройства, с которого была создана сессия + string status = 4; // Статус сессии (например, "active", "inactive") + google.protobuf.Timestamp created_at = 5; // Время создания сессии +} + +message AuthSessionLocked{ + string session_id = 1; // UUID заблокированной сессии + string user_id = 2; // UUID пользователя, которому принадлежит сессия + string reason = 3; // Причина блокировки сессии + google.protobuf.Timestamp locked_at = 4; // Время блокировки сессии +} + +message AuthSessionUnlocked{ + string session_id = 1; // UUID разблокированной сессии + string user_id = 2; // UUID пользователя, которому принадлежит сессия + google.protobuf.Timestamp unlocked_at = 3; // Время разблокировки сессии +} + +message AuthSessionRevoked{ + string session_id = 1; // UUID отозванной сессии + string user_id = 2; // UUID пользователя, которому принадлежит сессия + string reason = 3; // Причина отзыва сессии + google.protobuf.Timestamp revoked_at = 4; // Время отзыва сессии +} + +message AuthSessionCompromised{ + string session_id = 1; // UUID скомпрометированной сессии + string user_id = 2; // UUID пользователя, которому принадлежит сессия + string reason = 3; // Причина компрометации сессии + google.protobuf.Timestamp compromised_at = 4; // Время компрометации сессии +} + +message AuthQrRequestCreated{ + string request_id = 1; // UUID нового QR-запроса + google.protobuf.Timestamp expires_at = 2; // Время истечения срока действия QR-запроса +} + +message AuthQrRequestApproved{ + string request_id = 1; // UUID одобренного QR-запроса + string approving_user_id = 2; // UUID пользователя, который одобрил QR-запрос + string approving_session_id = 3; // UUID сессии, с которой был одобрен QR-запрос + google.protobuf.Timestamp approved_at = 4; // Время одобрения QR-запроса +} + +message AuthQrRequestExpired{ + string request_id = 1; // UUID истекшего QR-запроса + google.protobuf.Timestamp expired_at = 2; // Время истечения срока действия QR-запроса +} + diff --git a/proto/glifa/events/v1/channel_events.proto b/proto/glifa/events/v1/channel_events.proto new file mode 100644 index 0000000..34960ff --- /dev/null +++ b/proto/glifa/events/v1/channel_events.proto @@ -0,0 +1,55 @@ +syntax = "proto3"; + +package glifa.events.v1; + +import "google/protobuf/timestamp.proto"; +import "glifa/common/v1/enums.proto"; + +option go_package = "glifa/contracts/gen/go/glifa/events/v1;eventsv1"; + +message ChannelCreated { + string channel_id = 1; // UUID канала, который был создан + string handle = 2; // Уникальный идентификатор канала (например, "general", "random") + string title = 3; // Название канала + string owner_user_id = 4; // UUID пользователя, который создал канал + google.protobuf.Timestamp created_at = 5; // Время создания канала +} + +message ChannelSubscriberAdded { + string channel_id = 1; // UUID канала, в который был добавлен подписчик + string user_id = 2; // UUID пользователя, который был добавлен в канал + google.protobuf.Timestamp added_at = 3; // Время добавления подписчика в канал +} + +message ChannelSubscriberRemoved { + string channel_id = 1; // UUID канала, из которого был удален подписчик + string user_id = 2; // UUID пользователя, который был удален из канала + google.protobuf.Timestamp removed_at = 3; // Время удаления подписчика из канала +} + +message ChannelPostCreated { + string post_id = 1; // UUID созданного поста + string channel_id = 2; // UUID канала, в котором был создан пост + uint64 post_seq = 3; // Последовательный номер поста в рамках канала (начинается с 1 и увеличивается на 1 для каждого нового поста в канале) + string client_post_id = 4; // Идентификатор поста, сгенерированный на клиенте (для обеспечения идемпотентности при повторной отправке) + string author_user_id = 5; // UUID пользователя, который создал пост + glifa.common.v1.MessageContentType message_type = 6; // Тип контента поста (например, "text", "image", "file") + string text = 7; // Текст поста (если message_type == "text") + string file_id = 8; // UUID файла, прикрепленного к посту (если message_type == "file") + google.protobuf.Timestamp created_at = 9; // Время создания поста +} + +message ChannelPostEdited { + string post_id = 1; // UUID отредактированного поста + string channel_id = 2; // UUID канала, в котором был создан пост + string edit_version = 3; // Версия редактирования поста (начинается с 1 и увеличивается на 1 для каждого редактирования поста) + string text = 4; // Новый текст поста (если message_type == "text") + google.protobuf.Timestamp updated_at = 5; // Время редактирования поста +} + +message ChannelPostDeleted { + string post_id = 1; // UUID удаленного поста + string channel_id = 2; // UUID канала, в котором был создан пост + google.protobuf.Timestamp deleted_at = 3; // Время удаления поста +} + diff --git a/proto/glifa/events/v1/core_events.proto b/proto/glifa/events/v1/core_events.proto new file mode 100644 index 0000000..d475066 --- /dev/null +++ b/proto/glifa/events/v1/core_events.proto @@ -0,0 +1,78 @@ +syntax = "proto3"; + +package glifa.events.v1; + +import "google/protobuf/timestamp.proto"; +import "glifa/common/v1/enums.proto"; + +option go_package = "glifa/contracts/gen/go/glifa/events/v1;eventsv1"; + +message CoreUserProfileCreated { + string user_id = 1; // UUID пользователя, для которого создан профиль + string username = 2; // Имя пользователя + string display_name = 3; // Отображаемое имя пользователя + google.protobuf.Timestamp created_at = 4; // Время создания профиля пользователя +} + +message CoreUserProfileUpdated { + string user_id = 1; // UUID пользователя, чей профиль был обновлен + string display_name = 2; // Новое отображаемое имя пользователя (если изменилось) + string bio = 3; // Новая биография пользователя (если изменилось) + string avatar_media_object_id = 4; // UUID нового аватара пользователя (если изменился) + google.protobuf.Timestamp updated_at = 5; // Время обновления профиля пользователя +} + +message CoreChatMemberAdded { + string chat_id = 1; // UUID чата, в который был добавлен участник + string user_id = 2; // UUID пользователя, который был добавлен в чат + google.protobuf.Timestamp added_at = 4; // Время добавления участника в чат +} + +message CoreChatMemberRemoved { + string chat_id = 1; // UUID чата, из которого был удален участник + string user_id = 2; // UUID пользователя, который был удален из чата + google.protobuf.Timestamp removed_at = 4; // Время удаления участника из чата +} + +message CoreChatRoleAssigned { + string chat_id = 1; // UUID чата, в котором была назначена роль + string user_id = 2; // UUID пользователя, которому была назначена роль + string role_key = 3; // Ключ роли, которая была назначена пользователю (например, "admin", "moderator") + google.protobuf.Timestamp assigned_at = 4; // Время назначения роли пользователю в ч +} + +message CoreMessageCreated { + string message_id = 1; // UUID созданного сообщения + string chat_id = 2; // UUID чата, в котором было создано сообщение + string chat_seq = 3; // Последовательный номер сообщения в рамках чата (начинается с 1 и увеличивается на 1 для каждого нового сообщения в чате) + string client_message_id = 4; // Идентификатор сообщения, сгенерированный на клиенте (для обеспечения идемпотентности при повторной отправке) + string sender_user_id = 5; // UUID пользователя, который отправил сообщение + string sender_session_id = 6; // UUID сессии, с которой было отправлено сообщение + glifa.common.v1.MessageContentType message_type = 7; // Тип контента сообщения (например, "text", "image", "file") + glifa.common.v1.EncryptionMode encryption_mode = 8; // Режим шифрования сообщения (например, "none", "end-to-end") + string text = 9; // Текст сообщения (если message_type == "text") + string file_id = 10; // UUID файла, прикрепленного к сообщению (если message_type == "file") + string reply_to_message_id = 11; // UUID сообщения, на которое был дан ответ (если это сообщение является ответом) + google.protobuf.Timestamp created_at = 12; // Время создания сообщения +} + +message CoreMessageEdited { + string message_id = 1; // UUID отредактированного сообщения + string chat_id = 2; // UUID чата, в котором было отредактировано сообщение + string edit_version = 3; // Версия редактирования сообщения (начинается с 1 и увеличивается на 1 для каждого нового редактирования) + string text = 4; // Новый текст сообщения (если message_type == "text") + google.protobuf.Timestamp updated_at = 5; // Время редактирования сообщения +} + +message CoreMessageDeleted { + string message_id = 1; // UUID удаленного сообщения + string chat_id = 2; // UUID чата, в котором было удалено сообщение + google.protobuf.Timestamp deleted_at = 3; // Время удаления сообщения +} + +message CoreMessageReadUpdated { + string chat_id = 1; // UUID чата, в котором было обновлено состояние прочтения сообщений + string user_id = 2; // UUID пользователя, который прочитал сообщения + uint64 read_chat_seq = 3; // Максимальный последовательный номер сообщения, который пользователь прочитал в чате (включительно) + google.protobuf.Timestamp updated_at = 4; // Время обновления состояния прочтения +} diff --git a/proto/glifa/events/v1/eventlope.proto b/proto/glifa/events/v1/eventlope.proto new file mode 100644 index 0000000..fdb2487 --- /dev/null +++ b/proto/glifa/events/v1/eventlope.proto @@ -0,0 +1,24 @@ +syntax = "proto3"; + +package glifa.events.v1; + +import "google/protobuf/timestamp.proto"; +import "google/protobuf/any.proto"; + +option go_package = "glifa/contracts/gen/go/glifa/events/v1;eventsv1"; + +message DurableEventEventlope { + string event_id = 1; // UUID события + string event_type = 2; // Тип события (например, "user.created", " + uint32 event_version = 3; // Версия схемы данных события + string producer = 4; // Идентификатор системы, которая сгенерировала событие + string aggregate_type = 5; // Тип агрегата, к которому относится событие (например, "user", "order") + string aggregate_id = 6; // UUID агрегата, к которому относится событие + string partition_key = 7; // Ключ для партиционирования (например, "user_id" или "order_id") + google.protobuf.Timestamp occurred_at = 8; // Время возникновения события + string trace_id = 9; // UUID для распределенного трейсинга + string correlation_id = 10; // UUID для корреляции логов + string idempotency_key = 11; // UUID для идемпотентности операций + google.protobuf.Any payload = 12; // Данные события в виде сериализованного protobuf-сообщения (может быть любым типом, в зависимости от event_type) +} + diff --git a/proto/glifa/events/v1/media_events.proto b/proto/glifa/events/v1/media_events.proto new file mode 100644 index 0000000..c08b884 --- /dev/null +++ b/proto/glifa/events/v1/media_events.proto @@ -0,0 +1,39 @@ +syntax = "proto3"; + +package glifa.events.v1; + +import "google/protobuf/timestamp.proto"; + +option go_package = "glifa/contracts/gen/go/glifa/events/v1;eventsv1"; + +message MediaUploadInitiated { + string upload_intent_id = 1; // UUID намерения загрузки, который будет использоваться для идентификации процесса загрузки + string owner_user_id = 2; // UUID пользователя, который инициализировал загрузку + google.protobuf.Timestamp initiated_at = 3; // Время инициализации загрузки медиа +} + +message MediaUploadFinalized { + string upload_intent_id = 1; // UUID намерения загрузки, который был использован для идентификации процесса загрузки + string media_object_id = 2; // UUID созданного медиа-объекта после успешной загрузки + google.protobuf.Timestamp finalized_at = 3; // Время финализации загрузки медиа +} + +message MediaObjectActivated { + string media_object_id = 1; // UUID медиа-объекта, который был активирован + string owner_user_id = 2; // UUID пользователя, который активировал медиа-объект + string visibility = 3; // Видимость медиа-объекта (например, "public", "private", "unlisted") + google.protobuf.Timestamp activated_at = 4; // Время активации медиа-объекта (когда он стал доступен для использования) +} + +message MediaObjectQuarantined { + string media_object_id = 1; // UUID медиа-объекта, который был помещен в карантин + string reason = 2; // Причина помещения медиа-объекта в карантин (например, "inappropriate_content", "copyright_violation") + google.protobuf.Timestamp quarantined_at = 3; // Время помещения медиа-объекта в карантин +} + +message MediaVariantCreated { + string media_variant_id = 1; // UUID созданного варианта медиа-объекта + string media_object_id = 2; // UUID медиа-объекта, для которого был создан вариант + string variant_kind = 3; // Тип варианта (например, "thumbnail", "preview", "full") + google.protobuf.Timestamp created_at = 4; // Время создания варианта медиа-объекта +} \ No newline at end of file diff --git a/proto/glifa/media/v1/service.proto b/proto/glifa/media/v1/service.proto new file mode 100644 index 0000000..56d119d --- /dev/null +++ b/proto/glifa/media/v1/service.proto @@ -0,0 +1,107 @@ +syntax = "proto3"; + +package glifa.media.v1; + +import "glifa/common/v1/types.proto"; +import "glifa/media/v1/types.proto"; + +option go_package = "glifa/contracts/gen/go/glifa/media/v1;mediav1"; + +service MediaService { + rpc InitiateUpload(InitiateUploadRequest) returns (InitiateUploadResponse); + rpc PresignPartUpload(PresignPartUploadRequest) returns (PresignPartUploadResponse); + rpc CompletePart(CompletePartRequest) returns (CompletePartResponse); + rpc FinalizeUpload(FinalizeUploadRequest) returns (FinalizeUploadResponse); + rpc AbortUpload(AbortUploadRequest) returns (AbortUploadResponse); + rpc GetMediaObject(GetMediaObjectRequest) returns (GetMediaObjectResponse); + rpc CreateAccessGrant(CreateAccessGrantRequest) returns (CreateAccessGrantResponse); + rpc ResolveDownload(ResolveDownloadRequest) returns (ResolveDownloadResponse); +} + +message InitiateUploadRequest { + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса, такие как идентификатор корреляции, язык и т.д. + string file_name = 2; // Исходное имя файла, который будет загружен + string declared_mime_type = 3; // MIME-тип файла, который будет загружен (например, "image/jpeg", "video/mp4") + uint64 expected_size = 4; // Ожидаемый размер файла в байтах, который будет загружен + bool multipart = 5; // Флаг, указывающий, будет ли загрузка выполняться в несколько частей (multipart upload) + MediaVisibility visibility = 6; // Видимость медиа-объекта (публичный или приватный) +} + +message InitiateUploadResponse { + UploadIntent upload_intent = 1; // Намерение загрузки, содержащее информацию о процессе загрузки и его статусе +} + +message PresignPartUploadRequest { + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса, такие как идентификатор корреляции, язык и т.д. + string upload_intent_id = 2; // UUID намерения загрузки, к которому относится эта часть + int32 part_number = 3; // Номер части в последовательности загрузки (начинается с 1) +} + +message PresignPartUploadResponse { + string url = 1; // Предварительно подписанный URL для загрузки части файла в хранилище + map headers = 2; // Дополнительные заголовки, которые должны быть включены в запрос загрузки части (например, для аутентификации или указания типа контента) +} + +message CompletePartRequest { + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса, такие как идентификатор корреляции, язык и т.д. + string upload_intent_id = 2; // UUID намерения загрузки, к которому относится эта часть + int32 part_number = 3; // Номер части в последовательности загрузки (начинается с 1) + string etag = 4; // ETag, возвращаемый хранилищем после успешной загрузки части, который будет использоваться для финализации загрузки + uint64 size = 5; // Размер части в байтах +} + +message CompletePartResponse { + UploadPart part = 1; // Информация о загруженной части, включая номер части, ETag и размер +} + +message FinalizeUploadRequest { + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса, такие как идентификатор корреляции, язык и т.д. + string upload_intent_id = 2; // UUID намерения загрузки, который будет финализирован + string checksum = 3; // Контрольная сумма (например, MD5 или SHA-256) всего файла, который был загружен, для проверки целостности данных +} + +message FinalizeUploadResponse { + UploadIntent upload_intent = 1; // Намерение загрузки с обновленным статусом, указывающим, что загрузка была успешно завершена + MediaObject media_object = 2; // Информация о созданном медиа-объекте, включая его UUID, размер, MIME-тип и т.д. +} + +message AbortUploadRequest { + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса, такие как идентификатор корреляции, язык и т.д. + string upload_intent_id = 2; // UUID намерения загрузки, который будет прерван +} + +message AbortUploadResponse { + bool success = 1; // Флаг, указывающий, была ли операция прерывания успешной +} + +message GetMediaObjectRequest { + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса, такие как идентификатор корреляции, язык и т.д. + string media_object_id = 2; // UUID медиа-объекта, который пользователь хочет получить +} + +message GetMediaObjectResponse { + MediaObject media_object = 1; // Информация о запрошенном медиа-объекте, включая его UUID, размер, MIME-тип, статус и т.д. +} + +message CreateAccessGrantRequest { + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса, такие как идентификатор корреляции, язык и т.д. + string media_object_id = 2; // UUID медиа-объекта, для которого создается грант доступа + string subject_user_id = 3; // UUID пользователя, которому предоставляется доступ к медиа-объекту + bool single_use = 4; // Флаг, указывающий, является ли грант доступа одноразовым (может быть использован только один раз для доступа к медиа-объекту) +} + +message CreateAccessGrantResponse { + MediaAccessGrant grant = 1; // Информация о созданном гранте доступа, включая его UUID, связанный медиа-объект, субъект доступа и т.д. +} + +message ResolveDownloadRequest { + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса, такие как идентификатор корреляции, язык и т.д. + string media_object_id = 2; // UUID медиа-объекта, который пользователь хочет скачать + string access_grant_id = 3; // UUID гранта доступа, который будет использоваться для авторизации доступа к медиа-объекту при скачивании +} + +message ResolveDownloadResponse { + string url = 1; // Предварительно подписанный URL для скачивания файла медиа-объекта из хранилища + map headers = 2; // Дополнительные заголовки, которые должны быть включены в запрос скачивания файла (например, для аутентификации или указания типа контента) + string method = 3; // HTTP-метод, который должен быть использован для скачивания файла (например, "GET", "POST") +} \ No newline at end of file diff --git a/proto/glifa/media/v1/types.proto b/proto/glifa/media/v1/types.proto new file mode 100644 index 0000000..e1188b9 --- /dev/null +++ b/proto/glifa/media/v1/types.proto @@ -0,0 +1,80 @@ +syntax = "proto3"; + +package glifa.media.v1; + +import "google/protobuf/timestamp.proto"; + +option go_package = "glifa/contracts/gen/go/glifa/media/v1;mediav1"; + +enum UploadIntentStatus{ + UPLOAD_INTENT_STATUS_UNSPECIFIED = 0; // Неопределенный статус намерения загрузки + UPLOAD_INTENT_STATUS_INITIATED = 1; // Намерение загрузки было инициализировано, но загрузка еще не началась + UPLOAD_INTENT_STATUS_UPLOADING = 2; // Процесс загрузки медиа-объекта начался, но еще не завершился + UPLOAD_INTENT_STATUS_FINALIZED = 3; // Процесс загрузки медиа-объекта успешно завершился, и медиа-объект был создан + UPLOAD_INTENT_STATUS_ABORTED = 4; // Процесс загрузки был прерван или отменен до его завершения + UPLOAD_INTENT_STATUS_EXPIRED = 5; // Намерение загрузки истекло, и загрузка не может быть завершена +} + +enum MediaObjectStatus { + MEDIA_OBJECT_STATUS_UNSPECIFIED = 0; // Неопределенный статус медиа-объекта + MEDIA_OBJECT_STATUS_PENDING = 1; // Медиа-объект находится в ожидании обработки (например, конвертации или проверки) + MEDIA_OBJECT_STATUS_ACTIVE = 2; // Медиа-объект активен и доступен для использования + MEDIA_OBJECT_STATUS_QUARANTINED = 3; // Медиа-объект помещен в карантин из-за подозрения на нарушение правил (например, неподобающий контент) + MEDIA_OBJECT_STATUS_DELETED = 4; // Медиа-объект удален и больше не доступен +} + +enum MediaVisibility { + MEDIA_VISIBILITY_UNSPECIFIED = 0; // Неопределенная видимость медиа-объекта + MEDIA_VISIBILITY_PUBLIC = 1; // Медиа-объект публичный и доступен всем пользователям + MEDIA_VISIBILITY_PRIVATE = 2; // Медиа-объект приватный и доступен только владельцу +} + +message UploadIntent { + string id = 1; // UUID намерения загрузки, который будет использоваться для идентификации процесса загрузки + string owner_user_id = 2; // UUID пользователя, который инициализировал + string file_name = 3; // Исходное имя файла, который будет загружен + string declared_mime_type = 4; // MIME-тип файла, который будет загружен (например, "image/jpeg", "video/mp4") + uint64 expected_size = 5; // Ожидаемый размер файла в байтах, который будет загружен + bool multipart = 6; // Флаг, указывающий, будет ли загрузка выполняться в несколько частей (multipart upload) + UploadIntentStatus status = 7; // Текущий статус намерения загрузки + google.protobuf.Timestamp expires_at = 8; // Временная метка, указывающая, когда намерение загрузки истекает и больше не может быть использовано для загрузки файла + google.protobuf.Timestamp created_at = 9; // Временная метка создания намерения загрузки + google.protobuf.Timestamp updated_at = 10; // Временная метка последнего обновления намерения загрузки + +} + +message UploadPart { + string upload_intent_id = 1; // UUID намерения загрузки, к которому относится эта часть + int32 part_number = 2; // Номер части в последовательности загрузки (начинается с 1) + string etag = 3; // ETag, возвращаемый хранилищем после успешной загрузки части, который будет использоваться для финализации загрузки + uint64 size = 4; // Размер части в байтах + google.protobuf.Timestamp completed_at = 5; // Временная метка, указывающая, когда эта часть была успешно загружена +} + +message MediaObject { + string id = 1; // UUID медиа-объекта, который будет использоваться для идентификации и доступа к медиа-объекту + string owner_user_id = 2; // UUID пользователя, которому принадлежит этот медиа-объект + string object_key = 3; // Ключ объекта в хранилище, который указывает на местоположение файла медиа-объекта + string checksum = 4; // Контрольная сумма (например, MD5 или SHA-256) файла медиа-объекта, которая может использоваться для проверки целостности данных + uint64 size = 5; // Размер файла медиа-объекта в бай + string detected_mime_type = 6; // MIME-тип, определенный после загрузки и анализа файла медиа-объекта + MediaVisibility visibility = 7; // Видимость медиа-объекта (публичный или приватный) + MediaObjectStatus status = 8; // Текущий статус медиа-объекта (например, ожидает обработки, активен, в карантине, удален) + string encryption_key_ref = 9; // Ссылка на ключ шифрования, если медиа-объект зашифрован + string link_resource_type = 10; // Тип ресурса, с которым связан этот медиа-объект (например, "post", "profile_picture", "document") + string link_resource_id = 11; // UUID ресурса, с которым связан этот медиа-объект (например, идентификатор поста, идентификатор профиля пользователя, идентификатор документа) + google.protobuf.Timestamp created_at = 12; // Временная метка создания медиа-объекта + google.protobuf.Timestamp updated_at = 13; // Временная метка последнего обновления медиа-объекта +} + +message MediaAccessGrant{ + string id = 1; // UUID разрешения доступа, который будет использоваться для идентификации и управления разрешением доступа + string media_object_id = 2; // UUID медиа-объекта, к + string subject_user_id = 3; // UUID пользователя, которому предоставлено разрешение доступа к медиа-объекту + bool single_use = 4; // Флаг, указывающий, является ли это разрешение одноразовым (single-use), которое может быть использовано только один раз для доступа к медиа-объекту + google.protobuf.Timestamp expires_at = 5; // Временная метка, указывающая, когда разрешение доступа истекает и больше не может быть использовано для доступа к медиа-объекту + google.protobuf.Timestamp consumed_at = 6; // Временная метка, указывающая, когда это разрешение доступа было использовано для доступа к медиа-объекту (для одноразовых разрешений) + google.protobuf.Timestamp created_at = 7; // Временная метка создания разрешения доступа + +} + diff --git a/proto/glifa/ws/v1/service.proto b/proto/glifa/ws/v1/service.proto new file mode 100644 index 0000000..9e8adf4 --- /dev/null +++ b/proto/glifa/ws/v1/service.proto @@ -0,0 +1,76 @@ +syntax = "proto3"; + +package glifa.ws.v1; + +import "glifa/common/v1/types.proto"; +import "glifa/ws/v1/types.proto"; + +option go_package = "glifa/contracts/gen/go/glifa/ws/v1;wsv1"; + +service WsGatewayService { + rpc RegisterConnection(RegisterConnectionRequest) returns (RegisterConnectionResponse); + rpc UnregisterConnection(UnregisterConnectionRequest) returns (UnregisterConnectionResponse); + rpc PublishEnvelope(PublishEnvelopeRequest) returns (PublishEnvelopeResponse); + rpc PublishPresence(PublishPresenceRequest) returns (PublishPresenceResponse); + rpc PublishTyping(PublishTypingRequest) returns (PublishTypingResponse); + rpc ListUserConnections(ListUserConnectionsRequest) returns (ListUserConnectionsResponse); +} + +message RegisterConnectionRequest { + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса, такие как идентификатор корреляции, язык и т.д. + string access_token = 2; // Токен доступа, который будет использоваться для аутентификации и авторизации соединения + string connection_id = 3; // Уникальный идентификатор соединения, который может быть сгенерирован клиентом или сервером для отслеживания этого соединения + string node_id = 4; // Идентификатор узла, к которому подключается это соединение, если используется распределенная архитектура с несколькими узлами +} + +message RegisterConnectionResponse { + ConnectionInfo connection = 1; // Информация о зарегистрированном соединении, включая его статус и метаданные +} + +message UnregisterConnectionRequest { + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса, такие как идентификатор корреляции, язык и т.д. + string connection_id = 2; // Уникальный идентификатор соединения, которое должно быть удалено или разорвано +} + +message UnregisterConnectionResponse { + bool success = 1; // Флаг, указывающий, было ли соединение успешно удалено или разорвано +} + +message PublishEnvelopeRequest { + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса, такие как идентификатор корреляции, язык и т.д. + repeated string target_user_ids = 2; // Список UUID пользователей, которые являются целевыми получателями этого сообщения, и которым должно быть доставлено это сообщение + repeated string target_session_ids = 3; // Список UUID сессий, которые являются целевыми получателями этого сообщения, и которым должно быть доставлено это сообщение + repeated string target_channel_ids = 4; // Список UUID каналов или тем, на которые подписаны получатели, которым должно быть доставлено это сообщение + RealtimeEnvelope envelope = 5; // Конверт в реальном времени, который содержит данные и метаданные сообщения, которое должно быть доставлено получателям +} + +message PublishEnvelopeResponse { + uint32 accepted_targets = 1; // Количество целевых получателей, которым было принято это сообщение для доставки (например, количество пользователей, сессий или каналов, которым было отправлено это сообщение) +} + +message PublishPresenceRequest { + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса, такие как идентификатор корреляции, язык и т.д. + PresenceState presence = 2; // Состояние присутствия пользователя, которое должно быть опубликовано и доставлено подписчикам +} + +message PublishPresenceResponse { + bool success = 1; // Флаг, указывающий, было ли состояние присутствия успешно опубликовано и доставлено подписчикам +} + +message PublishTypingRequest { + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса, такие как идентификатор корреляции, язык и т.д. + TypingState typing = 2; // Состояние печати пользователя, которое должно быть опубликовано и доставлено подписчикам +} + +message PublishTypingResponse { + bool success = 1; // Флаг, указывающий, было ли состояние печати успешно опубликовано и доставлено подписчикам +} + +message ListUserConnectionsRequest { + glifa.common.v1.RequestMeta meta = 1; // Метаданные запроса, такие как идентификатор корреляции, язык и т.д. + string user_id = 2; // UUID пользователя, для которого нужно получить список активных соединений +} + +message ListUserConnectionsResponse { + repeated ConnectionInfo items = 1; // Список активных соединений, связанных с указанным пользователем, включая их статус и метаданные +} diff --git a/proto/glifa/ws/v1/types.proto b/proto/glifa/ws/v1/types.proto new file mode 100644 index 0000000..5ad3fd3 --- /dev/null +++ b/proto/glifa/ws/v1/types.proto @@ -0,0 +1,56 @@ +syntax = "proto3"; + +package glifa.ws.v1; + +import "google/protobuf/timestamp.proto"; +import "google/protobuf/any.proto"; +option go_package = "glifa/contracts/gen/go/glifa/ws/v1;wsv1"; + +enum ConnectionStatus { + CONNECTION_STATUS_UNSPECIFIED = 0; // Неопределенный статус соединения + CONNECTION_STATUS_CONNECTED = 1; // Соединение установлено и активно + CONNECTION_STATUS_DRAINING = 2; // Соединение находится в процессе завершения, и новые сообщения не принимаются, но существующие сообщения могут быть доставлены + CONNECTION_STATUS_DISCONNECTED = 3; // Соединение было разорвано или потеряно +} + +enum RealtimeEnvelopeKind { + REALTIME_ENVELOPE_KIND_UNSPECIFIED = 0; // Неопределенный тип конверта в реальном времени + REALTIME_ENVELOPE_KIND_DURABLE = 1; // Конверт в реальном времени, который гарантирует доставку сообщения получателю, даже если он временно недоступен (например, из-за отключения от сети) + REALTIME_ENVELOPE_KIND_EPHEMERAL = 2; // Конверт в реальном времени, который не гарантирует доставку сообщения получателю, если он временно недоступен (например, из-за отключения от сети), и может быть потерян в таких случаях +} + +message ConnectionInfo { + string connection_id = 1; // Уникальный идентификатор соединения, который может использоваться для отслеживания и управления соединением + string user_id = 2; // UUID пользователя, которому принадлежит это соединение + string session_id = 3; // UUID сессии, которая связана с этим соединением + string device_id = 4; // UUID устройства, с которого установлено это соединение + string node_id = 5; // Идентификатор узла, к которому подключено это соединение, если используется распределенная архитектура с несколькими узлами + ConnectionStatus status = 6; // Текущий статус соединения (например, подключено, в процессе завершения, отключено) + google.protobuf.Timestamp connected_at = 7; // Временная метка, указывающая, когда это соединение было установлено + google.protobuf.Timestamp last_seen_at = 8; // Временная метка, указывающая, когда это соединение в последний раз было активно или получало сообщения + repeated string subscriptions = 9; // Список подписок, на которые подписано это соединение, например, идентификаторы каналов или тем, на которые оно подписано для получения сообщений +} + +message RealtimeEnvelope { + string envelope_id = 1; // Уникальный идентификатор конверта в реальном времени, который может использоваться для отслеживания и управления сообщениями + RealtimeEnvelopeKind kind = 2; // Тип конверта в реальном времени, который определяет гарантии доставки сообщения (например, долговременный или эфемерный) + string topic = 3; // Тема или канал, на который это сообщение предназначено, и на который подписаны получатели, которые должны получить это сообщение + string aggregate_id = 4; // Идентификатор агрегата, который может использоваться для группировки связанных сообщений вместе (например, все сообщения, относящиеся к одному чату или разговору) + string event_type = 5; // Тип события, который описывает содержание или действие, связанное с этим сообщением (например, "message.created", "user.typing", "notification.new") + string event_version = 6; // Версия схемы события, которая может использоваться для управления изменениями в структуре данных события с течением времени + google.protobuf.Timestamp occurred_at = 7; // Временная метка, указывающая, когда это событие произошло или было создано, что может использоваться для упорядочивания сообщений и управления временем жизни сообщений + google.protobuf.Any payload = 8; // Полезная нагрузка сообщения, которая может содержать любые данные, связанные с этим событием, и может быть сериализована в формате JSON +} + +message PresenceState{ + string user_id = 1; // UUID пользователя, чье присутствие отслеживается + bool online = 2; // Статус присутствия пользователя (true - онлайн, false - офлайн) + google.protobuf.Timestamp last_seen_at = 3; // Временная метка, указывающая, когда пользователь в последний раз был онлайн или активен +} + +message TypingState { + string chat_id = 1; // UUID чата или канала, в котором пользователь печатает + string user_id = 2; // UUID пользователя, который печатает + string session_id = 3; // UUID сессии пользователя, который печатает + google.protobuf.Timestamp expires_at = 4; // Временная метка, указывающая, когда статус печати должен истечь (например, если пользователь перестал печатать и не отправил сообщение в течение определенного времени) +} \ No newline at end of file diff --git a/scripts/generate-proto.mjs b/scripts/generate-proto.mjs new file mode 100644 index 0000000..9cf58ec --- /dev/null +++ b/scripts/generate-proto.mjs @@ -0,0 +1,97 @@ +import { execFileSync } from 'node:child_process' +import { + existsSync, + mkdirSync, + readdirSync, + rmSync, + statSync, +} from 'node:fs' +import { delimiter, join, relative } from 'node:path' + +const rootDir = process.cwd() + +const protoRoot = 'proto' +const genRoot = 'gen' + +function toUnixPath(path) { + return path.replaceAll('\\', '/') +} + +function collectProtoFiles(dir) { + const files = [] + + for (const entry of readdirSync(dir)) { + const fullPath = join(dir, entry) + const stat = statSync(fullPath) + + if (stat.isDirectory()) { + files.push(...collectProtoFiles(fullPath)) + continue + } + + if (entry.endsWith('.proto')) { + files.push(toUnixPath(relative(rootDir, fullPath))) + } + } + + return files +} + +if (!existsSync(protoRoot)) { + console.error(`Proto directory not found: ${protoRoot}`) + process.exit(1) +} + +const tsProtoBinDir = join('node_modules', '.bin') +const tsProtoCmd = join(tsProtoBinDir, 'protoc-gen-ts_proto.cmd') + +if (!existsSync(tsProtoCmd)) { + console.error('ts-proto plugin not found.') + console.error('Run: yarn add -D ts-proto') + process.exit(1) +} + +const protoFiles = collectProtoFiles(protoRoot) + +if (protoFiles.length === 0) { + console.error('No .proto files found.') + process.exit(1) +} + +rmSync(genRoot, { + recursive: true, + force: true, +}) + +mkdirSync(genRoot, { + recursive: true, +}) + +const env = { + ...process.env, + + // Windows обычно использует Path, Linux/macOS используют PATH. + PATH: `${tsProtoBinDir}${delimiter}${process.env.PATH ?? ''}`, + Path: `${tsProtoBinDir}${delimiter}${process.env.Path ?? ''}`, +} + +execFileSync( + 'protoc', + [ + '-I', + protoRoot, + + '--ts_proto_out', + genRoot, + + '--ts_proto_opt', + 'nestJs=true,package=omit', + + ...protoFiles, + ], + { + cwd: rootDir, + stdio: 'inherit', + env, + }, +) \ No newline at end of file diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..3254ee3 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,86 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@bufbuild/protobuf@^2.0.0", "@bufbuild/protobuf@^2.10.2": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@bufbuild/protobuf/-/protobuf-2.12.0.tgz#53225636a8fcebb2bd94998ad9d42f99f96add4d" + integrity sha512-B/XlCaFIP8LOwzo+bz5uFzATYokcwCKQcghqnlfwSmM5eX/qTkvDBnDPs+gXtX/RyjxJ4DRikECcPJbyALA8FA== + +"@nestjs/microservices@^11.1.23": + version "11.1.23" + resolved "https://registry.yarnpkg.com/@nestjs/microservices/-/microservices-11.1.23.tgz#d34c54e895525c259491c4e5612958a815dec9d2" + integrity sha512-iVPp3u274Xx6XAEbKPWDCzUHP6wlt7L7RXUIyIpf3caJ3ldFh/dG3uyHva1lgjHG+ukz+XCXafl1cx352TPW0w== + dependencies: + iterare "1.2.1" + tslib "2.8.1" + +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== + +detect-libc@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg== + +dprint-node@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/dprint-node/-/dprint-node-1.0.8.tgz#a02470722d8208a7d7eb3704328afda1d6758625" + integrity sha512-iVKnUtYfGrYcW1ZAlfR/F59cUVL8QIhWoBJoSjkkdua/dkWIgjZfiLMeTjiB06X0ZLkQ0M2C1VbUj/CxkIf1zg== + dependencies: + detect-libc "^1.0.3" + +iterare@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/iterare/-/iterare-1.2.1.tgz#139c400ff7363690e33abffa33cbba8920f00042" + integrity sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q== + +long@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/long/-/long-5.3.2.tgz#1d84463095999262d7d7b7f8bfd4a8cc55167f83" + integrity sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA== + +protobufjs@^8.4.0: + version "8.4.0" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-8.4.0.tgz#57664ab3f835ec6e326fd9a98178da132b8b7240" + integrity sha512-iriNhQ57SYA5Jbdi+41AyPdx6jPPkFO7DODzkOBmqFhgYn/JzX2HxgxYPY18eQAs3CP/AWqtPvkWn8rclRAxdQ== + dependencies: + long "^5.3.2" + +rxjs@^7.8.2: + version "7.8.2" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.2.tgz#955bc473ed8af11a002a2be52071bf475638607b" + integrity sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA== + dependencies: + tslib "^2.1.0" + +ts-poet@^6.12.0: + version "6.12.0" + resolved "https://registry.yarnpkg.com/ts-poet/-/ts-poet-6.12.0.tgz#f28eb91778fdff8e1b264600c7ddddb40cd39d84" + integrity sha512-xo+iRNMWqyvXpFTaOAvLPA5QAWO6TZrSUs5s4Odaya3epqofBu/fMLHEWl8jPmjhA0s9sgj9sNvF1BmaQlmQkA== + dependencies: + dprint-node "^1.0.8" + +ts-proto-descriptors@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ts-proto-descriptors/-/ts-proto-descriptors-2.1.0.tgz#0c60525ea94748f7b3f394dc10d6eb8eeac4fe39" + integrity sha512-S5EZYEQ6L9KLFfjSRpZWDIXDV/W7tAj8uW7pLsihIxyr62EAVSiKuVPwE8iWnr849Bqa53enex1jhDUcpgquzA== + dependencies: + "@bufbuild/protobuf" "^2.0.0" + +ts-proto@^2.11.8: + version "2.11.8" + resolved "https://registry.yarnpkg.com/ts-proto/-/ts-proto-2.11.8.tgz#5e96f67213985dbde7513a8114bf750b144621a5" + integrity sha512-+5hzECnyVB33jxjG1BIdzAHcRBm7hjnm8womdJVp2A7xJWihP0drHHVsXYTr9i/LpWNGfh80I+AVVNzFM5AwJw== + dependencies: + "@bufbuild/protobuf" "^2.10.2" + case-anything "^2.1.13" + ts-poet "^6.12.0" + ts-proto-descriptors "2.1.0" + +tslib@2.8.1, tslib@^2.1.0: + version "2.8.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" + integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==