[598-32][@ant] feat: backend+SDK подписочный канал marketplace (Фаза 2A) — realtime-события пайщика вместо поллинга
Поднят первый GraphQL-subscription поверх graphql-ws на том же /v1/graphql: - PubSubModule (@Global, in-memory) — единый брокер событий приложения. - Подписка marketplaceEvents: union MarketplaceEvent (OrderReadyToReceive | ReceptionPendingSign) — «сигнал, а не данные»; детали клиент дочитывает авторизованным query. - Мост MarketplaceRealtimeBridge: доменные события EventEmitter2 (эмит после commit в PG, INV-12) → публикация в ПЕРСОНАЛЬНЫЙ топик адресата (marketplace:events:<coop>:<account>). Чужому пайщику событие физически не попадает — топик строится из аккаунта, не из аргументов клиента. - Аутентификация ws — в graphql-ws onConnect: верификация access-JWT из connectionParams, sub кладётся в контекст; единый context прокидывает юзера в req.user, чтобы @CurrentUser работал и на ws. HTTP-путь не тронут. - DRY: резолв юзера по sub вынесен в resolveUserBySub (стратегия + резолвер). - SDK: новая категория Subscriptions.Marketplace.Events (строгая типизация IInput/IOutput, селектор union через ...on), геттер Client.Subscription прокидывает Authorization в connectionParams. ZEUS-клиент пересобран. Зачем: убрать 10-сек поллинг гейта подписи на месте — позиции пункта должны прилетать в реальном времени и приватно, а не по капле общими опросами. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -130,6 +130,7 @@
|
||||
"graphql": "^16.9.0",
|
||||
"graphql-request": "^7.1.2",
|
||||
"graphql-scalars": "^1.24.0",
|
||||
"graphql-subscriptions": "^2.0.0",
|
||||
"graphql-tools": "^9.0.2",
|
||||
"graphql-type-json": "^0.3.2",
|
||||
"graphql-ws": "^5.16.0",
|
||||
@@ -166,6 +167,7 @@
|
||||
"rxjs": "^7.8.2",
|
||||
"socket.io-client": "^4.7.5",
|
||||
"spectaql": "^3.0.5",
|
||||
"subscriptions-transport-ws": "^0.11.0",
|
||||
"swagger-jsdoc": "^6.0.8",
|
||||
"swagger-ui-express": "^4.1.6",
|
||||
"threads": "^1.7.0",
|
||||
|
||||
@@ -6,6 +6,7 @@ import config from '~/config/config';
|
||||
import { tokenTypes } from '~/types/token.types';
|
||||
import { USER_REPOSITORY, UserRepository } from '~/domain/user/repositories/user.repository';
|
||||
import { UserDomainService, USER_DOMAIN_SERVICE } from '~/domain/user/services/user-domain.service';
|
||||
import { resolveUserBySub } from '~/application/auth/utils/resolve-user-by-sub';
|
||||
|
||||
@Injectable()
|
||||
export class JwtAuthStrategy extends PassportStrategy(JwtStrategy) {
|
||||
@@ -24,27 +25,7 @@ export class JwtAuthStrategy extends PassportStrategy(JwtStrategy) {
|
||||
throw new Error('Invalid token type');
|
||||
}
|
||||
|
||||
const userId = payload.sub;
|
||||
|
||||
// Определяем тип ID заранее для оптимизации запросов
|
||||
let user;
|
||||
if (this.isLegacyMongoId(userId)) {
|
||||
// Это legacy MongoDB ObjectId
|
||||
try {
|
||||
user = await this.userDomainService.getUserByLegacyMongoId(userId);
|
||||
} catch (error) {
|
||||
throw new Error('Пользователь с указанным JWT не найден');
|
||||
}
|
||||
} else if (this.isValidUuid(userId)) {
|
||||
// Это новый UUID
|
||||
user = await this.userRepository.findById(userId);
|
||||
if (!user) {
|
||||
throw new Error('Пользователь с указанным JWT не найден');
|
||||
}
|
||||
} else {
|
||||
// Неизвестный формат ID
|
||||
throw new Error('Неверный формат ID пользователя в JWT токене');
|
||||
}
|
||||
const user = await resolveUserBySub(payload.sub, this.userRepository, this.userDomainService);
|
||||
|
||||
// Возвращаем объект в формате, совместимом с MonoAccountDomainInterface
|
||||
return {
|
||||
@@ -64,23 +45,4 @@ export class JwtAuthStrategy extends PassportStrategy(JwtStrategy) {
|
||||
subscriber_hash: user.subscriber_hash,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверяет, является ли строка legacy MongoDB ObjectId (24 hex символа)
|
||||
*/
|
||||
private isLegacyMongoId(id: string): boolean {
|
||||
return /^[a-f\d]{24}$/i.test(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверяет, является ли строка валидным UUID (с дефисами или без)
|
||||
*/
|
||||
private isValidUuid(id: string): boolean {
|
||||
// UUID с дефисами: 8-4-4-4-12
|
||||
const uuidWithDashes = /^[a-f\d]{8}-[a-f\d]{4}-[a-f\d]{4}-[a-f\d]{4}-[a-f\d]{12}$/i;
|
||||
// UUID без дефисов: 32 символа
|
||||
const uuidWithoutDashes = /^[a-f\d]{32}$/i;
|
||||
|
||||
return uuidWithDashes.test(id) || uuidWithoutDashes.test(id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import { UserRepository } from '~/domain/user/repositories/user.repository';
|
||||
import { UserDomainService } from '~/domain/user/services/user-domain.service';
|
||||
|
||||
/**
|
||||
* Резолвит пользователя по `sub` из JWT — единый источник для passport-стратегии
|
||||
* (HTTP) и резолвера подписки (WebSocket). `sub` может быть legacy Mongo ObjectId
|
||||
* (24 hex) либо UUID; формат определяет, в какой источник идти.
|
||||
*/
|
||||
export async function resolveUserBySub(
|
||||
sub: string,
|
||||
userRepository: UserRepository,
|
||||
userDomainService: UserDomainService
|
||||
) {
|
||||
if (isLegacyMongoId(sub)) {
|
||||
return userDomainService.getUserByLegacyMongoId(sub);
|
||||
}
|
||||
if (isValidUuid(sub)) {
|
||||
const user = await userRepository.findById(sub);
|
||||
if (!user) {
|
||||
throw new Error('Пользователь с указанным JWT не найден');
|
||||
}
|
||||
return user;
|
||||
}
|
||||
throw new Error('Неверный формат ID пользователя в JWT токене');
|
||||
}
|
||||
|
||||
function isLegacyMongoId(id: string): boolean {
|
||||
return /^[a-f\d]{24}$/i.test(id);
|
||||
}
|
||||
|
||||
function isValidUuid(id: string): boolean {
|
||||
const uuidWithDashes = /^[a-f\d]{8}-[a-f\d]{4}-[a-f\d]{4}-[a-f\d]{4}-[a-f\d]{12}$/i;
|
||||
const uuidWithoutDashes = /^[a-f\d]{32}$/i;
|
||||
return uuidWithDashes.test(id) || uuidWithoutDashes.test(id);
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
import { createUnionType, Field, ObjectType } from '@nestjs/graphql';
|
||||
|
||||
/**
|
||||
* Дискриминатор полезной нагрузки realtime-события marketplace.
|
||||
*
|
||||
* Поле служебное — НЕ публикуется как @Field; используется только в
|
||||
* resolveType union'а, чтобы выбрать конкретный тип на проводе. Издатель
|
||||
* (bridge) проставляет его в публикуемый объект.
|
||||
*/
|
||||
export enum MarketplaceEventType {
|
||||
ORDER_READY_TO_RECEIVE = 'ORDER_READY_TO_RECEIVE',
|
||||
RECEPTION_PENDING_SIGN = 'RECEPTION_PENDING_SIGN',
|
||||
}
|
||||
|
||||
@ObjectType('MarketplaceOrderReadyToReceiveEvent', {
|
||||
description: 'Заказ пайщика собран на пункте и ожидает его подписи получения.',
|
||||
})
|
||||
export class MarketplaceOrderReadyToReceiveEventDTO {
|
||||
eventType!: MarketplaceEventType.ORDER_READY_TO_RECEIVE;
|
||||
|
||||
@Field(() => String, { description: 'Идентификатор заказа.' })
|
||||
order_id!: string;
|
||||
|
||||
@Field(() => String, { description: 'Контрольная сумма заказа.' })
|
||||
order_hash!: string;
|
||||
|
||||
@Field(() => String, { description: 'Пункт выдачи, где заказ готов к получению.' })
|
||||
braname!: string;
|
||||
}
|
||||
|
||||
@ObjectType('MarketplaceReceptionPendingSignEvent', {
|
||||
description: 'Поставка ожидает подписи поставщика на пункте приёмки.',
|
||||
})
|
||||
export class MarketplaceReceptionPendingSignEventDTO {
|
||||
eventType!: MarketplaceEventType.RECEPTION_PENDING_SIGN;
|
||||
|
||||
@Field(() => String, { description: 'Идентификатор приёмки.' })
|
||||
reception_id!: string;
|
||||
|
||||
@Field(() => String, { description: 'Наименование кооперативного участка приёмки.' })
|
||||
ku_name!: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Объединение всех типов realtime-событий персонального канала пайщика.
|
||||
*
|
||||
* Принцип «сигнал, а не данные»: payload несёт только идентификаторы +
|
||||
* минимальный контекст, чтобы клиент понял «что обновить». Полные данные
|
||||
* (состав, цены, персональное) клиент дочитывает авторизованным query.
|
||||
* Поэтому даже при ошибке маршрутизации приватного в канал не утекает.
|
||||
*/
|
||||
export const MarketplaceEventUnion = createUnionType({
|
||||
name: 'MarketplaceEvent',
|
||||
types: () =>
|
||||
[MarketplaceOrderReadyToReceiveEventDTO, MarketplaceReceptionPendingSignEventDTO] as const,
|
||||
resolveType(value: { eventType?: MarketplaceEventType }) {
|
||||
switch (value.eventType) {
|
||||
case MarketplaceEventType.ORDER_READY_TO_RECEIVE:
|
||||
return MarketplaceOrderReadyToReceiveEventDTO;
|
||||
case MarketplaceEventType.RECEPTION_PENDING_SIGN:
|
||||
return MarketplaceReceptionPendingSignEventDTO;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
export type MarketplaceEventPayload =
|
||||
| MarketplaceOrderReadyToReceiveEventDTO
|
||||
| MarketplaceReceptionPendingSignEventDTO;
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
import { Field, InputType } from '@nestjs/graphql';
|
||||
|
||||
/**
|
||||
* Параметры подписки на персональный канал событий пайщика.
|
||||
*
|
||||
* `coopname` принимается для симметрии с query/mutation и сверяется сервером
|
||||
* с собственным кооперативом. Адресация канала строится из имени аккаунта
|
||||
* JWT, НЕ из этого поля — подменить чужой поток через аргумент нельзя.
|
||||
*/
|
||||
@InputType('MarketplaceEventsInput')
|
||||
export class MarketplaceEventsInputDTO {
|
||||
@Field(() => String, { description: 'Кооперативное имя.' })
|
||||
coopname!: string;
|
||||
}
|
||||
+10
@@ -136,6 +136,10 @@ import {
|
||||
MarketplaceCheckoutService,
|
||||
MARKETPLACE_CHECKOUT_SERVICE,
|
||||
} from './services/marketplace-checkout.service';
|
||||
// Фаза 2: realtime-подписка marketplace (GraphQL subscription поверх graphql-ws).
|
||||
import { PubSubModule } from '~/infrastructure/pubsub/pubsub.module';
|
||||
import { MarketplaceEventsResolver } from './resolvers/marketplace-events.resolver';
|
||||
import { MarketplaceRealtimeBridge } from './realtime/marketplace-realtime.bridge';
|
||||
|
||||
/**
|
||||
* Модуль приложения marketplace
|
||||
@@ -176,6 +180,8 @@ import {
|
||||
]),
|
||||
// Эпик 8: writeoff cron сканер должен видеть marketplace_inventory
|
||||
TypeOrmModule.forFeature([MarketplaceInventoryEntity], 'marketplace'),
|
||||
// Фаза 2: общий PubSub (@Global) для realtime-канала событий пайщика.
|
||||
PubSubModule,
|
||||
// ExtensionDomainService инжектится @Optional() в MarketplaceWriteoffCronService —
|
||||
// импортировать ExtensionDomainModule сюда нельзя (цикл AppModule → ExtensionDomainModule →
|
||||
// ExtensionsModule → MarketplacePluginModule → MarketplaceExtensionApplicationModule).
|
||||
@@ -207,6 +213,10 @@ import {
|
||||
MarketplaceReturnClaimResolver,
|
||||
// Эпик 16 — корзина заказчика
|
||||
MarketplaceCartResolver,
|
||||
// Фаза 2 — realtime-подписка персонального канала пайщика + мост из
|
||||
// доменных событий (EventEmitter2) в PubSub.
|
||||
MarketplaceEventsResolver,
|
||||
MarketplaceRealtimeBridge,
|
||||
|
||||
// Guards (Story 1.3 / Story 1.6)
|
||||
MarketplaceMembershipGuard,
|
||||
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { OnEvent } from '@nestjs/event-emitter';
|
||||
import { PubSub } from 'graphql-subscriptions';
|
||||
import { PUB_SUB } from '~/infrastructure/pubsub/pubsub.module';
|
||||
import {
|
||||
MARKETPLACE_APL_SUPPLIER_SIGN_REQUEST_EVENT,
|
||||
MARKETPLACE_ORDER_READY_TO_RECEIVE_EVENT,
|
||||
MarketplaceAplSupplierSignRequestEvent,
|
||||
MarketplaceOrderReadyToReceiveEvent,
|
||||
} from '../events/marketplace-notification.events';
|
||||
import {
|
||||
MarketplaceEventType,
|
||||
MarketplaceOrderReadyToReceiveEventDTO,
|
||||
MarketplaceReceptionPendingSignEventDTO,
|
||||
} from '../dto/marketplace-event.dto';
|
||||
import { marketplaceMemberTopic } from './marketplace-realtime.topics';
|
||||
|
||||
/**
|
||||
* Мост: внутренние доменные события marketplace (EventEmitter2, эмитятся ПОСЛЕ
|
||||
* commit'а в PG — INV-12) → персональный realtime-канал адресата через PubSub.
|
||||
*
|
||||
* Маршрутизация по получателю — гарантия приватности: публикуем в топик
|
||||
* конкретного аккаунта-адресата (orderer/supplier), а не в общий канал.
|
||||
* Payload — только сигнал (идентификаторы + контекст), детали клиент
|
||||
* дочитывает авторизованным query.
|
||||
*/
|
||||
@Injectable()
|
||||
export class MarketplaceRealtimeBridge {
|
||||
constructor(@Inject(PUB_SUB) private readonly pubSub: PubSub) {}
|
||||
|
||||
@OnEvent(MARKETPLACE_ORDER_READY_TO_RECEIVE_EVENT)
|
||||
async onOrderReadyToReceive(event: MarketplaceOrderReadyToReceiveEvent): Promise<void> {
|
||||
const payload: MarketplaceOrderReadyToReceiveEventDTO = {
|
||||
eventType: MarketplaceEventType.ORDER_READY_TO_RECEIVE,
|
||||
order_id: event.order_id,
|
||||
order_hash: event.order_hash,
|
||||
braname: event.braname,
|
||||
};
|
||||
await this.pubSub.publish(
|
||||
marketplaceMemberTopic(event.coopname, event.orderer_account),
|
||||
payload
|
||||
);
|
||||
}
|
||||
|
||||
@OnEvent(MARKETPLACE_APL_SUPPLIER_SIGN_REQUEST_EVENT)
|
||||
async onSupplierSignRequest(event: MarketplaceAplSupplierSignRequestEvent): Promise<void> {
|
||||
const payload: MarketplaceReceptionPendingSignEventDTO = {
|
||||
eventType: MarketplaceEventType.RECEPTION_PENDING_SIGN,
|
||||
reception_id: event.apl_reception_id,
|
||||
ku_name: event.ku_name,
|
||||
};
|
||||
await this.pubSub.publish(
|
||||
marketplaceMemberTopic(event.coopname, event.supplier_account),
|
||||
payload
|
||||
);
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Имя PubSub-топика персонального канала событий пайщика.
|
||||
*
|
||||
* Инвариант приватности: события публикуются и читаются ТОЛЬКО по топику
|
||||
* конкретного получателя. Подписчик строит топик из имени аккаунта своего
|
||||
* JWT (не из аргументов запроса), издатель (bridge) — из аккаунта-адресата
|
||||
* доменного события. Поэтому событие физически не попадает в канал чужого
|
||||
* пайщика. См. OQ-T15 (per-cooperative scope) — здесь усилено до per-member.
|
||||
*/
|
||||
export function marketplaceMemberTopic(coopname: string, username: string): string {
|
||||
return `marketplace:events:${coopname}:${username}`;
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
import { ForbiddenException, Inject, Injectable } from '@nestjs/common';
|
||||
import { Args, Resolver, Subscription } from '@nestjs/graphql';
|
||||
import { PubSub } from 'graphql-subscriptions';
|
||||
import config from '~/config/config';
|
||||
import { CurrentUser } from '~/application/auth/decorators/current-user.decorator';
|
||||
import { USER_REPOSITORY, UserRepository } from '~/domain/user/repositories/user.repository';
|
||||
import { UserDomainService, USER_DOMAIN_SERVICE } from '~/domain/user/services/user-domain.service';
|
||||
import { resolveUserBySub } from '~/application/auth/utils/resolve-user-by-sub';
|
||||
import { PUB_SUB } from '~/infrastructure/pubsub/pubsub.module';
|
||||
import {
|
||||
MarketplaceEventPayload,
|
||||
MarketplaceEventUnion,
|
||||
} from '../dto/marketplace-event.dto';
|
||||
import { MarketplaceEventsInputDTO } from '../dto/marketplace-events-input.dto';
|
||||
import { marketplaceMemberTopic } from '../realtime/marketplace-realtime.topics';
|
||||
|
||||
/**
|
||||
* Единственная подписка приложения marketplace: персональный поток событий
|
||||
* пайщика. Аутентификация соединения — в graphql-ws `onConnect` (см.
|
||||
* graphql.module.ts), который кладёт `sub` JWT в контекст; здесь по `sub`
|
||||
* резолвится имя аккаунта и строится приватный топик. Клиент НЕ может задать
|
||||
* чужой топик — он выводится из токена, аргумент `input.coopname` лишь
|
||||
* сверяется с кооперативом инстанса.
|
||||
*/
|
||||
@Resolver()
|
||||
@Injectable()
|
||||
export class MarketplaceEventsResolver {
|
||||
constructor(
|
||||
@Inject(PUB_SUB) private readonly pubSub: PubSub,
|
||||
@Inject(USER_REPOSITORY) private readonly userRepository: UserRepository,
|
||||
@Inject(USER_DOMAIN_SERVICE) private readonly userDomainService: UserDomainService
|
||||
) {}
|
||||
|
||||
@Subscription(() => MarketplaceEventUnion, {
|
||||
name: 'marketplaceEvents',
|
||||
description: 'Персональный поток событий пайщика в Столе заказов.',
|
||||
resolve: (payload: MarketplaceEventPayload) => payload,
|
||||
})
|
||||
async marketplaceEvents(
|
||||
@CurrentUser() user: { sub?: string; username?: string },
|
||||
@Args('input') input: MarketplaceEventsInputDTO
|
||||
): Promise<AsyncIterator<MarketplaceEventPayload>> {
|
||||
if (input.coopname !== config.coopname) {
|
||||
throw new ForbiddenException('Подписка доступна только в рамках своего кооператива.');
|
||||
}
|
||||
|
||||
const username = user.username ?? (await this.resolveUsername(user.sub));
|
||||
const topic = marketplaceMemberTopic(config.coopname, username);
|
||||
return this.pubSub.asyncIterator<MarketplaceEventPayload>(topic);
|
||||
}
|
||||
|
||||
private async resolveUsername(sub: string | undefined): Promise<string> {
|
||||
if (!sub) {
|
||||
throw new ForbiddenException('Не удалось определить пайщика из токена подписки.');
|
||||
}
|
||||
const account = await resolveUserBySub(sub, this.userRepository, this.userDomainService);
|
||||
return account.username;
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,18 @@ import { docDirectiveTransformer } from './directives/doc.directive';
|
||||
import { GraphQLError, GraphQLFormattedError } from 'graphql';
|
||||
import { fieldAuthDirectiveTransformer } from './directives/fieldAuth.directive';
|
||||
import logger from '~/config/logger';
|
||||
import * as jwt from 'jsonwebtoken';
|
||||
import { tokenTypes } from '~/types/token.types';
|
||||
|
||||
/**
|
||||
* Bearer-токен из connectionParams ws-соединения. Принимаем и сам токен, и
|
||||
* форму `Bearer <token>` — клиенты Zeus шлют по-разному.
|
||||
*/
|
||||
function extractBearerToken(raw: unknown): string | null {
|
||||
if (typeof raw !== 'string' || !raw) return null;
|
||||
const match = raw.match(/^Bearer\s+(.+)$/i);
|
||||
return match ? match[1] : raw;
|
||||
}
|
||||
|
||||
@Global()
|
||||
@Module({
|
||||
@@ -20,6 +32,39 @@ import logger from '~/config/logger';
|
||||
// context: ({ req }) => req,
|
||||
playground: { endpoint: '/v1/graphql', settings: { 'request.credentials': 'same-origin' } },
|
||||
path: '/v1/graphql', // здесь можно задать другой путь, когда потребуется,
|
||||
// Realtime-подписки поверх graphql-ws на том же пути. Аутентификация
|
||||
// соединения — однократно в onConnect: верифицируем access-JWT из
|
||||
// connectionParams и кладём `sub` в `extra`, чтобы операции читали юзера
|
||||
// из контекста. Невалидный/отсутствующий токен → соединение отклоняется.
|
||||
subscriptions: {
|
||||
'graphql-ws': {
|
||||
path: '/v1/graphql',
|
||||
onConnect: (context: any) => {
|
||||
const params = context?.connectionParams ?? {};
|
||||
const token = extractBearerToken(params.authorization ?? params.Authorization);
|
||||
if (!token) return false;
|
||||
try {
|
||||
const payload: any = jwt.verify(token, config.jwt.secret);
|
||||
if (payload?.type !== tokenTypes.ACCESS) return false;
|
||||
context.extra = context.extra ?? {};
|
||||
context.extra.user = { sub: payload.sub };
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
// Единый context для HTTP и WS. Для ws (graphql-ws Context содержит
|
||||
// `extra`) прокидываем аутентифицированного юзера в req.user, чтобы
|
||||
// существующие @CurrentUser/декораторы работали без изменений. Для HTTP
|
||||
// возвращаем { req, res } как есть.
|
||||
context: (ctx: any) => {
|
||||
if (ctx && typeof ctx === 'object' && 'extra' in ctx) {
|
||||
return { req: { user: ctx.extra?.user ?? null, headers: {} } };
|
||||
}
|
||||
return ctx;
|
||||
},
|
||||
transformSchema: (schema) => {
|
||||
schema = docDirectiveTransformer(schema, 'auth');
|
||||
schema = fieldAuthDirectiveTransformer(schema, 'auth');
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import { Global, Module } from '@nestjs/common';
|
||||
import { PubSub } from 'graphql-subscriptions';
|
||||
|
||||
/**
|
||||
* DI-токен единственного in-memory PubSub приложения.
|
||||
*
|
||||
* Why in-memory (не graphql-redis-subscriptions): один controller обслуживает
|
||||
* один кооператив (config.coopname) одним процессом — горизонтального шардинга
|
||||
* подписчиков по нескольким инстансам в MVP нет, поэтому межпроцессный брокер
|
||||
* избыточен. При переходе на multi-instance замена — только эта фабрика
|
||||
* (RedisPubSub с тем же интерфейсом asyncIterator/publish), потребители не
|
||||
* меняются.
|
||||
*/
|
||||
export const PUB_SUB = Symbol('PUB_SUB');
|
||||
|
||||
@Global()
|
||||
@Module({
|
||||
providers: [
|
||||
{
|
||||
provide: PUB_SUB,
|
||||
useFactory: () => new PubSub(),
|
||||
},
|
||||
],
|
||||
exports: [PUB_SUB],
|
||||
})
|
||||
export class PubSubModule {}
|
||||
@@ -718,6 +718,9 @@ export const AllTypesProps: Record<string,any> = {
|
||||
},
|
||||
MarketplaceDetailKUInput:{
|
||||
workingHours:"WorkingHoursInput"
|
||||
},
|
||||
MarketplaceEventsInput:{
|
||||
|
||||
},
|
||||
MarketplaceFinalizeIssuanceInput:{
|
||||
signed_document:"MarketplaceIssueActSignedDocumentInput"
|
||||
@@ -2352,6 +2355,11 @@ export const AllTypesProps: Record<string,any> = {
|
||||
SubmitVoteInput:{
|
||||
votes:"VoteDistributionInput"
|
||||
},
|
||||
Subscription:{
|
||||
marketplaceEvents:{
|
||||
input:"MarketplaceEventsInput"
|
||||
}
|
||||
},
|
||||
SystemStatus: "enum" as const,
|
||||
TranscriptionStatus: "enum" as const,
|
||||
TriggerNotificationWorkflowInput:{
|
||||
@@ -4166,6 +4174,10 @@ export const ReturnTypes: Record<string,any> = {
|
||||
picture:"String",
|
||||
value:"String"
|
||||
},
|
||||
MarketplaceEvent:{
|
||||
"...on MarketplaceOrderReadyToReceiveEvent":"MarketplaceOrderReadyToReceiveEvent",
|
||||
"...on MarketplaceReceptionPendingSignEvent":"MarketplaceReceptionPendingSignEvent"
|
||||
},
|
||||
MarketplaceExpressPickupCandidate:{
|
||||
braname:"String",
|
||||
offerer_account:"String",
|
||||
@@ -4356,6 +4368,11 @@ export const ReturnTypes: Record<string,any> = {
|
||||
totalCount:"Int",
|
||||
totalPages:"Int"
|
||||
},
|
||||
MarketplaceOrderReadyToReceiveEvent:{
|
||||
braname:"String",
|
||||
order_hash:"String",
|
||||
order_id:"String"
|
||||
},
|
||||
MarketplaceOutgoingPaymentRequest:{
|
||||
amount:"String",
|
||||
apl_reception_id:"ID",
|
||||
@@ -4382,6 +4399,10 @@ export const ReturnTypes: Record<string,any> = {
|
||||
typeId:"Int",
|
||||
typeName:"String"
|
||||
},
|
||||
MarketplaceReceptionPendingSignEvent:{
|
||||
ku_name:"String",
|
||||
reception_id:"String"
|
||||
},
|
||||
MarketplaceRegistrationOfferStatus:{
|
||||
agreement_id:"String",
|
||||
agreement_type:"String",
|
||||
@@ -5792,6 +5813,9 @@ export const ReturnTypes: Record<string,any> = {
|
||||
action:"ExtendedBlockchainAction",
|
||||
documentAggregate:"DocumentAggregate"
|
||||
},
|
||||
Subscription:{
|
||||
marketplaceEvents:"MarketplaceEvent"
|
||||
},
|
||||
SubscriptionStatsDto:{
|
||||
active:"Int",
|
||||
inactive:"Int",
|
||||
@@ -5963,5 +5987,6 @@ export const ReturnTypes: Record<string,any> = {
|
||||
|
||||
export const Ops = {
|
||||
query: "Query" as const,
|
||||
mutation: "Mutation" as const
|
||||
mutation: "Mutation" as const,
|
||||
subscription: "Subscription" as const
|
||||
}
|
||||
@@ -1104,7 +1104,7 @@ export type ScalarCoders = {
|
||||
JSONObject?: ScalarResolver;
|
||||
ID?: ScalarResolver;
|
||||
}
|
||||
type ZEUS_UNIONS = GraphQLTypes["PaymentMethodData"] | GraphQLTypes["PrivateAccountSearchData"] | GraphQLTypes["UserCertificateUnion"]
|
||||
type ZEUS_UNIONS = GraphQLTypes["MarketplaceEvent"] | GraphQLTypes["PaymentMethodData"] | GraphQLTypes["PrivateAccountSearchData"] | GraphQLTypes["UserCertificateUnion"]
|
||||
|
||||
export type ValueTypes = {
|
||||
["Account"]: AliasType<{
|
||||
@@ -6750,6 +6750,14 @@ export type ValueTypes = {
|
||||
__typename?: boolean | `@${string}`,
|
||||
['...on MarketplaceDictionaryValue']?: Omit<ValueTypes["MarketplaceDictionaryValue"], "...on MarketplaceDictionaryValue">
|
||||
}>;
|
||||
["MarketplaceEvent"]: AliasType<{ ["...on MarketplaceOrderReadyToReceiveEvent"]?: ValueTypes["MarketplaceOrderReadyToReceiveEvent"],
|
||||
["...on MarketplaceReceptionPendingSignEvent"]?: ValueTypes["MarketplaceReceptionPendingSignEvent"]
|
||||
__typename?: boolean | `@${string}`
|
||||
}>;
|
||||
["MarketplaceEventsInput"]: {
|
||||
/** Кооперативное имя. */
|
||||
coopname: string | Variable<any, string>
|
||||
};
|
||||
["MarketplaceExpressPickupCandidate"]: AliasType<{
|
||||
/** КУ-получатель. */
|
||||
braname?:boolean | `@${string}`,
|
||||
@@ -7337,6 +7345,17 @@ export type ValueTypes = {
|
||||
totalPages?:boolean | `@${string}`,
|
||||
__typename?: boolean | `@${string}`,
|
||||
['...on MarketplaceOrderPaginationResult']?: Omit<ValueTypes["MarketplaceOrderPaginationResult"], "...on MarketplaceOrderPaginationResult">
|
||||
}>;
|
||||
/** Заказ пайщика собран на пункте и ожидает его подписи получения. */
|
||||
["MarketplaceOrderReadyToReceiveEvent"]: AliasType<{
|
||||
/** Пункт выдачи, где заказ готов к получению. */
|
||||
braname?:boolean | `@${string}`,
|
||||
/** Контрольная сумма заказа. */
|
||||
order_hash?:boolean | `@${string}`,
|
||||
/** Идентификатор заказа. */
|
||||
order_id?:boolean | `@${string}`,
|
||||
__typename?: boolean | `@${string}`,
|
||||
['...on MarketplaceOrderReadyToReceiveEvent']?: Omit<ValueTypes["MarketplaceOrderReadyToReceiveEvent"], "...on MarketplaceOrderReadyToReceiveEvent">
|
||||
}>;
|
||||
/** Этап жизненного цикла заказа. */
|
||||
["MarketplaceOrderStatus"]:MarketplaceOrderStatus;
|
||||
@@ -7387,6 +7406,15 @@ export type ValueTypes = {
|
||||
typeName?:boolean | `@${string}`,
|
||||
__typename?: boolean | `@${string}`,
|
||||
['...on MarketplaceProductType']?: Omit<ValueTypes["MarketplaceProductType"], "...on MarketplaceProductType">
|
||||
}>;
|
||||
/** Поставка ожидает подписи поставщика на пункте приёмки. */
|
||||
["MarketplaceReceptionPendingSignEvent"]: AliasType<{
|
||||
/** Наименование кооперативного участка приёмки. */
|
||||
ku_name?:boolean | `@${string}`,
|
||||
/** Идентификатор приёмки. */
|
||||
reception_id?:boolean | `@${string}`,
|
||||
__typename?: boolean | `@${string}`,
|
||||
['...on MarketplaceReceptionPendingSignEvent']?: Omit<ValueTypes["MarketplaceReceptionPendingSignEvent"], "...on MarketplaceReceptionPendingSignEvent">
|
||||
}>;
|
||||
["MarketplaceRegistrationOfferStatus"]: AliasType<{
|
||||
/** AGREEMENT_ID (например `marketplace_offer`) */
|
||||
@@ -10921,6 +10949,11 @@ validateReportEdits?: [{ editsJson: string | Variable<any, string>, reportType:
|
||||
/** Распределение голосов */
|
||||
votes: Array<ValueTypes["VoteDistributionInput"]> | Variable<any, string>
|
||||
};
|
||||
["Subscription"]: AliasType<{
|
||||
marketplaceEvents?: [{ input: ValueTypes["MarketplaceEventsInput"] | Variable<any, string>},ValueTypes["MarketplaceEvent"]],
|
||||
__typename?: boolean | `@${string}`,
|
||||
['...on Subscription']?: Omit<ValueTypes["Subscription"], "...on Subscription">
|
||||
}>;
|
||||
["SubscriptionStatsDto"]: AliasType<{
|
||||
/** Количество активных подписок */
|
||||
active?:boolean | `@${string}`,
|
||||
@@ -17014,6 +17047,15 @@ export type ResolverInputTypes = {
|
||||
value?:boolean | `@${string}`,
|
||||
__typename?: boolean | `@${string}`
|
||||
}>;
|
||||
["MarketplaceEvent"]: AliasType<{
|
||||
MarketplaceOrderReadyToReceiveEvent?:ResolverInputTypes["MarketplaceOrderReadyToReceiveEvent"],
|
||||
MarketplaceReceptionPendingSignEvent?:ResolverInputTypes["MarketplaceReceptionPendingSignEvent"],
|
||||
__typename?: boolean | `@${string}`
|
||||
}>;
|
||||
["MarketplaceEventsInput"]: {
|
||||
/** Кооперативное имя. */
|
||||
coopname: string
|
||||
};
|
||||
["MarketplaceExpressPickupCandidate"]: AliasType<{
|
||||
/** КУ-получатель. */
|
||||
braname?:boolean | `@${string}`,
|
||||
@@ -17585,6 +17627,16 @@ export type ResolverInputTypes = {
|
||||
/** Общее количество страниц */
|
||||
totalPages?:boolean | `@${string}`,
|
||||
__typename?: boolean | `@${string}`
|
||||
}>;
|
||||
/** Заказ пайщика собран на пункте и ожидает его подписи получения. */
|
||||
["MarketplaceOrderReadyToReceiveEvent"]: AliasType<{
|
||||
/** Пункт выдачи, где заказ готов к получению. */
|
||||
braname?:boolean | `@${string}`,
|
||||
/** Контрольная сумма заказа. */
|
||||
order_hash?:boolean | `@${string}`,
|
||||
/** Идентификатор заказа. */
|
||||
order_id?:boolean | `@${string}`,
|
||||
__typename?: boolean | `@${string}`
|
||||
}>;
|
||||
/** Этап жизненного цикла заказа. */
|
||||
["MarketplaceOrderStatus"]:MarketplaceOrderStatus;
|
||||
@@ -17633,6 +17685,14 @@ export type ResolverInputTypes = {
|
||||
/** Название типа товара */
|
||||
typeName?:boolean | `@${string}`,
|
||||
__typename?: boolean | `@${string}`
|
||||
}>;
|
||||
/** Поставка ожидает подписи поставщика на пункте приёмки. */
|
||||
["MarketplaceReceptionPendingSignEvent"]: AliasType<{
|
||||
/** Наименование кооперативного участка приёмки. */
|
||||
ku_name?:boolean | `@${string}`,
|
||||
/** Идентификатор приёмки. */
|
||||
reception_id?:boolean | `@${string}`,
|
||||
__typename?: boolean | `@${string}`
|
||||
}>;
|
||||
["MarketplaceRegistrationOfferStatus"]: AliasType<{
|
||||
/** AGREEMENT_ID (например `marketplace_offer`) */
|
||||
@@ -21051,6 +21111,10 @@ validateReportEdits?: [{ editsJson: string, reportType: ResolverInputTypes["Repo
|
||||
/** Распределение голосов */
|
||||
votes: Array<ResolverInputTypes["VoteDistributionInput"]>
|
||||
};
|
||||
["Subscription"]: AliasType<{
|
||||
marketplaceEvents?: [{ input: ResolverInputTypes["MarketplaceEventsInput"]},ResolverInputTypes["MarketplaceEvent"]],
|
||||
__typename?: boolean | `@${string}`
|
||||
}>;
|
||||
["SubscriptionStatsDto"]: AliasType<{
|
||||
/** Количество активных подписок */
|
||||
active?:boolean | `@${string}`,
|
||||
@@ -21638,6 +21702,7 @@ validateReportEdits?: [{ editsJson: string, reportType: ResolverInputTypes["Repo
|
||||
["schema"]: AliasType<{
|
||||
query?:ResolverInputTypes["Query"],
|
||||
mutation?:ResolverInputTypes["Mutation"],
|
||||
subscription?:ResolverInputTypes["Subscription"],
|
||||
__typename?: boolean | `@${string}`
|
||||
}>;
|
||||
["ID"]:unknown
|
||||
@@ -26947,6 +27012,11 @@ export type ModelTypes = {
|
||||
picture?: string | undefined | null,
|
||||
/** Значение */
|
||||
value: string
|
||||
};
|
||||
["MarketplaceEvent"]:ModelTypes["MarketplaceOrderReadyToReceiveEvent"] | ModelTypes["MarketplaceReceptionPendingSignEvent"];
|
||||
["MarketplaceEventsInput"]: {
|
||||
/** Кооперативное имя. */
|
||||
coopname: string
|
||||
};
|
||||
["MarketplaceExpressPickupCandidate"]: {
|
||||
/** КУ-получатель. */
|
||||
@@ -27498,6 +27568,15 @@ export type ModelTypes = {
|
||||
totalCount: number,
|
||||
/** Общее количество страниц */
|
||||
totalPages: number
|
||||
};
|
||||
/** Заказ пайщика собран на пункте и ожидает его подписи получения. */
|
||||
["MarketplaceOrderReadyToReceiveEvent"]: {
|
||||
/** Пункт выдачи, где заказ готов к получению. */
|
||||
braname: string,
|
||||
/** Контрольная сумма заказа. */
|
||||
order_hash: string,
|
||||
/** Идентификатор заказа. */
|
||||
order_id: string
|
||||
};
|
||||
["MarketplaceOrderStatus"]:MarketplaceOrderStatus;
|
||||
["MarketplaceOutgoingPaymentRequest"]: {
|
||||
@@ -27542,6 +27621,13 @@ export type ModelTypes = {
|
||||
typeId: number,
|
||||
/** Название типа товара */
|
||||
typeName: string
|
||||
};
|
||||
/** Поставка ожидает подписи поставщика на пункте приёмки. */
|
||||
["MarketplaceReceptionPendingSignEvent"]: {
|
||||
/** Наименование кооперативного участка приёмки. */
|
||||
ku_name: string,
|
||||
/** Идентификатор приёмки. */
|
||||
reception_id: string
|
||||
};
|
||||
["MarketplaceRegistrationOfferStatus"]: {
|
||||
/** AGREEMENT_ID (например `marketplace_offer`) */
|
||||
@@ -31599,6 +31685,10 @@ export type ModelTypes = {
|
||||
project_hash: string,
|
||||
/** Распределение голосов */
|
||||
votes: Array<ModelTypes["VoteDistributionInput"]>
|
||||
};
|
||||
["Subscription"]: {
|
||||
/** Персональный поток событий пайщика в Столе заказов. */
|
||||
marketplaceEvents: ModelTypes["MarketplaceEvent"]
|
||||
};
|
||||
["SubscriptionStatsDto"]: {
|
||||
/** Количество активных подписок */
|
||||
@@ -32158,7 +32248,8 @@ export type ModelTypes = {
|
||||
["ZeroReportSignerType"]:ZeroReportSignerType;
|
||||
["schema"]: {
|
||||
query?: ModelTypes["Query"] | undefined | null,
|
||||
mutation?: ModelTypes["Mutation"] | undefined | null
|
||||
mutation?: ModelTypes["Mutation"] | undefined | null,
|
||||
subscription?: ModelTypes["Subscription"] | undefined | null
|
||||
};
|
||||
["ID"]:any
|
||||
}
|
||||
@@ -37809,6 +37900,15 @@ export type GraphQLTypes = {
|
||||
/** Значение */
|
||||
value: string,
|
||||
['...on MarketplaceDictionaryValue']: Omit<GraphQLTypes["MarketplaceDictionaryValue"], "...on MarketplaceDictionaryValue">
|
||||
};
|
||||
["MarketplaceEvent"]:{
|
||||
__typename:"MarketplaceOrderReadyToReceiveEvent" | "MarketplaceReceptionPendingSignEvent"
|
||||
['...on MarketplaceOrderReadyToReceiveEvent']: '__union' & GraphQLTypes["MarketplaceOrderReadyToReceiveEvent"];
|
||||
['...on MarketplaceReceptionPendingSignEvent']: '__union' & GraphQLTypes["MarketplaceReceptionPendingSignEvent"];
|
||||
};
|
||||
["MarketplaceEventsInput"]: {
|
||||
/** Кооперативное имя. */
|
||||
coopname: string
|
||||
};
|
||||
["MarketplaceExpressPickupCandidate"]: {
|
||||
__typename: "MarketplaceExpressPickupCandidate",
|
||||
@@ -38397,6 +38497,17 @@ export type GraphQLTypes = {
|
||||
/** Общее количество страниц */
|
||||
totalPages: number,
|
||||
['...on MarketplaceOrderPaginationResult']: Omit<GraphQLTypes["MarketplaceOrderPaginationResult"], "...on MarketplaceOrderPaginationResult">
|
||||
};
|
||||
/** Заказ пайщика собран на пункте и ожидает его подписи получения. */
|
||||
["MarketplaceOrderReadyToReceiveEvent"]: {
|
||||
__typename: "MarketplaceOrderReadyToReceiveEvent",
|
||||
/** Пункт выдачи, где заказ готов к получению. */
|
||||
braname: string,
|
||||
/** Контрольная сумма заказа. */
|
||||
order_hash: string,
|
||||
/** Идентификатор заказа. */
|
||||
order_id: string,
|
||||
['...on MarketplaceOrderReadyToReceiveEvent']: Omit<GraphQLTypes["MarketplaceOrderReadyToReceiveEvent"], "...on MarketplaceOrderReadyToReceiveEvent">
|
||||
};
|
||||
/** Этап жизненного цикла заказа. */
|
||||
["MarketplaceOrderStatus"]: MarketplaceOrderStatus;
|
||||
@@ -38447,6 +38558,15 @@ export type GraphQLTypes = {
|
||||
/** Название типа товара */
|
||||
typeName: string,
|
||||
['...on MarketplaceProductType']: Omit<GraphQLTypes["MarketplaceProductType"], "...on MarketplaceProductType">
|
||||
};
|
||||
/** Поставка ожидает подписи поставщика на пункте приёмки. */
|
||||
["MarketplaceReceptionPendingSignEvent"]: {
|
||||
__typename: "MarketplaceReceptionPendingSignEvent",
|
||||
/** Наименование кооперативного участка приёмки. */
|
||||
ku_name: string,
|
||||
/** Идентификатор приёмки. */
|
||||
reception_id: string,
|
||||
['...on MarketplaceReceptionPendingSignEvent']: Omit<GraphQLTypes["MarketplaceReceptionPendingSignEvent"], "...on MarketplaceReceptionPendingSignEvent">
|
||||
};
|
||||
["MarketplaceRegistrationOfferStatus"]: {
|
||||
__typename: "MarketplaceRegistrationOfferStatus",
|
||||
@@ -42774,6 +42894,12 @@ export type GraphQLTypes = {
|
||||
project_hash: string,
|
||||
/** Распределение голосов */
|
||||
votes: Array<GraphQLTypes["VoteDistributionInput"]>
|
||||
};
|
||||
["Subscription"]: {
|
||||
__typename: "Subscription",
|
||||
/** Персональный поток событий пайщика в Столе заказов. */
|
||||
marketplaceEvents: GraphQLTypes["MarketplaceEvent"],
|
||||
['...on Subscription']: Omit<GraphQLTypes["Subscription"], "...on Subscription">
|
||||
};
|
||||
["SubscriptionStatsDto"]: {
|
||||
__typename: "SubscriptionStatsDto",
|
||||
@@ -44208,6 +44334,7 @@ type ZEUS_VARIABLES = {
|
||||
["MarketplaceCreateWriteoffDraftInput"]: ValueTypes["MarketplaceCreateWriteoffDraftInput"];
|
||||
["MarketplaceDeclineOrdersBatchInput"]: ValueTypes["MarketplaceDeclineOrdersBatchInput"];
|
||||
["MarketplaceDetailKUInput"]: ValueTypes["MarketplaceDetailKUInput"];
|
||||
["MarketplaceEventsInput"]: ValueTypes["MarketplaceEventsInput"];
|
||||
["MarketplaceFinalizeIssuanceInput"]: ValueTypes["MarketplaceFinalizeIssuanceInput"];
|
||||
["MarketplaceGenerateInventoryLabelInput"]: ValueTypes["MarketplaceGenerateInventoryLabelInput"];
|
||||
["MarketplaceGeocodeStatus"]: ValueTypes["MarketplaceGeocodeStatus"];
|
||||
|
||||
@@ -11,6 +11,7 @@ import { ZeusScalars } from './zeus/index'
|
||||
export * as Classes from './classes'
|
||||
export * as Mutations from './mutations'
|
||||
export * as Queries from './queries'
|
||||
export * as Subscriptions from './subscriptions'
|
||||
export * as Selectors from './selectors'
|
||||
|
||||
export * as Types from './types'
|
||||
@@ -183,7 +184,12 @@ export class Client {
|
||||
* Подписка на GraphQL-события.
|
||||
*/
|
||||
public get Subscription() {
|
||||
return ZeusSubscription(this.options.api_url.replace(/^http/, 'ws'))
|
||||
// Прокидываем заголовки (в т.ч. Authorization) — Zeus кладёт их в
|
||||
// connectionParams ws-соединения, по которым сервер аутентифицирует
|
||||
// подписку в onConnect. Без этого канал был бы анонимным и отклонялся.
|
||||
return ZeusSubscription(this.options.api_url.replace(/^http/, 'ws'), {
|
||||
headers: this.currentHeaders,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export * as Marketplace from './marketplace'
|
||||
@@ -0,0 +1,2 @@
|
||||
/** Персональный realtime-канал событий пайщика в Столе заказов */
|
||||
export * as Events from './marketplaceEvents'
|
||||
@@ -0,0 +1,42 @@
|
||||
import { $, type GraphQLTypes, type InputType, type ModelTypes, Selector } from '../../zeus/index'
|
||||
|
||||
/**
|
||||
* Персональный realtime-канал событий пайщика в Столе заказов.
|
||||
*
|
||||
* Подписка несёт «сигнал» (идентификаторы + минимальный контекст), а не данные:
|
||||
* получив событие, клиент дочитывает детали авторизованным query. Сервер
|
||||
* адресует события по аккаунту из JWT соединения — чужое в канал не попадает.
|
||||
*
|
||||
* Union `MarketplaceEvent` дискриминируется по `__typename`; выбирай поля
|
||||
* нужного типа через `... on`.
|
||||
*/
|
||||
export const name = 'marketplaceEvents'
|
||||
|
||||
export const subscription = Selector('Subscription')({
|
||||
[name]: [
|
||||
{ input: $('input', 'MarketplaceEventsInput!') },
|
||||
{
|
||||
__typename: true,
|
||||
'...on MarketplaceOrderReadyToReceiveEvent': {
|
||||
order_id: true,
|
||||
order_hash: true,
|
||||
braname: true,
|
||||
},
|
||||
'...on MarketplaceReceptionPendingSignEvent': {
|
||||
reception_id: true,
|
||||
ku_name: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
export interface IInput {
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
[key: string]: unknown
|
||||
|
||||
input: ModelTypes['MarketplaceEventsInput']
|
||||
}
|
||||
|
||||
export type IOutput = InputType<GraphQLTypes['Subscription'], typeof subscription>
|
||||
@@ -718,6 +718,9 @@ export const AllTypesProps: Record<string,any> = {
|
||||
},
|
||||
MarketplaceDetailKUInput:{
|
||||
workingHours:"WorkingHoursInput"
|
||||
},
|
||||
MarketplaceEventsInput:{
|
||||
|
||||
},
|
||||
MarketplaceFinalizeIssuanceInput:{
|
||||
signed_document:"MarketplaceIssueActSignedDocumentInput"
|
||||
@@ -2352,6 +2355,11 @@ export const AllTypesProps: Record<string,any> = {
|
||||
SubmitVoteInput:{
|
||||
votes:"VoteDistributionInput"
|
||||
},
|
||||
Subscription:{
|
||||
marketplaceEvents:{
|
||||
input:"MarketplaceEventsInput"
|
||||
}
|
||||
},
|
||||
SystemStatus: "enum" as const,
|
||||
TranscriptionStatus: "enum" as const,
|
||||
TriggerNotificationWorkflowInput:{
|
||||
@@ -4166,6 +4174,10 @@ export const ReturnTypes: Record<string,any> = {
|
||||
picture:"String",
|
||||
value:"String"
|
||||
},
|
||||
MarketplaceEvent:{
|
||||
"...on MarketplaceOrderReadyToReceiveEvent":"MarketplaceOrderReadyToReceiveEvent",
|
||||
"...on MarketplaceReceptionPendingSignEvent":"MarketplaceReceptionPendingSignEvent"
|
||||
},
|
||||
MarketplaceExpressPickupCandidate:{
|
||||
braname:"String",
|
||||
offerer_account:"String",
|
||||
@@ -4356,6 +4368,11 @@ export const ReturnTypes: Record<string,any> = {
|
||||
totalCount:"Int",
|
||||
totalPages:"Int"
|
||||
},
|
||||
MarketplaceOrderReadyToReceiveEvent:{
|
||||
braname:"String",
|
||||
order_hash:"String",
|
||||
order_id:"String"
|
||||
},
|
||||
MarketplaceOutgoingPaymentRequest:{
|
||||
amount:"String",
|
||||
apl_reception_id:"ID",
|
||||
@@ -4382,6 +4399,10 @@ export const ReturnTypes: Record<string,any> = {
|
||||
typeId:"Int",
|
||||
typeName:"String"
|
||||
},
|
||||
MarketplaceReceptionPendingSignEvent:{
|
||||
ku_name:"String",
|
||||
reception_id:"String"
|
||||
},
|
||||
MarketplaceRegistrationOfferStatus:{
|
||||
agreement_id:"String",
|
||||
agreement_type:"String",
|
||||
@@ -5792,6 +5813,9 @@ export const ReturnTypes: Record<string,any> = {
|
||||
action:"ExtendedBlockchainAction",
|
||||
documentAggregate:"DocumentAggregate"
|
||||
},
|
||||
Subscription:{
|
||||
marketplaceEvents:"MarketplaceEvent"
|
||||
},
|
||||
SubscriptionStatsDto:{
|
||||
active:"Int",
|
||||
inactive:"Int",
|
||||
@@ -5963,5 +5987,6 @@ export const ReturnTypes: Record<string,any> = {
|
||||
|
||||
export const Ops = {
|
||||
query: "Query" as const,
|
||||
mutation: "Mutation" as const
|
||||
mutation: "Mutation" as const,
|
||||
subscription: "Subscription" as const
|
||||
}
|
||||
@@ -1104,7 +1104,7 @@ export type ScalarCoders = {
|
||||
JSONObject?: ScalarResolver;
|
||||
ID?: ScalarResolver;
|
||||
}
|
||||
type ZEUS_UNIONS = GraphQLTypes["PaymentMethodData"] | GraphQLTypes["PrivateAccountSearchData"] | GraphQLTypes["UserCertificateUnion"]
|
||||
type ZEUS_UNIONS = GraphQLTypes["MarketplaceEvent"] | GraphQLTypes["PaymentMethodData"] | GraphQLTypes["PrivateAccountSearchData"] | GraphQLTypes["UserCertificateUnion"]
|
||||
|
||||
export type ValueTypes = {
|
||||
["Account"]: AliasType<{
|
||||
@@ -6750,6 +6750,14 @@ export type ValueTypes = {
|
||||
__typename?: boolean | `@${string}`,
|
||||
['...on MarketplaceDictionaryValue']?: Omit<ValueTypes["MarketplaceDictionaryValue"], "...on MarketplaceDictionaryValue">
|
||||
}>;
|
||||
["MarketplaceEvent"]: AliasType<{ ["...on MarketplaceOrderReadyToReceiveEvent"]?: ValueTypes["MarketplaceOrderReadyToReceiveEvent"],
|
||||
["...on MarketplaceReceptionPendingSignEvent"]?: ValueTypes["MarketplaceReceptionPendingSignEvent"]
|
||||
__typename?: boolean | `@${string}`
|
||||
}>;
|
||||
["MarketplaceEventsInput"]: {
|
||||
/** Кооперативное имя. */
|
||||
coopname: string | Variable<any, string>
|
||||
};
|
||||
["MarketplaceExpressPickupCandidate"]: AliasType<{
|
||||
/** КУ-получатель. */
|
||||
braname?:boolean | `@${string}`,
|
||||
@@ -7337,6 +7345,17 @@ export type ValueTypes = {
|
||||
totalPages?:boolean | `@${string}`,
|
||||
__typename?: boolean | `@${string}`,
|
||||
['...on MarketplaceOrderPaginationResult']?: Omit<ValueTypes["MarketplaceOrderPaginationResult"], "...on MarketplaceOrderPaginationResult">
|
||||
}>;
|
||||
/** Заказ пайщика собран на пункте и ожидает его подписи получения. */
|
||||
["MarketplaceOrderReadyToReceiveEvent"]: AliasType<{
|
||||
/** Пункт выдачи, где заказ готов к получению. */
|
||||
braname?:boolean | `@${string}`,
|
||||
/** Контрольная сумма заказа. */
|
||||
order_hash?:boolean | `@${string}`,
|
||||
/** Идентификатор заказа. */
|
||||
order_id?:boolean | `@${string}`,
|
||||
__typename?: boolean | `@${string}`,
|
||||
['...on MarketplaceOrderReadyToReceiveEvent']?: Omit<ValueTypes["MarketplaceOrderReadyToReceiveEvent"], "...on MarketplaceOrderReadyToReceiveEvent">
|
||||
}>;
|
||||
/** Этап жизненного цикла заказа. */
|
||||
["MarketplaceOrderStatus"]:MarketplaceOrderStatus;
|
||||
@@ -7387,6 +7406,15 @@ export type ValueTypes = {
|
||||
typeName?:boolean | `@${string}`,
|
||||
__typename?: boolean | `@${string}`,
|
||||
['...on MarketplaceProductType']?: Omit<ValueTypes["MarketplaceProductType"], "...on MarketplaceProductType">
|
||||
}>;
|
||||
/** Поставка ожидает подписи поставщика на пункте приёмки. */
|
||||
["MarketplaceReceptionPendingSignEvent"]: AliasType<{
|
||||
/** Наименование кооперативного участка приёмки. */
|
||||
ku_name?:boolean | `@${string}`,
|
||||
/** Идентификатор приёмки. */
|
||||
reception_id?:boolean | `@${string}`,
|
||||
__typename?: boolean | `@${string}`,
|
||||
['...on MarketplaceReceptionPendingSignEvent']?: Omit<ValueTypes["MarketplaceReceptionPendingSignEvent"], "...on MarketplaceReceptionPendingSignEvent">
|
||||
}>;
|
||||
["MarketplaceRegistrationOfferStatus"]: AliasType<{
|
||||
/** AGREEMENT_ID (например `marketplace_offer`) */
|
||||
@@ -10921,6 +10949,11 @@ validateReportEdits?: [{ editsJson: string | Variable<any, string>, reportType:
|
||||
/** Распределение голосов */
|
||||
votes: Array<ValueTypes["VoteDistributionInput"]> | Variable<any, string>
|
||||
};
|
||||
["Subscription"]: AliasType<{
|
||||
marketplaceEvents?: [{ input: ValueTypes["MarketplaceEventsInput"] | Variable<any, string>},ValueTypes["MarketplaceEvent"]],
|
||||
__typename?: boolean | `@${string}`,
|
||||
['...on Subscription']?: Omit<ValueTypes["Subscription"], "...on Subscription">
|
||||
}>;
|
||||
["SubscriptionStatsDto"]: AliasType<{
|
||||
/** Количество активных подписок */
|
||||
active?:boolean | `@${string}`,
|
||||
@@ -17014,6 +17047,15 @@ export type ResolverInputTypes = {
|
||||
value?:boolean | `@${string}`,
|
||||
__typename?: boolean | `@${string}`
|
||||
}>;
|
||||
["MarketplaceEvent"]: AliasType<{
|
||||
MarketplaceOrderReadyToReceiveEvent?:ResolverInputTypes["MarketplaceOrderReadyToReceiveEvent"],
|
||||
MarketplaceReceptionPendingSignEvent?:ResolverInputTypes["MarketplaceReceptionPendingSignEvent"],
|
||||
__typename?: boolean | `@${string}`
|
||||
}>;
|
||||
["MarketplaceEventsInput"]: {
|
||||
/** Кооперативное имя. */
|
||||
coopname: string
|
||||
};
|
||||
["MarketplaceExpressPickupCandidate"]: AliasType<{
|
||||
/** КУ-получатель. */
|
||||
braname?:boolean | `@${string}`,
|
||||
@@ -17585,6 +17627,16 @@ export type ResolverInputTypes = {
|
||||
/** Общее количество страниц */
|
||||
totalPages?:boolean | `@${string}`,
|
||||
__typename?: boolean | `@${string}`
|
||||
}>;
|
||||
/** Заказ пайщика собран на пункте и ожидает его подписи получения. */
|
||||
["MarketplaceOrderReadyToReceiveEvent"]: AliasType<{
|
||||
/** Пункт выдачи, где заказ готов к получению. */
|
||||
braname?:boolean | `@${string}`,
|
||||
/** Контрольная сумма заказа. */
|
||||
order_hash?:boolean | `@${string}`,
|
||||
/** Идентификатор заказа. */
|
||||
order_id?:boolean | `@${string}`,
|
||||
__typename?: boolean | `@${string}`
|
||||
}>;
|
||||
/** Этап жизненного цикла заказа. */
|
||||
["MarketplaceOrderStatus"]:MarketplaceOrderStatus;
|
||||
@@ -17633,6 +17685,14 @@ export type ResolverInputTypes = {
|
||||
/** Название типа товара */
|
||||
typeName?:boolean | `@${string}`,
|
||||
__typename?: boolean | `@${string}`
|
||||
}>;
|
||||
/** Поставка ожидает подписи поставщика на пункте приёмки. */
|
||||
["MarketplaceReceptionPendingSignEvent"]: AliasType<{
|
||||
/** Наименование кооперативного участка приёмки. */
|
||||
ku_name?:boolean | `@${string}`,
|
||||
/** Идентификатор приёмки. */
|
||||
reception_id?:boolean | `@${string}`,
|
||||
__typename?: boolean | `@${string}`
|
||||
}>;
|
||||
["MarketplaceRegistrationOfferStatus"]: AliasType<{
|
||||
/** AGREEMENT_ID (например `marketplace_offer`) */
|
||||
@@ -21051,6 +21111,10 @@ validateReportEdits?: [{ editsJson: string, reportType: ResolverInputTypes["Repo
|
||||
/** Распределение голосов */
|
||||
votes: Array<ResolverInputTypes["VoteDistributionInput"]>
|
||||
};
|
||||
["Subscription"]: AliasType<{
|
||||
marketplaceEvents?: [{ input: ResolverInputTypes["MarketplaceEventsInput"]},ResolverInputTypes["MarketplaceEvent"]],
|
||||
__typename?: boolean | `@${string}`
|
||||
}>;
|
||||
["SubscriptionStatsDto"]: AliasType<{
|
||||
/** Количество активных подписок */
|
||||
active?:boolean | `@${string}`,
|
||||
@@ -21638,6 +21702,7 @@ validateReportEdits?: [{ editsJson: string, reportType: ResolverInputTypes["Repo
|
||||
["schema"]: AliasType<{
|
||||
query?:ResolverInputTypes["Query"],
|
||||
mutation?:ResolverInputTypes["Mutation"],
|
||||
subscription?:ResolverInputTypes["Subscription"],
|
||||
__typename?: boolean | `@${string}`
|
||||
}>;
|
||||
["ID"]:unknown
|
||||
@@ -26947,6 +27012,11 @@ export type ModelTypes = {
|
||||
picture?: string | undefined | null,
|
||||
/** Значение */
|
||||
value: string
|
||||
};
|
||||
["MarketplaceEvent"]:ModelTypes["MarketplaceOrderReadyToReceiveEvent"] | ModelTypes["MarketplaceReceptionPendingSignEvent"];
|
||||
["MarketplaceEventsInput"]: {
|
||||
/** Кооперативное имя. */
|
||||
coopname: string
|
||||
};
|
||||
["MarketplaceExpressPickupCandidate"]: {
|
||||
/** КУ-получатель. */
|
||||
@@ -27498,6 +27568,15 @@ export type ModelTypes = {
|
||||
totalCount: number,
|
||||
/** Общее количество страниц */
|
||||
totalPages: number
|
||||
};
|
||||
/** Заказ пайщика собран на пункте и ожидает его подписи получения. */
|
||||
["MarketplaceOrderReadyToReceiveEvent"]: {
|
||||
/** Пункт выдачи, где заказ готов к получению. */
|
||||
braname: string,
|
||||
/** Контрольная сумма заказа. */
|
||||
order_hash: string,
|
||||
/** Идентификатор заказа. */
|
||||
order_id: string
|
||||
};
|
||||
["MarketplaceOrderStatus"]:MarketplaceOrderStatus;
|
||||
["MarketplaceOutgoingPaymentRequest"]: {
|
||||
@@ -27542,6 +27621,13 @@ export type ModelTypes = {
|
||||
typeId: number,
|
||||
/** Название типа товара */
|
||||
typeName: string
|
||||
};
|
||||
/** Поставка ожидает подписи поставщика на пункте приёмки. */
|
||||
["MarketplaceReceptionPendingSignEvent"]: {
|
||||
/** Наименование кооперативного участка приёмки. */
|
||||
ku_name: string,
|
||||
/** Идентификатор приёмки. */
|
||||
reception_id: string
|
||||
};
|
||||
["MarketplaceRegistrationOfferStatus"]: {
|
||||
/** AGREEMENT_ID (например `marketplace_offer`) */
|
||||
@@ -31599,6 +31685,10 @@ export type ModelTypes = {
|
||||
project_hash: string,
|
||||
/** Распределение голосов */
|
||||
votes: Array<ModelTypes["VoteDistributionInput"]>
|
||||
};
|
||||
["Subscription"]: {
|
||||
/** Персональный поток событий пайщика в Столе заказов. */
|
||||
marketplaceEvents: ModelTypes["MarketplaceEvent"]
|
||||
};
|
||||
["SubscriptionStatsDto"]: {
|
||||
/** Количество активных подписок */
|
||||
@@ -32158,7 +32248,8 @@ export type ModelTypes = {
|
||||
["ZeroReportSignerType"]:ZeroReportSignerType;
|
||||
["schema"]: {
|
||||
query?: ModelTypes["Query"] | undefined | null,
|
||||
mutation?: ModelTypes["Mutation"] | undefined | null
|
||||
mutation?: ModelTypes["Mutation"] | undefined | null,
|
||||
subscription?: ModelTypes["Subscription"] | undefined | null
|
||||
};
|
||||
["ID"]:any
|
||||
}
|
||||
@@ -37809,6 +37900,15 @@ export type GraphQLTypes = {
|
||||
/** Значение */
|
||||
value: string,
|
||||
['...on MarketplaceDictionaryValue']: Omit<GraphQLTypes["MarketplaceDictionaryValue"], "...on MarketplaceDictionaryValue">
|
||||
};
|
||||
["MarketplaceEvent"]:{
|
||||
__typename:"MarketplaceOrderReadyToReceiveEvent" | "MarketplaceReceptionPendingSignEvent"
|
||||
['...on MarketplaceOrderReadyToReceiveEvent']: '__union' & GraphQLTypes["MarketplaceOrderReadyToReceiveEvent"];
|
||||
['...on MarketplaceReceptionPendingSignEvent']: '__union' & GraphQLTypes["MarketplaceReceptionPendingSignEvent"];
|
||||
};
|
||||
["MarketplaceEventsInput"]: {
|
||||
/** Кооперативное имя. */
|
||||
coopname: string
|
||||
};
|
||||
["MarketplaceExpressPickupCandidate"]: {
|
||||
__typename: "MarketplaceExpressPickupCandidate",
|
||||
@@ -38397,6 +38497,17 @@ export type GraphQLTypes = {
|
||||
/** Общее количество страниц */
|
||||
totalPages: number,
|
||||
['...on MarketplaceOrderPaginationResult']: Omit<GraphQLTypes["MarketplaceOrderPaginationResult"], "...on MarketplaceOrderPaginationResult">
|
||||
};
|
||||
/** Заказ пайщика собран на пункте и ожидает его подписи получения. */
|
||||
["MarketplaceOrderReadyToReceiveEvent"]: {
|
||||
__typename: "MarketplaceOrderReadyToReceiveEvent",
|
||||
/** Пункт выдачи, где заказ готов к получению. */
|
||||
braname: string,
|
||||
/** Контрольная сумма заказа. */
|
||||
order_hash: string,
|
||||
/** Идентификатор заказа. */
|
||||
order_id: string,
|
||||
['...on MarketplaceOrderReadyToReceiveEvent']: Omit<GraphQLTypes["MarketplaceOrderReadyToReceiveEvent"], "...on MarketplaceOrderReadyToReceiveEvent">
|
||||
};
|
||||
/** Этап жизненного цикла заказа. */
|
||||
["MarketplaceOrderStatus"]: MarketplaceOrderStatus;
|
||||
@@ -38447,6 +38558,15 @@ export type GraphQLTypes = {
|
||||
/** Название типа товара */
|
||||
typeName: string,
|
||||
['...on MarketplaceProductType']: Omit<GraphQLTypes["MarketplaceProductType"], "...on MarketplaceProductType">
|
||||
};
|
||||
/** Поставка ожидает подписи поставщика на пункте приёмки. */
|
||||
["MarketplaceReceptionPendingSignEvent"]: {
|
||||
__typename: "MarketplaceReceptionPendingSignEvent",
|
||||
/** Наименование кооперативного участка приёмки. */
|
||||
ku_name: string,
|
||||
/** Идентификатор приёмки. */
|
||||
reception_id: string,
|
||||
['...on MarketplaceReceptionPendingSignEvent']: Omit<GraphQLTypes["MarketplaceReceptionPendingSignEvent"], "...on MarketplaceReceptionPendingSignEvent">
|
||||
};
|
||||
["MarketplaceRegistrationOfferStatus"]: {
|
||||
__typename: "MarketplaceRegistrationOfferStatus",
|
||||
@@ -42774,6 +42894,12 @@ export type GraphQLTypes = {
|
||||
project_hash: string,
|
||||
/** Распределение голосов */
|
||||
votes: Array<GraphQLTypes["VoteDistributionInput"]>
|
||||
};
|
||||
["Subscription"]: {
|
||||
__typename: "Subscription",
|
||||
/** Персональный поток событий пайщика в Столе заказов. */
|
||||
marketplaceEvents: GraphQLTypes["MarketplaceEvent"],
|
||||
['...on Subscription']: Omit<GraphQLTypes["Subscription"], "...on Subscription">
|
||||
};
|
||||
["SubscriptionStatsDto"]: {
|
||||
__typename: "SubscriptionStatsDto",
|
||||
@@ -44208,6 +44334,7 @@ type ZEUS_VARIABLES = {
|
||||
["MarketplaceCreateWriteoffDraftInput"]: ValueTypes["MarketplaceCreateWriteoffDraftInput"];
|
||||
["MarketplaceDeclineOrdersBatchInput"]: ValueTypes["MarketplaceDeclineOrdersBatchInput"];
|
||||
["MarketplaceDetailKUInput"]: ValueTypes["MarketplaceDetailKUInput"];
|
||||
["MarketplaceEventsInput"]: ValueTypes["MarketplaceEventsInput"];
|
||||
["MarketplaceFinalizeIssuanceInput"]: ValueTypes["MarketplaceFinalizeIssuanceInput"];
|
||||
["MarketplaceGenerateInventoryLabelInput"]: ValueTypes["MarketplaceGenerateInventoryLabelInput"];
|
||||
["MarketplaceGeocodeStatus"]: ValueTypes["MarketplaceGeocodeStatus"];
|
||||
|
||||
Generated
+16
@@ -433,6 +433,9 @@ importers:
|
||||
graphql-scalars:
|
||||
specifier: ^1.24.0
|
||||
version: 1.25.0(graphql@16.13.2)
|
||||
graphql-subscriptions:
|
||||
specifier: ^2.0.0
|
||||
version: 2.0.0(graphql@16.13.2)
|
||||
graphql-tools:
|
||||
specifier: ^9.0.2
|
||||
version: 9.0.26(graphql-ws@5.16.2(graphql@16.13.2))(graphql@16.13.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rxjs@7.8.2)(subscriptions-transport-ws@0.11.0(graphql@16.13.2))
|
||||
@@ -541,6 +544,9 @@ importers:
|
||||
spectaql:
|
||||
specifier: ^3.0.5
|
||||
version: 3.0.9
|
||||
subscriptions-transport-ws:
|
||||
specifier: ^0.11.0
|
||||
version: 0.11.0(graphql@16.13.2)
|
||||
swagger-jsdoc:
|
||||
specifier: ^6.0.8
|
||||
version: 6.2.8(openapi-types@12.1.3)
|
||||
@@ -11936,6 +11942,11 @@ packages:
|
||||
peerDependencies:
|
||||
graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0
|
||||
|
||||
graphql-subscriptions@2.0.0:
|
||||
resolution: {integrity: sha512-s6k2b8mmt9gF9pEfkxsaO1lTxaySfKoEJzEfmwguBbQ//Oq23hIXCfR1hm4kdh5hnR20RdwB+s3BCb+0duHSZA==}
|
||||
peerDependencies:
|
||||
graphql: ^15.7.2 || ^16.0.0
|
||||
|
||||
graphql-tag@2.12.6:
|
||||
resolution: {integrity: sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==}
|
||||
engines: {node: '>=10'}
|
||||
@@ -33003,6 +33014,11 @@ snapshots:
|
||||
graphql: 16.13.2
|
||||
tslib: 2.8.1
|
||||
|
||||
graphql-subscriptions@2.0.0(graphql@16.13.2):
|
||||
dependencies:
|
||||
graphql: 16.13.2
|
||||
iterall: 1.3.0
|
||||
|
||||
graphql-tag@2.12.6(graphql@16.13.2):
|
||||
dependencies:
|
||||
graphql: 16.13.2
|
||||
|
||||
Reference in New Issue
Block a user