mirror of
https://github.com/nestjs/nest.git
synced 2026-02-24 00:02:56 +00:00
Compare commits
85 Commits
miZyind-co
...
v7.6.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bbf091c77c | ||
|
|
192d22f5e0 | ||
|
|
72cd8ff732 | ||
|
|
fdb93219ad | ||
|
|
a9451b64fc | ||
|
|
d36c938548 | ||
|
|
63048baf99 | ||
|
|
a52001dfb9 | ||
|
|
bb38257d13 | ||
|
|
703afcb1ba | ||
|
|
80f5a9ce48 | ||
|
|
5a23bc1749 | ||
|
|
bb6b643645 | ||
|
|
710b385a32 | ||
|
|
e78f364ef4 | ||
|
|
23ce8d03e4 | ||
|
|
4c4d8039b8 | ||
|
|
016c6b554b | ||
|
|
3f5aad635b | ||
|
|
1c500b4bfc | ||
|
|
cad68b6d46 | ||
|
|
a22abe53b5 | ||
|
|
65afede473 | ||
|
|
171b53c3fb | ||
|
|
8875d431b4 | ||
|
|
0d078a0188 | ||
|
|
4dd0a1344e | ||
|
|
585ead7f24 | ||
|
|
be64b51796 | ||
|
|
55a2efd883 | ||
|
|
338be4c8d0 | ||
|
|
b0afb1a63a | ||
|
|
59cd40dd56 | ||
|
|
685c685bd7 | ||
|
|
be2384c4c7 | ||
|
|
e7ef9d9c70 | ||
|
|
fc5b440da2 | ||
|
|
998d3de9e6 | ||
|
|
e766276922 | ||
|
|
2abb426d99 | ||
|
|
4fc147f6e0 | ||
|
|
63337763a2 | ||
|
|
ab6960da62 | ||
|
|
a0ded7ad68 | ||
|
|
15aca2bfef | ||
|
|
9df5146082 | ||
|
|
c79685c88b | ||
|
|
9c8cf3978a | ||
|
|
8c9ee77fb8 | ||
|
|
fb3db3f6bf | ||
|
|
8c503d3193 | ||
|
|
b65f1be3f2 | ||
|
|
9a64742f61 | ||
|
|
1e32627d17 | ||
|
|
e4243d55c2 | ||
|
|
684c5f4af7 | ||
|
|
51e3559995 | ||
|
|
beb8fe36fc | ||
|
|
2a4dcc1964 | ||
|
|
e7150ba5a9 | ||
|
|
a0a3fb96cf | ||
|
|
7ef474e74e | ||
|
|
8dc4967721 | ||
|
|
419167ad0f | ||
|
|
35add88251 | ||
|
|
0f80068198 | ||
|
|
32b19c7c37 | ||
|
|
827f1e7f77 | ||
|
|
404a916129 | ||
|
|
1e1a52eb20 | ||
|
|
c67b58f527 | ||
|
|
4763fb9552 | ||
|
|
68ad994f2d | ||
|
|
0f15e35f2b | ||
|
|
25ca219254 | ||
|
|
5e21c9e51e | ||
|
|
b0a0623cf8 | ||
|
|
9449d612aa | ||
|
|
15473e4251 | ||
|
|
1a46de0af3 | ||
|
|
453e4afd3e | ||
|
|
ffd602ffd5 | ||
|
|
badae7b4e7 | ||
|
|
a85cb0fe4b | ||
|
|
cc9a912d0a |
@@ -70,3 +70,4 @@ services:
|
||||
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092
|
||||
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
|
||||
KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0
|
||||
KAFKA_DELETE_TOPIC_ENABLE: 'true'
|
||||
|
||||
@@ -26,7 +26,7 @@ class TestInjectable
|
||||
class AppModule {}
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create(AppModule, { logger: true });
|
||||
const app = await NestFactory.create(AppModule, { logger: false });
|
||||
|
||||
if (SIGNAL_TO_LISTEN && SIGNAL_TO_LISTEN !== 'NONE') {
|
||||
app.enableShutdownHooks([SIGNAL_TO_LISTEN]);
|
||||
|
||||
291
integration/microservices/e2e/concurrent-kafka.spec.ts
Normal file
291
integration/microservices/e2e/concurrent-kafka.spec.ts
Normal file
@@ -0,0 +1,291 @@
|
||||
import { INestApplication, Logger } from '@nestjs/common';
|
||||
import { Transport } from '@nestjs/microservices';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { Admin, ITopicMetadata, Kafka } from 'kafkajs';
|
||||
import * as request from 'supertest';
|
||||
import * as util from 'util';
|
||||
import { KafkaConcurrentController } from '../src/kafka-concurrent/kafka-concurrent.controller';
|
||||
import { KafkaConcurrentMessagesController } from '../src/kafka-concurrent/kafka-concurrent.messages.controller';
|
||||
|
||||
describe('Kafka concurrent', function () {
|
||||
const numbersOfServers = 3;
|
||||
|
||||
const requestTopic = 'math.sum.sync.number.wait';
|
||||
const responseTopic = 'math.sum.sync.number.wait.reply';
|
||||
|
||||
let admin: Admin;
|
||||
const servers: any[] = [];
|
||||
const apps: INestApplication[] = [];
|
||||
|
||||
const logger = new Logger('concurrent-kafka.spec.ts');
|
||||
|
||||
// set timeout to be longer (especially for the after hook)
|
||||
this.timeout(30000);
|
||||
|
||||
const startServer = async () => {
|
||||
const module = await Test.createTestingModule({
|
||||
controllers: [
|
||||
KafkaConcurrentController,
|
||||
KafkaConcurrentMessagesController,
|
||||
],
|
||||
}).compile();
|
||||
|
||||
// use our own logger for a little
|
||||
// Logger.overrideLogger(new Logger());
|
||||
|
||||
const app = module.createNestApplication();
|
||||
|
||||
const server = app.getHttpAdapter().getInstance();
|
||||
|
||||
app.connectMicroservice({
|
||||
transport: Transport.KAFKA,
|
||||
options: {
|
||||
client: {
|
||||
brokers: ['localhost:9092'],
|
||||
},
|
||||
run: {
|
||||
partitionsConsumedConcurrently: numbersOfServers,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// enable these for clean shutdown
|
||||
app.enableShutdownHooks();
|
||||
|
||||
// push to the collection
|
||||
servers.push(server);
|
||||
apps.push(app);
|
||||
|
||||
// await the start
|
||||
await app.startAllMicroservicesAsync();
|
||||
await app.init();
|
||||
};
|
||||
|
||||
it(`Create kafka topics/partitions`, async () => {
|
||||
const kafka = new Kafka({
|
||||
clientId: 'concurrent-test-admin',
|
||||
brokers: ['localhost:9092'],
|
||||
});
|
||||
|
||||
admin = kafka.admin();
|
||||
await admin.connect();
|
||||
|
||||
let topicMetadata: {
|
||||
topics: ITopicMetadata[];
|
||||
};
|
||||
|
||||
try {
|
||||
topicMetadata = await admin.fetchTopicMetadata({
|
||||
topics: [requestTopic, responseTopic],
|
||||
});
|
||||
} catch (e) {
|
||||
// create with number of servers
|
||||
try {
|
||||
await admin.createTopics({
|
||||
topics: [
|
||||
{
|
||||
topic: requestTopic,
|
||||
numPartitions: numbersOfServers,
|
||||
replicationFactor: 1,
|
||||
},
|
||||
{
|
||||
topic: responseTopic,
|
||||
numPartitions: numbersOfServers,
|
||||
replicationFactor: 1,
|
||||
},
|
||||
],
|
||||
});
|
||||
} catch (e) {
|
||||
logger.error(util.format('Create topics error: %o', e));
|
||||
}
|
||||
}
|
||||
|
||||
if (topicMetadata && topicMetadata.topics.length > 0) {
|
||||
// we have topics, how many partitions do they have?
|
||||
for (const topic of topicMetadata.topics) {
|
||||
if (topic.partitions.length < numbersOfServers) {
|
||||
try {
|
||||
await admin.createPartitions({
|
||||
topicPartitions: [
|
||||
{
|
||||
topic: topic.name,
|
||||
count: numbersOfServers,
|
||||
},
|
||||
],
|
||||
});
|
||||
} catch (e) {
|
||||
logger.error(util.format('Create partitions error: %o', e));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// create with number of servers
|
||||
try {
|
||||
await admin.createTopics({
|
||||
topics: [
|
||||
{
|
||||
topic: requestTopic,
|
||||
numPartitions: numbersOfServers,
|
||||
replicationFactor: 1,
|
||||
},
|
||||
{
|
||||
topic: responseTopic,
|
||||
numPartitions: numbersOfServers,
|
||||
replicationFactor: 1,
|
||||
},
|
||||
],
|
||||
});
|
||||
} catch (e) {
|
||||
logger.error(util.format('Create topics error: %o', e));
|
||||
}
|
||||
|
||||
// disconnect
|
||||
await admin.disconnect();
|
||||
});
|
||||
|
||||
it(`Start Kafka apps`, async () => {
|
||||
// start all at once
|
||||
await Promise.all(
|
||||
Array(numbersOfServers)
|
||||
.fill(1)
|
||||
.map(async (v, i) => {
|
||||
// return startServer();
|
||||
|
||||
// wait in intervals so the consumers start in order
|
||||
return new Promise<void>(resolve => {
|
||||
setTimeout(async () => {
|
||||
await startServer();
|
||||
|
||||
return resolve();
|
||||
}, 1000 * i);
|
||||
});
|
||||
}),
|
||||
);
|
||||
}).timeout(30000);
|
||||
|
||||
it(`Concurrent messages without forcing a rebalance.`, async () => {
|
||||
// wait a second before notifying the servers to respond
|
||||
setTimeout(async () => {
|
||||
// notify the other servers that it is time to respond
|
||||
await Promise.all(
|
||||
servers.map(async server => {
|
||||
// send to all servers since indexes don't necessarily align with server consumers
|
||||
return request(server).post('/go').send();
|
||||
}),
|
||||
);
|
||||
}, 1000);
|
||||
|
||||
await Promise.all(
|
||||
servers.map(async (server, index) => {
|
||||
// send requests
|
||||
const payload = {
|
||||
key: index,
|
||||
numbers: [1, index],
|
||||
};
|
||||
const result = (1 + index).toString();
|
||||
|
||||
return request(server)
|
||||
.post('/mathSumSyncNumberWait')
|
||||
.send(payload)
|
||||
.expect(200)
|
||||
.expect(200, result);
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it(`Close kafka client consumer while waiting for message pattern response.`, async () => {
|
||||
await Promise.all(
|
||||
servers.map(async (server, index) => {
|
||||
// shut off and delete the leader
|
||||
if (index === 0) {
|
||||
return new Promise<void>(resolve => {
|
||||
// wait a second before closing so the producers can send the message to the server consumers
|
||||
setTimeout(async () => {
|
||||
// get the controller
|
||||
const controller = apps[index].get(KafkaConcurrentController);
|
||||
|
||||
// close the controller clients
|
||||
await controller.client.close();
|
||||
|
||||
// notify the other servers that we have stopped
|
||||
await Promise.all(
|
||||
servers.map(async server => {
|
||||
// send to all servers since indexes don't necessarily align with server consumers
|
||||
return request(server).post('/go').send();
|
||||
}),
|
||||
);
|
||||
|
||||
return resolve();
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
|
||||
// send requests
|
||||
const payload = {
|
||||
key: index,
|
||||
numbers: [1, index],
|
||||
};
|
||||
const result = (1 + index).toString();
|
||||
|
||||
return request(server)
|
||||
.post('/mathSumSyncNumberWait')
|
||||
.send(payload)
|
||||
.expect(200)
|
||||
.expect(200, result);
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it(`Start kafka client consumer while waiting for message pattern response.`, async () => {
|
||||
await Promise.all(
|
||||
servers.map(async (server, index) => {
|
||||
// shut off and delete the leader
|
||||
if (index === 0) {
|
||||
return new Promise<void>(resolve => {
|
||||
// wait a second before closing so the producers can send the message to the server consumers
|
||||
setTimeout(async () => {
|
||||
// get the controller
|
||||
const controller = apps[index].get(KafkaConcurrentController);
|
||||
|
||||
// connect the controller client
|
||||
await controller.client.connect();
|
||||
|
||||
// notify the servers that we have started
|
||||
await Promise.all(
|
||||
servers.map(async server => {
|
||||
// send to all servers since indexes don't necessarily align with server consumers
|
||||
return request(server).post('/go').send();
|
||||
}),
|
||||
);
|
||||
|
||||
return resolve();
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
|
||||
// send requests
|
||||
const payload = {
|
||||
key: index,
|
||||
numbers: [1, index],
|
||||
};
|
||||
const result = (1 + index).toString();
|
||||
|
||||
return request(server)
|
||||
.post('/mathSumSyncNumberWait')
|
||||
.send(payload)
|
||||
.expect(200)
|
||||
.expect(200, result);
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
after(`Stopping Kafka app`, async () => {
|
||||
// close all concurrently
|
||||
return Promise.all(
|
||||
apps.map(async app => {
|
||||
return app.close();
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -9,10 +9,13 @@ import { UserEntity } from '../src/kafka/entities/user.entity';
|
||||
import { KafkaController } from '../src/kafka/kafka.controller';
|
||||
import { KafkaMessagesController } from '../src/kafka/kafka.messages.controller';
|
||||
|
||||
describe('Kafka transport', () => {
|
||||
describe('Kafka transport', function () {
|
||||
let server;
|
||||
let app: INestApplication;
|
||||
|
||||
// set timeout to be longer (especially for the after hook)
|
||||
this.timeout(30000);
|
||||
|
||||
it(`Start Kafka app`, async () => {
|
||||
const module = await Test.createTestingModule({
|
||||
controllers: [KafkaController, KafkaMessagesController],
|
||||
@@ -29,6 +32,7 @@ describe('Kafka transport', () => {
|
||||
},
|
||||
},
|
||||
});
|
||||
app.enableShutdownHooks();
|
||||
await app.startAllMicroservicesAsync();
|
||||
await app.init();
|
||||
}).timeout(30000);
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
export class SumDto {
|
||||
key: string;
|
||||
numbers: number[];
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
HttpCode,
|
||||
OnModuleDestroy,
|
||||
OnModuleInit,
|
||||
Post,
|
||||
} from '@nestjs/common';
|
||||
import { Logger } from '@nestjs/common/services/logger.service';
|
||||
import { Client, ClientKafka, Transport } from '@nestjs/microservices';
|
||||
import { PartitionerArgs } from 'kafkajs';
|
||||
import { Observable } from 'rxjs';
|
||||
import { SumDto } from './dto/sum.dto';
|
||||
|
||||
/**
|
||||
* The following function explicity sends messages to the key representing the partition.
|
||||
*/
|
||||
const explicitPartitioner = () => {
|
||||
return ({ message }: PartitionerArgs) => {
|
||||
return parseFloat(message.headers.toPartition.toString());
|
||||
};
|
||||
};
|
||||
|
||||
@Controller()
|
||||
export class KafkaConcurrentController
|
||||
implements OnModuleInit, OnModuleDestroy {
|
||||
protected readonly logger = new Logger(KafkaConcurrentController.name);
|
||||
|
||||
@Client({
|
||||
transport: Transport.KAFKA,
|
||||
options: {
|
||||
client: {
|
||||
brokers: ['localhost:9092'],
|
||||
},
|
||||
run: {
|
||||
partitionsConsumedConcurrently: 3,
|
||||
},
|
||||
producer: {
|
||||
createPartitioner: explicitPartitioner,
|
||||
},
|
||||
},
|
||||
})
|
||||
public readonly client: ClientKafka;
|
||||
|
||||
async onModuleInit() {
|
||||
const requestPatterns = ['math.sum.sync.number.wait'];
|
||||
|
||||
requestPatterns.forEach(pattern => {
|
||||
this.client.subscribeToResponseOf(pattern);
|
||||
});
|
||||
|
||||
await this.client.connect();
|
||||
}
|
||||
|
||||
async onModuleDestroy() {
|
||||
await this.client.close();
|
||||
}
|
||||
|
||||
@Post('mathSumSyncNumberWait')
|
||||
@HttpCode(200)
|
||||
public mathSumSyncNumberWait(@Body() data: SumDto): Observable<string> {
|
||||
return this.client.send('math.sum.sync.number.wait', {
|
||||
headers: {
|
||||
toPartition: data.key.toString(),
|
||||
},
|
||||
key: data.key.toString(),
|
||||
value: data.numbers,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import { Controller, HttpCode, Post } from '@nestjs/common';
|
||||
import { MessagePattern } from '@nestjs/microservices';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { first, map, skipWhile } from 'rxjs/operators';
|
||||
|
||||
@Controller()
|
||||
export class KafkaConcurrentMessagesController {
|
||||
public waiting = new BehaviorSubject<boolean>(false);
|
||||
|
||||
@Post('go')
|
||||
@HttpCode(200)
|
||||
async go() {
|
||||
// no longer waiting
|
||||
this.waiting.next(false);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@MessagePattern('math.sum.sync.number.wait')
|
||||
public mathSumSyncNumberWait(data: any): Observable<number> {
|
||||
// start waiting
|
||||
this.waiting.next(true);
|
||||
|
||||
// find sum
|
||||
const sum = data.value[0] + data.value[1];
|
||||
|
||||
return this.waiting.asObservable().pipe(
|
||||
skipWhile(isWaiting => {
|
||||
return isWaiting;
|
||||
}),
|
||||
map(() => {
|
||||
return sum;
|
||||
}),
|
||||
first(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Body, Controller, HttpCode, OnModuleInit, Post } from '@nestjs/common';
|
||||
import { Body, Controller, HttpCode, OnModuleInit, Post, OnModuleDestroy } from '@nestjs/common';
|
||||
import { Logger } from '@nestjs/common/services/logger.service';
|
||||
import { Client, ClientKafka, Transport } from '@nestjs/microservices';
|
||||
import { Observable } from 'rxjs';
|
||||
@@ -6,7 +6,7 @@ import { BusinessDto } from './dtos/business.dto';
|
||||
import { UserDto } from './dtos/user.dto';
|
||||
|
||||
@Controller()
|
||||
export class KafkaController implements OnModuleInit {
|
||||
export class KafkaController implements OnModuleInit, OnModuleDestroy {
|
||||
protected readonly logger = new Logger(KafkaController.name);
|
||||
static IS_NOTIFIED = false;
|
||||
static MATH_SUM = 0;
|
||||
@@ -21,7 +21,7 @@ export class KafkaController implements OnModuleInit {
|
||||
})
|
||||
private readonly client: ClientKafka;
|
||||
|
||||
onModuleInit() {
|
||||
async onModuleInit() {
|
||||
const requestPatterns = [
|
||||
'math.sum.sync.kafka.message',
|
||||
'math.sum.sync.without.key',
|
||||
@@ -36,6 +36,12 @@ export class KafkaController implements OnModuleInit {
|
||||
requestPatterns.forEach(pattern => {
|
||||
this.client.subscribeToResponseOf(pattern);
|
||||
});
|
||||
|
||||
await this.client.connect();
|
||||
}
|
||||
|
||||
async onModuleDestroy() {
|
||||
await this.client.close();
|
||||
}
|
||||
|
||||
// sync send kafka message
|
||||
|
||||
@@ -20,7 +20,7 @@ describe('ErrorGateway', () => {
|
||||
ws.emit('push', {
|
||||
test: 'test',
|
||||
});
|
||||
await new Promise(resolve =>
|
||||
await new Promise<void>(resolve =>
|
||||
ws.on('exception', data => {
|
||||
expect(data).to.be.eql({
|
||||
status: 'error',
|
||||
|
||||
@@ -20,7 +20,7 @@ describe('WebSocketGateway (ack)', () => {
|
||||
await app.listenAsync(3000);
|
||||
|
||||
ws = io.connect('http://localhost:8080');
|
||||
await new Promise(resolve =>
|
||||
await new Promise<void>(resolve =>
|
||||
ws.emit('push', { test: 'test' }, data => {
|
||||
expect(data).to.be.eql('pong');
|
||||
resolve();
|
||||
@@ -33,7 +33,7 @@ describe('WebSocketGateway (ack)', () => {
|
||||
await app.listenAsync(3000);
|
||||
|
||||
ws = io.connect('http://localhost:8080');
|
||||
await new Promise(resolve =>
|
||||
await new Promise<void>(resolve =>
|
||||
ws.emit('push', data => {
|
||||
expect(data).to.be.eql('pong');
|
||||
resolve();
|
||||
|
||||
@@ -25,7 +25,7 @@ describe('WebSocketGateway', () => {
|
||||
ws.emit('push', {
|
||||
test: 'test',
|
||||
});
|
||||
await new Promise(resolve =>
|
||||
await new Promise<void>(resolve =>
|
||||
ws.on('pop', data => {
|
||||
expect(data.test).to.be.eql('test');
|
||||
resolve();
|
||||
@@ -41,7 +41,7 @@ describe('WebSocketGateway', () => {
|
||||
ws.emit('push', {
|
||||
test: 'test',
|
||||
});
|
||||
await new Promise(resolve =>
|
||||
await new Promise<void>(resolve =>
|
||||
ws.on('pop', data => {
|
||||
expect(data.test).to.be.eql('test');
|
||||
resolve();
|
||||
@@ -58,7 +58,7 @@ describe('WebSocketGateway', () => {
|
||||
ws.emit('push', {
|
||||
test: 'test',
|
||||
});
|
||||
await new Promise(resolve =>
|
||||
await new Promise<void>(resolve =>
|
||||
ws.on('pop', data => {
|
||||
expect(data.test).to.be.eql('test');
|
||||
resolve();
|
||||
|
||||
@@ -34,7 +34,7 @@ describe('WebSocketGateway (WsAdapter)', () => {
|
||||
},
|
||||
}),
|
||||
);
|
||||
await new Promise(resolve =>
|
||||
await new Promise<void>(resolve =>
|
||||
ws.on('message', data => {
|
||||
expect(JSON.parse(data).data.test).to.be.eql('test');
|
||||
resolve();
|
||||
@@ -57,7 +57,7 @@ describe('WebSocketGateway (WsAdapter)', () => {
|
||||
},
|
||||
}),
|
||||
);
|
||||
await new Promise(resolve =>
|
||||
await new Promise<void>(resolve =>
|
||||
ws.on('message', data => {
|
||||
expect(JSON.parse(data).data.test).to.be.eql('test');
|
||||
resolve();
|
||||
@@ -77,7 +77,7 @@ describe('WebSocketGateway (WsAdapter)', () => {
|
||||
ws = new WebSocket('ws://localhost:8080');
|
||||
ws2 = new WebSocket('ws://localhost:8090');
|
||||
|
||||
await new Promise(resolve =>
|
||||
await new Promise<void>(resolve =>
|
||||
ws.on('open', () => {
|
||||
ws.on('message', data => {
|
||||
expect(JSON.parse(data).data.test).to.be.eql('test');
|
||||
@@ -94,7 +94,7 @@ describe('WebSocketGateway (WsAdapter)', () => {
|
||||
}),
|
||||
);
|
||||
|
||||
await new Promise(resolve => {
|
||||
await new Promise<void>(resolve => {
|
||||
ws2.on('message', data => {
|
||||
expect(JSON.parse(data).data.test).to.be.eql('test');
|
||||
resolve();
|
||||
|
||||
@@ -3,5 +3,5 @@
|
||||
"packages": [
|
||||
"packages/*"
|
||||
],
|
||||
"version": "7.5.5"
|
||||
"version": "7.6.1"
|
||||
}
|
||||
|
||||
165
package-lock.json
generated
165
package-lock.json
generated
@@ -3621,6 +3621,12 @@
|
||||
"requires": {
|
||||
"is-number": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"uuid": {
|
||||
"version": "8.3.1",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz",
|
||||
"integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -3631,9 +3637,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@nestjs/mongoose": {
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/mongoose/-/mongoose-7.1.2.tgz",
|
||||
"integrity": "sha512-VjeF0woAWs/J/ecpVqKwpPAEh8oRICJgn60ZHu73XHa9VDw8F1wPCrHdG3SQtPumbjNTTvXEqSyaKSuW/8Qp/A==",
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/mongoose/-/mongoose-7.2.0.tgz",
|
||||
"integrity": "sha512-EYlY/MPcVz9t5gWt1Gz0/wGi0m6BqeNuVw548P7glOqguCKE+Qy/tI/RTJX0Fo9PnSnF4dj3dOWkfDwT237vSg==",
|
||||
"dev": true
|
||||
},
|
||||
"@nestjs/typeorm": {
|
||||
@@ -3643,6 +3649,14 @@
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"uuid": "8.3.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"uuid": {
|
||||
"version": "8.3.1",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz",
|
||||
"integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@nodelib/fs.scandir": {
|
||||
@@ -4441,9 +4455,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@types/mocha": {
|
||||
"version": "8.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-8.0.4.tgz",
|
||||
"integrity": "sha512-M4BwiTJjHmLq6kjON7ZoI2JMlBvpY3BYSdiP6s/qCT3jb1s9/DeJF0JELpAxiVSIxXDzfNKe+r7yedMIoLbknQ==",
|
||||
"version": "8.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-8.2.0.tgz",
|
||||
"integrity": "sha512-/Sge3BymXo4lKc31C8OINJgXLaw+7vL1/L1pGiBNpGrBiT8FQiaFpSYV0uhTaG4y78vcMBTMFsWaHDvuD+xGzQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/mongodb": {
|
||||
@@ -4467,9 +4481,9 @@
|
||||
}
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "14.14.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.10.tgz",
|
||||
"integrity": "sha512-J32dgx2hw8vXrSbu4ZlVhn1Nm3GbeCFNw2FWL8S5QKucHGY0cyNwjdQdO+KMBZ4wpmC7KhLCiNsdk1RFRIYUQQ==",
|
||||
"version": "14.14.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.11.tgz",
|
||||
"integrity": "sha512-BJ97wAUuU3NUiUCp44xzUFquQEvnk1wu7q4CMEUYKJWjdkr0YWYDsm4RFtAvxYsNjLsKcrFt6RvK8r+mnzMbEQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/node-fetch": {
|
||||
@@ -8248,8 +8262,7 @@
|
||||
"component-inherit": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz",
|
||||
"integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=",
|
||||
"dev": true
|
||||
"integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM="
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
@@ -9592,11 +9605,6 @@
|
||||
"yargs-parser": "^20.2.3"
|
||||
}
|
||||
},
|
||||
"minimist": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
|
||||
},
|
||||
"minimist-options": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz",
|
||||
@@ -9782,11 +9790,6 @@
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"dev": true
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||
@@ -11402,9 +11405,9 @@
|
||||
}
|
||||
},
|
||||
"engine.io-client": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-4.0.4.tgz",
|
||||
"integrity": "sha512-and4JRvjv+BQ4WBLopYUFePxju3ms3aBRk0XjaLdh/t9TKv2LCKtKKWFRoRzIfUZsu3U38FcYqNLuXhfS16vqw==",
|
||||
"version": "4.0.5",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-4.0.5.tgz",
|
||||
"integrity": "sha512-1lkn0QdekHQPMTcxUh8LqIuxQHNtKV5GvqkQzmZ1rYKAvB6puMm13U7K1ps3OQZ4joE46asQiAKrcdL9weNEVw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"base64-arraybuffer": "0.1.4",
|
||||
@@ -12980,21 +12983,13 @@
|
||||
}
|
||||
},
|
||||
"fastify-cors": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fastify-cors/-/fastify-cors-5.0.0.tgz",
|
||||
"integrity": "sha512-r7nQCEewNlwCF98ovNDlG89Et5tpbt+aYNLyTY3l2bwH213ZndKwhgqtlqWsJHOQ5naIRgwgzzkUbHVOYVL3/g==",
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fastify-cors/-/fastify-cors-5.1.0.tgz",
|
||||
"integrity": "sha512-PTq4wSBFljXmbFKmp5eKW9gg0m488nXBl+OSTb/vnWXXLvVn7HFk7WKgt7uQVfd9UuksveCGTXipVlus3qhmrw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fastify-plugin": "^3.0.0",
|
||||
"vary": "^1.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"fastify-plugin": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-3.0.0.tgz",
|
||||
"integrity": "sha512-ZdCvKEEd92DNLps5n0v231Bha8bkz1DjnPP/aEz37rz/q42Z5JVLmgnqR4DYuNn3NXAO3IDCPyRvgvxtJ4Ym4w==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"fastify-error": {
|
||||
@@ -17308,18 +17303,15 @@
|
||||
"dev": true
|
||||
},
|
||||
"kafkajs": {
|
||||
"version": "1.12.0",
|
||||
"resolved": "https://registry.npmjs.org/kafkajs/-/kafkajs-1.12.0.tgz",
|
||||
"integrity": "sha512-Izkd9iFRgeeKaHEgVpGQH08ygzCbHSxTbnu8W3G3uiNaVjGibUTmTwjv1Qf2M8NORXcPfzwVyg6bBlVj4SKr9g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"long": "^4.0.0"
|
||||
}
|
||||
"version": "1.14.0",
|
||||
"resolved": "https://registry.npmjs.org/kafkajs/-/kafkajs-1.14.0.tgz",
|
||||
"integrity": "sha512-W+WCekiooY5rJP3Me5N3gWcQ8O6uG6lw0vv9t+sI+WqXKjKwj2+CWIXJy241x+ITE+1M1D19ABSiL2J8lKja5A==",
|
||||
"dev": true
|
||||
},
|
||||
"kareem": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.1.tgz",
|
||||
"integrity": "sha512-l3hLhffs9zqoDe8zjmb/mAN4B8VT3L56EUvKNqLFVs9YlFA+zx7ke1DO8STAdDyYNkeSo1nKmjuvQeI12So8Xw==",
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.2.tgz",
|
||||
"integrity": "sha512-STHz9P7X2L4Kwn72fA4rGyqyXdmrMSdxqHx9IXon/FXluXieaFA6KJ2upcHAHxQPQ0LeM/OjLrhFxifHewOALQ==",
|
||||
"dev": true
|
||||
},
|
||||
"keyv": {
|
||||
@@ -19823,14 +19815,14 @@
|
||||
}
|
||||
},
|
||||
"mongoose": {
|
||||
"version": "5.11.5",
|
||||
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.11.5.tgz",
|
||||
"integrity": "sha512-uwSeALQ1+qamUZBrIe1D6/uCzlHvcSbNQPG9w02DJqF3VHJSFOX1RdoxJE/wTN6WW7tTV8NMdLDSdxKqfo8J1A==",
|
||||
"version": "5.11.6",
|
||||
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.11.6.tgz",
|
||||
"integrity": "sha512-sLM8gwgC6h/mM4kPsmQOBleKFwy/iY+h8nnqZgoI+MaqGNqidpLIM8yKjiWw8H10FuDf9Hq14biVKxMT4WgnXA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/mongodb": "^3.5.27",
|
||||
"bson": "^1.1.4",
|
||||
"kareem": "2.3.1",
|
||||
"kareem": "2.3.2",
|
||||
"mongodb": "3.6.3",
|
||||
"mongoose-legacy-pluralize": "1.0.2",
|
||||
"mpath": "0.8.0",
|
||||
@@ -24087,6 +24079,54 @@
|
||||
"ms": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"engine.io-client": {
|
||||
"version": "3.4.4",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.4.4.tgz",
|
||||
"integrity": "sha512-iU4CRr38Fecj8HoZEnFtm2EiKGbYZcPn3cHxqNGl/tmdWRf60KhK+9vE0JeSjgnlS/0oynEfLgKbT9ALpim0sQ==",
|
||||
"requires": {
|
||||
"component-emitter": "~1.3.0",
|
||||
"component-inherit": "0.0.3",
|
||||
"debug": "~3.1.0",
|
||||
"engine.io-parser": "~2.2.0",
|
||||
"has-cors": "1.1.0",
|
||||
"indexof": "0.0.1",
|
||||
"parseqs": "0.0.6",
|
||||
"parseuri": "0.0.6",
|
||||
"ws": "~6.1.0",
|
||||
"xmlhttprequest-ssl": "~1.5.4",
|
||||
"yeast": "0.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"component-emitter": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
|
||||
"integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg=="
|
||||
},
|
||||
"debug": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
|
||||
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
|
||||
"requires": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||
},
|
||||
"parseqs": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz",
|
||||
"integrity": "sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w=="
|
||||
},
|
||||
"parseuri": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.6.tgz",
|
||||
"integrity": "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"isarray": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
|
||||
@@ -24102,6 +24142,7 @@
|
||||
"component-bind": "1.0.0",
|
||||
"component-emitter": "1.2.1",
|
||||
"debug": "~4.1.0",
|
||||
"engine.io-client": "~3.4.0",
|
||||
"has-binary2": "~1.0.2",
|
||||
"has-cors": "1.1.0",
|
||||
"indexof": "0.0.1",
|
||||
@@ -24143,6 +24184,14 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ws": {
|
||||
"version": "6.1.4",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-6.1.4.tgz",
|
||||
"integrity": "sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==",
|
||||
"requires": {
|
||||
"async-limiter": "~1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -26041,9 +26090,9 @@
|
||||
}
|
||||
},
|
||||
"typescript": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.3.tgz",
|
||||
"integrity": "sha512-tEu6DGxGgRJPb/mVPIZ48e69xCn2yRmCgYmDugAVwmJ6o+0u1RI18eO7E7WBTLYLaEVVOhwQmcdhQHweux/WPg==",
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.2.tgz",
|
||||
"integrity": "sha512-thGloWsGH3SOxv1SoY7QojKi0tc+8FnOmiarEGMbd/lar7QOEd3hvlx3Fp5y6FlDUGl9L+pd4n2e+oToGMmhRQ==",
|
||||
"dev": true
|
||||
},
|
||||
"ua-parser-js": {
|
||||
@@ -26411,9 +26460,9 @@
|
||||
"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
|
||||
},
|
||||
"uuid": {
|
||||
"version": "8.3.1",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz",
|
||||
"integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg=="
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
|
||||
},
|
||||
"v8-compile-cache": {
|
||||
"version": "2.2.0",
|
||||
@@ -26963,8 +27012,7 @@
|
||||
"xmlhttprequest-ssl": {
|
||||
"version": "1.5.5",
|
||||
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz",
|
||||
"integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=",
|
||||
"dev": true
|
||||
"integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4="
|
||||
},
|
||||
"xss": {
|
||||
"version": "1.0.7",
|
||||
@@ -27299,8 +27347,7 @@
|
||||
"yeast": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz",
|
||||
"integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=",
|
||||
"dev": true
|
||||
"integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk="
|
||||
},
|
||||
"yn": {
|
||||
"version": "3.1.1",
|
||||
|
||||
20
package.json
20
package.json
@@ -66,8 +66,8 @@
|
||||
"reflect-metadata": "0.1.13",
|
||||
"rxjs": "6.6.3",
|
||||
"socket.io": "2.3.0",
|
||||
"uuid": "8.3.1",
|
||||
"tslib": "2.0.3"
|
||||
"tslib": "2.0.3",
|
||||
"uuid": "8.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@codechecks/client": "0.1.10",
|
||||
@@ -75,7 +75,7 @@
|
||||
"@commitlint/config-angular": "11.0.0",
|
||||
"@grpc/proto-loader": "0.5.5",
|
||||
"@nestjs/graphql": "7.9.1",
|
||||
"@nestjs/mongoose": "7.1.2",
|
||||
"@nestjs/mongoose": "7.2.0",
|
||||
"@nestjs/typeorm": "7.1.5",
|
||||
"@types/amqplib": "0.5.16",
|
||||
"@types/bytes": "3.1.0",
|
||||
@@ -85,9 +85,9 @@
|
||||
"@types/cors": "2.8.8",
|
||||
"@types/express": "4.17.9",
|
||||
"@types/gulp": "4.0.7",
|
||||
"@types/mocha": "8.0.4",
|
||||
"@types/mocha": "8.2.0",
|
||||
"@types/mongoose": "5.10.2",
|
||||
"@types/node": "14.14.10",
|
||||
"@types/node": "14.14.11",
|
||||
"@types/redis": "2.8.28",
|
||||
"@types/reflect-metadata": "0.1.0",
|
||||
"@types/sinon": "9.0.9",
|
||||
@@ -112,14 +112,14 @@
|
||||
"core-js": "3.8.1",
|
||||
"coveralls": "3.1.0",
|
||||
"delete-empty": "3.0.0",
|
||||
"engine.io-client": "4.0.4",
|
||||
"engine.io-client": "4.0.5",
|
||||
"eslint": "7.15.0",
|
||||
"eslint-config-prettier": "7.0.0",
|
||||
"eslint-plugin-import": "2.22.1",
|
||||
"eventsource": "1.0.7",
|
||||
"fancy-log": "1.3.3",
|
||||
"fastify": "3.9.1",
|
||||
"fastify-cors": "5.0.0",
|
||||
"fastify-cors": "5.1.0",
|
||||
"fastify-formbody": "5.0.0",
|
||||
"fastify-multipart": "3.3.1",
|
||||
"fastify-static": "3.3.0",
|
||||
@@ -135,7 +135,7 @@
|
||||
"husky": "4.3.5",
|
||||
"imports-loader": "1.2.0",
|
||||
"json-loader": "0.5.7",
|
||||
"kafkajs": "1.12.0",
|
||||
"kafkajs": "1.14.0",
|
||||
"lerna": "2.11.0",
|
||||
"light-my-request": "4.3.0",
|
||||
"lint-staged": "10.5.3",
|
||||
@@ -143,7 +143,7 @@
|
||||
"merge-graphql-schemas": "1.7.8",
|
||||
"middie": "5.2.0",
|
||||
"mocha": "8.2.1",
|
||||
"mongoose": "5.11.5",
|
||||
"mongoose": "5.11.6",
|
||||
"mqtt": "4.2.6",
|
||||
"multer": "1.4.2",
|
||||
"mysql": "2.18.1",
|
||||
@@ -162,7 +162,7 @@
|
||||
"ts-morph": "9.1.0",
|
||||
"ts-node": "9.1.1",
|
||||
"typeorm": "0.2.29",
|
||||
"typescript": "4.0.3",
|
||||
"typescript": "4.1.2",
|
||||
"wrk": "1.2.1",
|
||||
"ws": "7.4.1"
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nestjs/common",
|
||||
"version": "7.5.5",
|
||||
"version": "7.6.1",
|
||||
"description": "Nest - modern, fast, powerful node.js web framework (@common)",
|
||||
"author": "Kamil Mysliwiec",
|
||||
"homepage": "https://nestjs.com",
|
||||
@@ -20,10 +20,24 @@
|
||||
"axios": "0.21.0",
|
||||
"iterare": "1.2.1",
|
||||
"tslib": "2.0.3",
|
||||
"uuid": "8.3.1"
|
||||
"uuid": "8.3.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"cache-manager": "*",
|
||||
"class-transformer": "*",
|
||||
"class-validator": "*",
|
||||
"reflect-metadata": "^0.1.12",
|
||||
"rxjs": "^6.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"cache-manager": {
|
||||
"optional": true
|
||||
},
|
||||
"class-validator": {
|
||||
"optional": true
|
||||
},
|
||||
"class-transformer": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,27 +199,35 @@ export class ValidationPipe implements PipeTransform<any> {
|
||||
|
||||
protected mapChildrenToValidationErrors(
|
||||
error: ValidationError,
|
||||
parentPath?: string,
|
||||
): ValidationError[] {
|
||||
if (!(error.children && error.children.length)) {
|
||||
return [error];
|
||||
}
|
||||
const validationErrors = [];
|
||||
parentPath = parentPath
|
||||
? `${parentPath}.${error.property}`
|
||||
: error.property;
|
||||
for (const item of error.children) {
|
||||
if (item.children && item.children.length) {
|
||||
validationErrors.push(...this.mapChildrenToValidationErrors(item));
|
||||
validationErrors.push(
|
||||
...this.mapChildrenToValidationErrors(item, parentPath),
|
||||
);
|
||||
}
|
||||
validationErrors.push(this.prependConstraintsWithParentProp(error, item));
|
||||
validationErrors.push(
|
||||
this.prependConstraintsWithParentProp(parentPath, item),
|
||||
);
|
||||
}
|
||||
return validationErrors;
|
||||
}
|
||||
|
||||
protected prependConstraintsWithParentProp(
|
||||
parentError: ValidationError,
|
||||
parentPath: string,
|
||||
error: ValidationError,
|
||||
): ValidationError {
|
||||
const constraints = {};
|
||||
for (const key in error.constraints) {
|
||||
constraints[key] = `${parentError.property}.${error.constraints[key]}`;
|
||||
constraints[key] = `${parentPath}.${error.constraints[key]}`;
|
||||
}
|
||||
return {
|
||||
...error,
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
IsOptional,
|
||||
IsString,
|
||||
ValidateNested,
|
||||
IsArray,
|
||||
} from 'class-validator';
|
||||
import { HttpStatus } from '../../enums';
|
||||
import { UnprocessableEntityException } from '../../exceptions';
|
||||
@@ -156,6 +157,32 @@ describe('ValidationPipe', () => {
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
class TestModelForNestedArrayValidation {
|
||||
@IsString()
|
||||
public prop: string;
|
||||
|
||||
@IsArray()
|
||||
@ValidateNested()
|
||||
@Type(() => TestModel2)
|
||||
public test: TestModel2[];
|
||||
}
|
||||
it('should provide complete path for nested errors', async () => {
|
||||
try {
|
||||
const model = new TestModelForNestedArrayValidation();
|
||||
model.test = [new TestModel2()];
|
||||
await target.transform(model, {
|
||||
type: 'body',
|
||||
metatype: TestModelForNestedArrayValidation,
|
||||
});
|
||||
} catch (err) {
|
||||
expect(err.getResponse().message).to.be.eql([
|
||||
'prop must be a string',
|
||||
'test.0.prop1 must be a string',
|
||||
'test.0.prop2 must be a boolean value',
|
||||
]);
|
||||
}
|
||||
});
|
||||
});
|
||||
describe('when validation transforms', () => {
|
||||
it('should return a TestModel instance', async () => {
|
||||
|
||||
@@ -27,6 +27,12 @@ export const isPlainObject = (fn: any): fn is object => {
|
||||
export const addLeadingSlash = (path?: string): string =>
|
||||
path ? (path.charAt(0) !== '/' ? '/' + path : path) : '';
|
||||
|
||||
/**
|
||||
* Deprecated. Use the "addLeadingSlash" function instead.
|
||||
* @deprecated
|
||||
*/
|
||||
export const validatePath = addLeadingSlash;
|
||||
|
||||
export const isFunction = (fn: any): boolean => typeof fn === 'function';
|
||||
export const isString = (fn: any): fn is string => typeof fn === 'string';
|
||||
export const isConstructor = (fn: any): boolean => fn === 'constructor';
|
||||
|
||||
@@ -348,7 +348,7 @@ export class NestApplication
|
||||
}
|
||||
|
||||
private listenToPromise(microservice: INestMicroservice) {
|
||||
return new Promise(async resolve => {
|
||||
return new Promise<void>(async resolve => {
|
||||
await microservice.listen(resolve);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -215,10 +215,10 @@ export class NestFactoryStatic {
|
||||
}
|
||||
|
||||
private applyLogger(options: NestApplicationContextOptions | undefined) {
|
||||
if (!options) {
|
||||
if (!options || options?.logger === true || isNil(options?.logger)) {
|
||||
return;
|
||||
}
|
||||
!isNil(options.logger) && Logger.overrideLogger(options.logger);
|
||||
Logger.overrideLogger(options.logger);
|
||||
}
|
||||
|
||||
private createHttpAdapter<T = any>(httpServer?: T): AbstractHttpAdapter {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nestjs/core",
|
||||
"version": "7.5.5",
|
||||
"version": "7.6.1",
|
||||
"description": "Nest - modern, fast, powerful node.js web framework (@core)",
|
||||
"author": "Kamil Mysliwiec",
|
||||
"license": "MIT",
|
||||
@@ -33,14 +33,28 @@
|
||||
"object-hash": "2.0.3",
|
||||
"path-to-regexp": "3.2.0",
|
||||
"tslib": "2.0.3",
|
||||
"uuid": "8.3.1"
|
||||
"uuid": "8.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/common": "7.5.5"
|
||||
"@nestjs/common": "7.6.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@nestjs/common": "^7.0.0",
|
||||
"@nestjs/microservices": "^7.0.0",
|
||||
"@nestjs/platform-express": "^7.0.0",
|
||||
"@nestjs/websockets": "^7.0.0",
|
||||
"reflect-metadata": "^0.1.12",
|
||||
"rxjs": "^6.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@nestjs/websockets": {
|
||||
"optional": true
|
||||
},
|
||||
"@nestjs/microservices": {
|
||||
"optional": true
|
||||
},
|
||||
"@nestjs/platform-express": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ data: hello
|
||||
'Content-Type': 'text/event-stream',
|
||||
Connection: 'keep-alive',
|
||||
'Cache-Control':
|
||||
'private, no-cache, no-store, must-revalidate, max-age=0',
|
||||
'private, no-cache, no-store, must-revalidate, max-age=0, no-transform',
|
||||
'Transfer-Encoding': 'identity',
|
||||
Pragma: 'no-cache',
|
||||
Expire: '0',
|
||||
|
||||
@@ -8,7 +8,6 @@ import {
|
||||
} from '../constants';
|
||||
import { KafkaResponseDeserializer } from '../deserializers/kafka-response.deserializer';
|
||||
import { KafkaHeaders } from '../enums';
|
||||
import { InvalidKafkaClientTopicPartitionException } from '../errors/invalid-kafka-client-topic-partition.exception';
|
||||
import { InvalidKafkaClientTopicException } from '../errors/invalid-kafka-client-topic.exception';
|
||||
import {
|
||||
BrokersFunction,
|
||||
@@ -24,7 +23,7 @@ import {
|
||||
import {
|
||||
KafkaLogger,
|
||||
KafkaParser,
|
||||
KafkaRoundRobinPartitionAssigner,
|
||||
KafkaReplyPartitionAssigner,
|
||||
} from '../helpers';
|
||||
import {
|
||||
KafkaOptions,
|
||||
@@ -46,7 +45,7 @@ export class ClientKafka extends ClientProxy {
|
||||
protected producer: Producer = null;
|
||||
protected logger = new Logger(ClientKafka.name);
|
||||
protected responsePatterns: string[] = [];
|
||||
protected consumerAssignments: { [key: string]: number[] } = {};
|
||||
protected consumerAssignments: { [key: string]: number } = {};
|
||||
|
||||
protected brokers: string[] | BrokersFunction;
|
||||
protected clientId: string;
|
||||
@@ -59,17 +58,16 @@ export class ClientKafka extends ClientProxy {
|
||||
this.getOptionsProp(this.options, 'client') || ({} as KafkaConfig);
|
||||
const consumerOptions =
|
||||
this.getOptionsProp(this.options, 'consumer') || ({} as ConsumerConfig);
|
||||
const postfixId =
|
||||
this.getOptionsProp(this.options, 'postfixId') || '-client';
|
||||
|
||||
this.brokers = clientOptions.brokers || [KAFKA_DEFAULT_BROKER];
|
||||
|
||||
// Append a unique id to the clientId and groupId
|
||||
// so they don't collide with a microservices client
|
||||
this.clientId =
|
||||
(clientOptions.clientId || KAFKA_DEFAULT_CLIENT) +
|
||||
(clientOptions.clientIdPostfix || '-client');
|
||||
this.groupId =
|
||||
(consumerOptions.groupId || KAFKA_DEFAULT_GROUP) +
|
||||
(clientOptions.clientIdPostfix || '-client');
|
||||
(clientOptions.clientId || KAFKA_DEFAULT_CLIENT) + postfixId;
|
||||
this.groupId = (consumerOptions.groupId || KAFKA_DEFAULT_GROUP) + postfixId;
|
||||
|
||||
kafkaPackage = loadPackage('kafkajs', ClientKafka.name, () =>
|
||||
require('kafkajs'),
|
||||
@@ -99,11 +97,8 @@ export class ClientKafka extends ClientProxy {
|
||||
this.client = this.createClient();
|
||||
|
||||
const partitionAssigners = [
|
||||
(
|
||||
config: ConstructorParameters<
|
||||
typeof KafkaRoundRobinPartitionAssigner
|
||||
>[0],
|
||||
) => new KafkaRoundRobinPartitionAssigner(config),
|
||||
(config: ConstructorParameters<typeof KafkaReplyPartitionAssigner>[1]) =>
|
||||
new KafkaReplyPartitionAssigner(this, config),
|
||||
] as any[];
|
||||
|
||||
const consumerOptions = Object.assign(
|
||||
@@ -188,6 +183,10 @@ export class ClientKafka extends ClientProxy {
|
||||
};
|
||||
}
|
||||
|
||||
public getConsumerAssignments() {
|
||||
return this.consumerAssignments;
|
||||
}
|
||||
|
||||
protected dispatchEvent(packet: OutgoingEvent): Promise<any> {
|
||||
const pattern = this.normalizePattern(packet.pattern);
|
||||
const outgoingEvent = this.serializer.serialize(packet.data);
|
||||
@@ -202,17 +201,13 @@ export class ClientKafka extends ClientProxy {
|
||||
}
|
||||
|
||||
protected getReplyTopicPartition(topic: string): string {
|
||||
const topicAssignments = this.consumerAssignments[topic];
|
||||
if (isUndefined(topicAssignments)) {
|
||||
const minimumPartition = this.consumerAssignments[topic];
|
||||
if (isUndefined(minimumPartition)) {
|
||||
throw new InvalidKafkaClientTopicException(topic);
|
||||
}
|
||||
|
||||
// if the current member isn't listening to
|
||||
// any partitions on the topic then throw an error.
|
||||
if (isUndefined(topicAssignments[0])) {
|
||||
throw new InvalidKafkaClientTopicPartitionException(topic);
|
||||
}
|
||||
return topicAssignments[0].toString();
|
||||
// get the minimum partition
|
||||
return minimumPartition.toString();
|
||||
}
|
||||
|
||||
protected publish(
|
||||
@@ -254,7 +249,18 @@ export class ClientKafka extends ClientProxy {
|
||||
}
|
||||
|
||||
protected setConsumerAssignments(data: ConsumerGroupJoinEvent): void {
|
||||
this.consumerAssignments = data.payload.memberAssignment;
|
||||
const consumerAssignments: { [key: string]: number } = {};
|
||||
|
||||
// only need to set the minimum
|
||||
Object.keys(data.payload.memberAssignment).forEach(memberId => {
|
||||
const minimumPartition = Math.min(
|
||||
...data.payload.memberAssignment[memberId],
|
||||
);
|
||||
|
||||
consumerAssignments[memberId] = minimumPartition;
|
||||
});
|
||||
|
||||
this.consumerAssignments = consumerAssignments;
|
||||
}
|
||||
|
||||
protected initializeSerializer(options: KafkaOptions['options']) {
|
||||
|
||||
@@ -157,7 +157,7 @@ export class ClientMqtt extends ClientProxy {
|
||||
const pattern = this.normalizePattern(packet.pattern);
|
||||
const serializedPacket = this.serializer.serialize(packet);
|
||||
|
||||
return new Promise((resolve, reject) =>
|
||||
return new Promise<void>((resolve, reject) =>
|
||||
this.mqttClient.publish(pattern, JSON.stringify(serializedPacket), err =>
|
||||
err ? reject(err) : resolve(),
|
||||
),
|
||||
|
||||
@@ -111,7 +111,7 @@ export class ClientNats extends ClientProxy {
|
||||
const pattern = this.normalizePattern(packet.pattern);
|
||||
const serializedPacket = this.serializer.serialize(packet);
|
||||
|
||||
return new Promise((resolve, reject) =>
|
||||
return new Promise<void>((resolve, reject) =>
|
||||
this.natsClient.publish(pattern, serializedPacket as any, err =>
|
||||
err ? reject(err) : resolve(),
|
||||
),
|
||||
|
||||
@@ -190,7 +190,7 @@ export class ClientRedis extends ClientProxy {
|
||||
const pattern = this.normalizePattern(packet.pattern);
|
||||
const serializedPacket = this.serializer.serialize(packet);
|
||||
|
||||
return new Promise((resolve, reject) =>
|
||||
return new Promise<void>((resolve, reject) =>
|
||||
this.pubClient.publish(pattern, JSON.stringify(serializedPacket), err =>
|
||||
err ? reject(err) : resolve(),
|
||||
),
|
||||
|
||||
@@ -16,9 +16,9 @@ import {
|
||||
RQM_DEFAULT_QUEUE_OPTIONS,
|
||||
RQM_DEFAULT_URL,
|
||||
} from '../constants';
|
||||
import { RmqUrl } from '../external/rmq-url.interface';
|
||||
import { ReadPacket, RmqOptions, WritePacket } from '../interfaces';
|
||||
import { ClientProxy } from './client-proxy';
|
||||
import { RmqUrl } from '../external/rmq-url.interface';
|
||||
|
||||
let rqmPackage: any = {};
|
||||
|
||||
@@ -204,14 +204,14 @@ export class ClientRMQ extends ClientProxy {
|
||||
protected dispatchEvent(packet: ReadPacket): Promise<any> {
|
||||
const serializedPacket = this.serializer.serialize(packet);
|
||||
|
||||
return new Promise((resolve, reject) =>
|
||||
return new Promise<void>((resolve, reject) =>
|
||||
this.channel.sendToQueue(
|
||||
this.queue,
|
||||
Buffer.from(JSON.stringify(serializedPacket)),
|
||||
{
|
||||
persistent: this.persistent,
|
||||
},
|
||||
err => (err ? reject(err) : resolve()),
|
||||
(err: unknown) => (err ? reject(err) : resolve()),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
import { RuntimeException } from '@nestjs/core/errors/exceptions/runtime.exception';
|
||||
|
||||
export class InvalidKafkaClientTopicPartitionException extends RuntimeException {
|
||||
constructor(topic?: string) {
|
||||
super(
|
||||
`The client consumer subscribed to the topic (${topic}) which is not assigned to any partitions.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,931 +0,0 @@
|
||||
/// <reference types="node" />
|
||||
|
||||
import * as net from 'net';
|
||||
import * as tls from 'tls';
|
||||
|
||||
type Without<T, U> = { [P in Exclude<keyof T, keyof U>]?: never };
|
||||
type XOR<T, U> = T | U extends object
|
||||
? (Without<T, U> & U) | (Without<U, T> & T)
|
||||
: T | U;
|
||||
|
||||
export declare class Kafka {
|
||||
constructor(config: KafkaConfig);
|
||||
producer(config?: ProducerConfig): Producer;
|
||||
consumer(config?: ConsumerConfig): Consumer;
|
||||
admin(config?: AdminConfig): Admin;
|
||||
logger(): Logger;
|
||||
}
|
||||
|
||||
export type BrokersFunction = () => string[] | Promise<string[]>;
|
||||
|
||||
export interface KafkaConfig {
|
||||
brokers: string[] | BrokersFunction;
|
||||
ssl?: tls.ConnectionOptions | boolean;
|
||||
sasl?: SASLOptions;
|
||||
clientId?: string;
|
||||
clientIdPostfix?: string;
|
||||
connectionTimeout?: number;
|
||||
authenticationTimeout?: number;
|
||||
reauthenticationThreshold?: number;
|
||||
requestTimeout?: number;
|
||||
enforceRequestTimeout?: boolean;
|
||||
retry?: RetryOptions;
|
||||
socketFactory?: ISocketFactory;
|
||||
logLevel?: logLevel;
|
||||
logCreator?: logCreator;
|
||||
}
|
||||
|
||||
export type ISocketFactory = (
|
||||
host: string,
|
||||
port: number,
|
||||
ssl: tls.ConnectionOptions,
|
||||
onConnect: () => void,
|
||||
) => net.Socket;
|
||||
|
||||
export type SASLMechanism = 'plain' | 'scram-sha-256' | 'scram-sha-512' | 'aws';
|
||||
|
||||
export interface SASLOptions {
|
||||
mechanism: SASLMechanism;
|
||||
username: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
export interface ProducerConfig {
|
||||
createPartitioner?: ICustomPartitioner;
|
||||
retry?: RetryOptions;
|
||||
metadataMaxAge?: number;
|
||||
allowAutoTopicCreation?: boolean;
|
||||
idempotent?: boolean;
|
||||
transactionalId?: string;
|
||||
transactionTimeout?: number;
|
||||
maxInFlightRequests?: number;
|
||||
}
|
||||
|
||||
export interface Message {
|
||||
key?: Buffer | string | null;
|
||||
value: Buffer | string | null;
|
||||
partition?: number;
|
||||
headers?: IHeaders;
|
||||
timestamp?: string;
|
||||
}
|
||||
|
||||
export interface PartitionerArgs {
|
||||
topic: string;
|
||||
partitionMetadata: PartitionMetadata[];
|
||||
message: Message;
|
||||
}
|
||||
|
||||
export type ICustomPartitioner = () => (args: PartitionerArgs) => number;
|
||||
export type DefaultPartitioner = ICustomPartitioner;
|
||||
export type JavaCompatiblePartitioner = ICustomPartitioner;
|
||||
|
||||
export let Partitioners: {
|
||||
DefaultPartitioner: DefaultPartitioner;
|
||||
JavaCompatiblePartitioner: JavaCompatiblePartitioner;
|
||||
};
|
||||
|
||||
export type PartitionMetadata = {
|
||||
partitionErrorCode: number;
|
||||
partitionId: number;
|
||||
leader: number;
|
||||
replicas: number[];
|
||||
isr: number[];
|
||||
offlineReplicas?: number[];
|
||||
};
|
||||
|
||||
export interface IHeaders {
|
||||
[key: string]: Buffer | string;
|
||||
}
|
||||
|
||||
export interface ConsumerConfig {
|
||||
groupId: string;
|
||||
partitionAssigners?: PartitionAssigner[];
|
||||
metadataMaxAge?: number;
|
||||
sessionTimeout?: number;
|
||||
rebalanceTimeout?: number;
|
||||
heartbeatInterval?: number;
|
||||
maxBytesPerPartition?: number;
|
||||
minBytes?: number;
|
||||
maxBytes?: number;
|
||||
maxWaitTimeInMs?: number;
|
||||
retry?: RetryOptions & {
|
||||
restartOnFailure?: (err: Error) => Promise<boolean>;
|
||||
};
|
||||
allowAutoTopicCreation?: boolean;
|
||||
maxInFlightRequests?: number;
|
||||
readUncommitted?: boolean;
|
||||
rackId?: string;
|
||||
}
|
||||
|
||||
export type PartitionAssigner = (config: { cluster: Cluster }) => Assigner;
|
||||
|
||||
export interface CoordinatorMetadata {
|
||||
errorCode: number;
|
||||
coordinator: {
|
||||
nodeId: number;
|
||||
host: string;
|
||||
port: number;
|
||||
};
|
||||
}
|
||||
|
||||
export type Cluster = {
|
||||
isConnected(): boolean;
|
||||
connect(): Promise<void>;
|
||||
disconnect(): Promise<void>;
|
||||
refreshMetadata(): Promise<void>;
|
||||
refreshMetadataIfNecessary(): Promise<void>;
|
||||
addTargetTopic(topic: string): Promise<void>;
|
||||
findBroker(node: { nodeId: string }): Promise<Broker>;
|
||||
findControllerBroker(): Promise<Broker>;
|
||||
findTopicPartitionMetadata(topic: string): PartitionMetadata[];
|
||||
findLeaderForPartitions(
|
||||
topic: string,
|
||||
partitions: number[],
|
||||
): { [leader: string]: number[] };
|
||||
findGroupCoordinator(group: { groupId: string }): Promise<Broker>;
|
||||
findGroupCoordinatorMetadata(group: {
|
||||
groupId: string;
|
||||
}): Promise<CoordinatorMetadata>;
|
||||
defaultOffset(config: { fromBeginning: boolean }): number;
|
||||
fetchTopicsOffset(
|
||||
topics: Array<
|
||||
{
|
||||
topic: string;
|
||||
partitions: Array<{ partition: number }>;
|
||||
} & XOR<{ fromBeginning: boolean }, { fromTimestamp: number }>
|
||||
>,
|
||||
): Promise<{
|
||||
topic: string;
|
||||
partitions: Array<{ partition: number; offset: string }>;
|
||||
}>;
|
||||
};
|
||||
|
||||
export type Assignment = { [topic: string]: number[] };
|
||||
|
||||
export type GroupMember = { memberId: string; memberMetadata: Buffer };
|
||||
|
||||
export type GroupMemberAssignment = {
|
||||
memberId: string;
|
||||
memberAssignment: Buffer;
|
||||
};
|
||||
|
||||
export type GroupState = { name: string; metadata: Buffer };
|
||||
|
||||
export type Assigner = {
|
||||
name: string;
|
||||
version: number;
|
||||
assign(group: {
|
||||
members: GroupMember[];
|
||||
topics: string[];
|
||||
}): Promise<GroupMemberAssignment[]>;
|
||||
protocol(subscription: { topics: string[] }): GroupState;
|
||||
};
|
||||
|
||||
export interface RetryOptions {
|
||||
maxRetryTime?: number;
|
||||
initialRetryTime?: number;
|
||||
factor?: number;
|
||||
multiplier?: number;
|
||||
retries?: number;
|
||||
}
|
||||
|
||||
export interface AdminConfig {
|
||||
retry?: RetryOptions;
|
||||
}
|
||||
|
||||
export interface ITopicConfig {
|
||||
topic: string;
|
||||
numPartitions?: number;
|
||||
replicationFactor?: number;
|
||||
replicaAssignment?: object[];
|
||||
configEntries?: object[];
|
||||
}
|
||||
|
||||
export interface ITopicPartitionConfig {
|
||||
topic: string;
|
||||
count: number;
|
||||
assignments?: Array<Array<number>>;
|
||||
}
|
||||
|
||||
export interface ITopicMetadata {
|
||||
name: string;
|
||||
partitions: PartitionMetadata[];
|
||||
}
|
||||
|
||||
export enum ResourceTypes {
|
||||
UNKNOWN = 0,
|
||||
ANY = 1,
|
||||
TOPIC = 2,
|
||||
GROUP = 3,
|
||||
CLUSTER = 4,
|
||||
TRANSACTIONAL_ID = 5,
|
||||
DELEGATION_TOKEN = 6,
|
||||
}
|
||||
|
||||
export interface ResourceConfigQuery {
|
||||
type: ResourceTypes;
|
||||
name: string;
|
||||
configNames?: string[];
|
||||
}
|
||||
|
||||
export interface ConfigEntries {
|
||||
configName: string;
|
||||
configValue: string;
|
||||
isDefault: boolean;
|
||||
isSensitive: boolean;
|
||||
readOnly: boolean;
|
||||
configSynonyms: ConfigSynonyms[];
|
||||
}
|
||||
|
||||
export interface ConfigSynonyms {
|
||||
configName: string;
|
||||
configValue: string;
|
||||
configSource: number;
|
||||
}
|
||||
|
||||
export interface DescribeConfigResponse {
|
||||
resources: {
|
||||
configEntries: ConfigEntries[];
|
||||
errorCode: number;
|
||||
errorMessage: string;
|
||||
resourceName: string;
|
||||
resourceType: ResourceTypes;
|
||||
}[];
|
||||
throttleTime: number;
|
||||
}
|
||||
|
||||
export interface IResourceConfig {
|
||||
type: ResourceTypes;
|
||||
name: string;
|
||||
configEntries: { name: string; value: string }[];
|
||||
}
|
||||
|
||||
type ValueOf<T> = T[keyof T];
|
||||
|
||||
export type AdminEvents = {
|
||||
CONNECT: 'admin.connect';
|
||||
DISCONNECT: 'admin.disconnect';
|
||||
REQUEST: 'admin.network.request';
|
||||
REQUEST_TIMEOUT: 'admin.network.request_timeout';
|
||||
REQUEST_QUEUE_SIZE: 'admin.network.request_queue_size';
|
||||
};
|
||||
|
||||
export interface InstrumentationEvent<T> {
|
||||
id: string;
|
||||
type: string;
|
||||
timestamp: number;
|
||||
payload: T;
|
||||
}
|
||||
|
||||
export type RemoveInstrumentationEventListener<T> = () => void;
|
||||
|
||||
export type ConnectEvent = InstrumentationEvent<null>;
|
||||
export type DisconnectEvent = InstrumentationEvent<null>;
|
||||
export type RequestEvent = InstrumentationEvent<{
|
||||
apiKey: number;
|
||||
apiName: string;
|
||||
apiVersion: number;
|
||||
broker: string;
|
||||
clientId: string;
|
||||
correlationId: number;
|
||||
createdAt: number;
|
||||
duration: number;
|
||||
pendingDuration: number;
|
||||
sentAt: number;
|
||||
size: number;
|
||||
}>;
|
||||
export type RequestTimeoutEvent = InstrumentationEvent<{
|
||||
apiKey: number;
|
||||
apiName: string;
|
||||
apiVersion: number;
|
||||
broker: string;
|
||||
clientId: string;
|
||||
correlationId: number;
|
||||
createdAt: number;
|
||||
pendingDuration: number;
|
||||
sentAt: number;
|
||||
}>;
|
||||
export type RequestQueueSizeEvent = InstrumentationEvent<{
|
||||
broker: string;
|
||||
clientId: string;
|
||||
queueSize: number;
|
||||
}>;
|
||||
|
||||
export interface SeekEntry {
|
||||
partition: number;
|
||||
offset: string;
|
||||
}
|
||||
|
||||
export type Admin = {
|
||||
connect(): Promise<void>;
|
||||
disconnect(): Promise<void>;
|
||||
listTopics(): Promise<string[]>;
|
||||
createTopics(options: {
|
||||
validateOnly?: boolean;
|
||||
waitForLeaders?: boolean;
|
||||
timeout?: number;
|
||||
topics: ITopicConfig[];
|
||||
}): Promise<boolean>;
|
||||
deleteTopics(options: { topics: string[]; timeout?: number }): Promise<void>;
|
||||
createPartitions(options: {
|
||||
validateOnly?: boolean;
|
||||
timeout?: number;
|
||||
topicPartitions: ITopicPartitionConfig[];
|
||||
}): Promise<boolean>;
|
||||
fetchTopicMetadata(options?: {
|
||||
topics: string[];
|
||||
}): Promise<{ topics: Array<ITopicMetadata> }>;
|
||||
fetchOffsets(options: {
|
||||
groupId: string;
|
||||
topic: string;
|
||||
}): Promise<Array<SeekEntry & { metadata: string | null }>>;
|
||||
fetchTopicOffsets(
|
||||
topic: string,
|
||||
): Promise<Array<SeekEntry & { high: string; low: string }>>;
|
||||
fetchTopicOffsetsByTimestamp(
|
||||
topic: string,
|
||||
timestamp?: number,
|
||||
): Promise<Array<SeekEntry>>;
|
||||
describeCluster(): Promise<{
|
||||
brokers: Array<{ nodeId: number; host: string; port: number }>;
|
||||
controller: number | null;
|
||||
clusterId: string;
|
||||
}>;
|
||||
setOffsets(options: {
|
||||
groupId: string;
|
||||
topic: string;
|
||||
partitions: SeekEntry[];
|
||||
}): Promise<void>;
|
||||
resetOffsets(options: {
|
||||
groupId: string;
|
||||
topic: string;
|
||||
earliest: boolean;
|
||||
}): Promise<void>;
|
||||
describeConfigs(configs: {
|
||||
resources: ResourceConfigQuery[];
|
||||
includeSynonyms: boolean;
|
||||
}): Promise<DescribeConfigResponse>;
|
||||
alterConfigs(configs: {
|
||||
validateOnly: boolean;
|
||||
resources: IResourceConfig[];
|
||||
}): Promise<any>;
|
||||
listGroups(): Promise<{ groups: GroupOverview[] }>;
|
||||
deleteGroups(groupIds: string[]): Promise<DeleteGroupsResult[]>;
|
||||
describeGroups(groupIds: string[]): Promise<GroupDescriptions>;
|
||||
logger(): Logger;
|
||||
on(
|
||||
eventName: ValueOf<AdminEvents>,
|
||||
listener: (...args: any[]) => void,
|
||||
): RemoveInstrumentationEventListener<typeof eventName>;
|
||||
events: AdminEvents;
|
||||
};
|
||||
|
||||
export let PartitionAssigners: { roundRobin: PartitionAssigner };
|
||||
|
||||
export interface ISerializer<T> {
|
||||
encode(value: T): Buffer;
|
||||
decode(buffer: Buffer): T | null;
|
||||
}
|
||||
|
||||
export type MemberMetadata = {
|
||||
version: number;
|
||||
topics: string[];
|
||||
userData: Buffer;
|
||||
};
|
||||
|
||||
export type MemberAssignment = {
|
||||
version: number;
|
||||
assignment: Assignment;
|
||||
userData: Buffer;
|
||||
};
|
||||
|
||||
export let AssignerProtocol: {
|
||||
MemberMetadata: ISerializer<MemberMetadata>;
|
||||
MemberAssignment: ISerializer<MemberAssignment>;
|
||||
};
|
||||
|
||||
export enum logLevel {
|
||||
NOTHING = 0,
|
||||
ERROR = 1,
|
||||
WARN = 2,
|
||||
INFO = 4,
|
||||
DEBUG = 5,
|
||||
}
|
||||
|
||||
export interface LogEntry {
|
||||
namespace: string;
|
||||
level: logLevel;
|
||||
label: string;
|
||||
log: LoggerEntryContent;
|
||||
}
|
||||
|
||||
export interface LoggerEntryContent {
|
||||
readonly timestamp: Date;
|
||||
readonly message: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export type logCreator = (logLevel: logLevel) => (entry: LogEntry) => void;
|
||||
|
||||
export type Logger = {
|
||||
info: (message: string, extra?: object) => void;
|
||||
error: (message: string, extra?: object) => void;
|
||||
warn: (message: string, extra?: object) => void;
|
||||
debug: (message: string, extra?: object) => void;
|
||||
};
|
||||
|
||||
export type Broker = {
|
||||
isConnected(): boolean;
|
||||
connect(): Promise<void>;
|
||||
disconnect(): Promise<void>;
|
||||
apiVersions(): Promise<{
|
||||
[apiKey: number]: { minVersion: number; maxVersion: number };
|
||||
}>;
|
||||
metadata(
|
||||
topics: string[],
|
||||
): Promise<{
|
||||
brokers: Array<{
|
||||
nodeId: number;
|
||||
host: string;
|
||||
port: number;
|
||||
rack?: string;
|
||||
}>;
|
||||
topicMetadata: Array<{
|
||||
topicErrorCode: number;
|
||||
topic: number;
|
||||
partitionMetadata: PartitionMetadata[];
|
||||
}>;
|
||||
}>;
|
||||
offsetCommit(request: {
|
||||
groupId: string;
|
||||
groupGenerationId: number;
|
||||
memberId: string;
|
||||
retentionTime?: number;
|
||||
topics: Array<{
|
||||
topic: string;
|
||||
partitions: Array<{ partition: number; offset: string }>;
|
||||
}>;
|
||||
}): Promise<any>;
|
||||
fetch(request: {
|
||||
replicaId?: number;
|
||||
isolationLevel?: number;
|
||||
maxWaitTime?: number;
|
||||
minBytes?: number;
|
||||
maxBytes?: number;
|
||||
topics: Array<{
|
||||
topic: string;
|
||||
partitions: Array<{
|
||||
partition: number;
|
||||
fetchOffset: string;
|
||||
maxBytes: number;
|
||||
}>;
|
||||
}>;
|
||||
rackId?: string;
|
||||
}): Promise<any>;
|
||||
};
|
||||
|
||||
export type KafkaMessage = {
|
||||
key: Buffer;
|
||||
value: Buffer | null;
|
||||
timestamp: string;
|
||||
size: number;
|
||||
attributes: number;
|
||||
offset: string;
|
||||
headers?: IHeaders;
|
||||
};
|
||||
|
||||
export interface ProducerRecord {
|
||||
topic: string;
|
||||
messages: Message[];
|
||||
acks?: number;
|
||||
timeout?: number;
|
||||
compression?: CompressionTypes;
|
||||
}
|
||||
|
||||
export type RecordMetadata = {
|
||||
topicName: string;
|
||||
partition: number;
|
||||
errorCode: number;
|
||||
offset: string;
|
||||
timestamp: string;
|
||||
};
|
||||
|
||||
export interface TopicMessages {
|
||||
topic: string;
|
||||
messages: Message[];
|
||||
}
|
||||
|
||||
export interface ProducerBatch {
|
||||
acks?: number;
|
||||
timeout?: number;
|
||||
compression?: CompressionTypes;
|
||||
topicMessages?: TopicMessages[];
|
||||
}
|
||||
|
||||
export interface PartitionOffset {
|
||||
partition: number;
|
||||
offset: string;
|
||||
}
|
||||
|
||||
export interface TopicOffsets {
|
||||
topic: string;
|
||||
partitions: PartitionOffset[];
|
||||
}
|
||||
|
||||
export interface Offsets {
|
||||
topics: TopicOffsets[];
|
||||
}
|
||||
|
||||
type Sender = {
|
||||
send(record: ProducerRecord): Promise<RecordMetadata[]>;
|
||||
sendBatch(batch: ProducerBatch): Promise<RecordMetadata[]>;
|
||||
};
|
||||
|
||||
export type ProducerEvents = {
|
||||
CONNECT: 'producer.connect';
|
||||
DISCONNECT: 'producer.disconnect';
|
||||
REQUEST: 'producer.network.request';
|
||||
REQUEST_TIMEOUT: 'producer.network.request_timeout';
|
||||
REQUEST_QUEUE_SIZE: 'producer.network.request_queue_size';
|
||||
};
|
||||
|
||||
export type Producer = Sender & {
|
||||
connect(): Promise<void>;
|
||||
disconnect(): Promise<void>;
|
||||
isIdempotent(): boolean;
|
||||
events: ProducerEvents;
|
||||
on(
|
||||
eventName: ValueOf<ProducerEvents>,
|
||||
listener: (...args: any[]) => void,
|
||||
): RemoveInstrumentationEventListener<typeof eventName>;
|
||||
transaction(): Promise<Transaction>;
|
||||
logger(): Logger;
|
||||
};
|
||||
|
||||
export type Transaction = Sender & {
|
||||
sendOffsets(offsets: Offsets & { consumerGroupId: string }): Promise<void>;
|
||||
commit(): Promise<void>;
|
||||
abort(): Promise<void>;
|
||||
isActive(): boolean;
|
||||
};
|
||||
|
||||
export type ConsumerGroup = {
|
||||
groupId: string;
|
||||
generationId: number;
|
||||
memberId: string;
|
||||
coordinator: Broker;
|
||||
};
|
||||
|
||||
export type MemberDescription = {
|
||||
clientHost: string;
|
||||
clientId: string;
|
||||
memberId: string;
|
||||
memberAssignment: Buffer;
|
||||
memberMetadata: Buffer;
|
||||
};
|
||||
|
||||
export type GroupDescription = {
|
||||
groupId: string;
|
||||
members: MemberDescription[];
|
||||
protocol: string;
|
||||
protocolType: string;
|
||||
state: string;
|
||||
};
|
||||
|
||||
export type GroupDescriptions = {
|
||||
groups: GroupDescription[];
|
||||
};
|
||||
|
||||
export type TopicPartitions = { topic: string; partitions: number[] };
|
||||
export type TopicPartitionOffsetAndMetadata = {
|
||||
topic: string;
|
||||
partition: number;
|
||||
offset: string;
|
||||
metadata?: string | null;
|
||||
};
|
||||
|
||||
// TODO: Remove with 2.x
|
||||
export type TopicPartitionOffsetAndMedata = TopicPartitionOffsetAndMetadata;
|
||||
|
||||
export type Batch = {
|
||||
topic: string;
|
||||
partition: number;
|
||||
highWatermark: string;
|
||||
messages: KafkaMessage[];
|
||||
isEmpty(): boolean;
|
||||
firstOffset(): string | null;
|
||||
lastOffset(): string;
|
||||
offsetLag(): string;
|
||||
offsetLagLow(): string;
|
||||
};
|
||||
|
||||
export type GroupOverview = {
|
||||
groupId: string;
|
||||
protocolType: string;
|
||||
};
|
||||
|
||||
export type DeleteGroupsResult = {
|
||||
groupId: string;
|
||||
errorCode?: number;
|
||||
};
|
||||
|
||||
export type ConsumerEvents = {
|
||||
HEARTBEAT: 'consumer.heartbeat';
|
||||
COMMIT_OFFSETS: 'consumer.commit_offsets';
|
||||
GROUP_JOIN: 'consumer.group_join';
|
||||
FETCH_START: 'consumer.fetch_start';
|
||||
FETCH: 'consumer.fetch';
|
||||
START_BATCH_PROCESS: 'consumer.start_batch_process';
|
||||
END_BATCH_PROCESS: 'consumer.end_batch_process';
|
||||
CONNECT: 'consumer.connect';
|
||||
DISCONNECT: 'consumer.disconnect';
|
||||
STOP: 'consumer.stop';
|
||||
CRASH: 'consumer.crash';
|
||||
REQUEST: 'consumer.network.request';
|
||||
REQUEST_TIMEOUT: 'consumer.network.request_timeout';
|
||||
REQUEST_QUEUE_SIZE: 'consumer.network.request_queue_size';
|
||||
};
|
||||
export type ConsumerHeartbeatEvent = InstrumentationEvent<{
|
||||
groupId: string;
|
||||
memberId: string;
|
||||
groupGenerationId: number;
|
||||
}>;
|
||||
export type ConsumerCommitOffsetsEvent = InstrumentationEvent<{
|
||||
groupId: string;
|
||||
memberId: string;
|
||||
groupGenerationId: number;
|
||||
topics: {
|
||||
topic: string;
|
||||
partitions: {
|
||||
offset: string;
|
||||
partition: string;
|
||||
}[];
|
||||
}[];
|
||||
}>;
|
||||
export interface IMemberAssignment {
|
||||
[key: string]: number[];
|
||||
}
|
||||
export type ConsumerGroupJoinEvent = InstrumentationEvent<{
|
||||
duration: number;
|
||||
groupId: string;
|
||||
isLeader: boolean;
|
||||
leaderId: string;
|
||||
groupProtocol: string;
|
||||
memberId: string;
|
||||
memberAssignment: IMemberAssignment;
|
||||
}>;
|
||||
export type ConsumerFetchEvent = InstrumentationEvent<{
|
||||
numberOfBatches: number;
|
||||
duration: number;
|
||||
}>;
|
||||
interface IBatchProcessEvent {
|
||||
topic: string;
|
||||
partition: number;
|
||||
highWatermark: string;
|
||||
offsetLag: string;
|
||||
offsetLagLow: string;
|
||||
batchSize: number;
|
||||
firstOffset: string;
|
||||
lastOffset: string;
|
||||
}
|
||||
export type ConsumerStartBatchProcessEvent = InstrumentationEvent<
|
||||
IBatchProcessEvent
|
||||
>;
|
||||
export type ConsumerEndBatchProcessEvent = InstrumentationEvent<
|
||||
IBatchProcessEvent & { duration: number }
|
||||
>;
|
||||
export type ConsumerCrashEvent = InstrumentationEvent<{
|
||||
error: Error;
|
||||
groupId: string;
|
||||
}>;
|
||||
|
||||
export interface OffsetsByTopicPartition {
|
||||
topics: TopicOffsets[];
|
||||
}
|
||||
|
||||
export interface EachMessagePayload {
|
||||
topic: string;
|
||||
partition: number;
|
||||
message: KafkaMessage;
|
||||
}
|
||||
|
||||
export interface EachBatchPayload {
|
||||
batch: Batch;
|
||||
resolveOffset(offset: string): void;
|
||||
heartbeat(): Promise<void>;
|
||||
commitOffsetsIfNecessary(offsets?: Offsets): Promise<void>;
|
||||
uncommittedOffsets(): OffsetsByTopicPartition;
|
||||
isRunning(): boolean;
|
||||
isStale(): boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Type alias to keep compatibility with @types/kafkajs
|
||||
* @see https://github.com/DefinitelyTyped/DefinitelyTyped/blob/712ad9d59ccca6a3cc92f347fea0d1c7b02f5eeb/types/kafkajs/index.d.ts#L321-L325
|
||||
*/
|
||||
export type ConsumerEachMessagePayload = EachMessagePayload;
|
||||
|
||||
/**
|
||||
* Type alias to keep compatibility with @types/kafkajs
|
||||
* @see https://github.com/DefinitelyTyped/DefinitelyTyped/blob/712ad9d59ccca6a3cc92f347fea0d1c7b02f5eeb/types/kafkajs/index.d.ts#L327-L336
|
||||
*/
|
||||
export type ConsumerEachBatchPayload = EachBatchPayload;
|
||||
|
||||
export type ConsumerRunConfig = {
|
||||
autoCommit?: boolean;
|
||||
autoCommitInterval?: number | null;
|
||||
autoCommitThreshold?: number | null;
|
||||
eachBatchAutoResolve?: boolean;
|
||||
partitionsConsumedConcurrently?: number;
|
||||
eachBatch?: (payload: EachBatchPayload) => Promise<void>;
|
||||
eachMessage?: (payload: EachMessagePayload) => Promise<void>;
|
||||
};
|
||||
|
||||
export type ConsumerSubscribeTopic = {
|
||||
topic: string | RegExp;
|
||||
fromBeginning?: boolean;
|
||||
};
|
||||
|
||||
export type Consumer = {
|
||||
connect(): Promise<void>;
|
||||
disconnect(): Promise<void>;
|
||||
subscribe(topic: ConsumerSubscribeTopic): Promise<void>;
|
||||
stop(): Promise<void>;
|
||||
run(config?: ConsumerRunConfig): Promise<void>;
|
||||
commitOffsets(
|
||||
topicPartitions: Array<TopicPartitionOffsetAndMetadata>,
|
||||
): Promise<void>;
|
||||
seek(topicPartition: {
|
||||
topic: string;
|
||||
partition: number;
|
||||
offset: string;
|
||||
}): void;
|
||||
describeGroup(): Promise<GroupDescription>;
|
||||
pause(topics: Array<{ topic: string; partitions?: number[] }>): void;
|
||||
paused(): TopicPartitions[];
|
||||
resume(topics: Array<{ topic: string; partitions?: number[] }>): void;
|
||||
on(
|
||||
eventName: ValueOf<ConsumerEvents>,
|
||||
listener: (...args: any[]) => void,
|
||||
): RemoveInstrumentationEventListener<typeof eventName>;
|
||||
logger(): Logger;
|
||||
events: ConsumerEvents;
|
||||
};
|
||||
|
||||
export enum CompressionTypes {
|
||||
None = 0,
|
||||
GZIP = 1,
|
||||
Snappy = 2,
|
||||
LZ4 = 3,
|
||||
ZSTD = 4,
|
||||
}
|
||||
|
||||
export let CompressionCodecs: {
|
||||
[CompressionTypes.GZIP]: () => any;
|
||||
[CompressionTypes.Snappy]: () => any;
|
||||
[CompressionTypes.LZ4]: () => any;
|
||||
[CompressionTypes.ZSTD]: () => any;
|
||||
};
|
||||
|
||||
export declare class KafkaJSError extends Error {
|
||||
constructor(e: Error | string, metadata?: KafkaJSErrorMetadata);
|
||||
}
|
||||
|
||||
export declare class KafkaJSNonRetriableError extends KafkaJSError {
|
||||
constructor(e: Error | string);
|
||||
}
|
||||
|
||||
export declare class KafkaJSProtocolError extends KafkaJSError {
|
||||
constructor(e: Error | string);
|
||||
}
|
||||
|
||||
export declare class KafkaJSOffsetOutOfRange extends KafkaJSProtocolError {
|
||||
constructor(e: Error | string, metadata?: KafkaJSOffsetOutOfRangeMetadata);
|
||||
}
|
||||
|
||||
export declare class KafkaJSNumberOfRetriesExceeded extends KafkaJSNonRetriableError {
|
||||
constructor(
|
||||
e: Error | string,
|
||||
metadata?: KafkaJSNumberOfRetriesExceededMetadata,
|
||||
);
|
||||
}
|
||||
|
||||
export declare class KafkaJSConnectionError extends KafkaJSError {
|
||||
constructor(e: Error | string, metadata?: KafkaJSConnectionErrorMetadata);
|
||||
}
|
||||
|
||||
export declare class KafkaJSRequestTimeoutError extends KafkaJSError {
|
||||
constructor(e: Error | string, metadata?: KafkaJSRequestTimeoutErrorMetadata);
|
||||
}
|
||||
|
||||
export declare class KafkaJSMetadataNotLoaded extends KafkaJSError {
|
||||
constructor();
|
||||
}
|
||||
|
||||
export declare class KafkaJSTopicMetadataNotLoaded extends KafkaJSMetadataNotLoaded {
|
||||
constructor(
|
||||
e: Error | string,
|
||||
metadata?: KafkaJSTopicMetadataNotLoadedMetadata,
|
||||
);
|
||||
}
|
||||
|
||||
export declare class KafkaJSStaleTopicMetadataAssignment extends KafkaJSError {
|
||||
constructor(
|
||||
e: Error | string,
|
||||
metadata?: KafkaJSStaleTopicMetadataAssignmentMetadata,
|
||||
);
|
||||
}
|
||||
|
||||
export declare class KafkaJSServerDoesNotSupportApiKey extends KafkaJSNonRetriableError {
|
||||
constructor(
|
||||
e: Error | string,
|
||||
metadata?: KafkaJSServerDoesNotSupportApiKeyMetadata,
|
||||
);
|
||||
}
|
||||
|
||||
export declare class KafkaJSBrokerNotFound extends KafkaJSError {
|
||||
constructor();
|
||||
}
|
||||
|
||||
export declare class KafkaJSPartialMessageError extends KafkaJSError {
|
||||
constructor();
|
||||
}
|
||||
|
||||
export declare class KafkaJSSASLAuthenticationError extends KafkaJSError {
|
||||
constructor();
|
||||
}
|
||||
|
||||
export declare class KafkaJSGroupCoordinatorNotFound extends KafkaJSError {
|
||||
constructor();
|
||||
}
|
||||
|
||||
export declare class KafkaJSNotImplemented extends KafkaJSError {
|
||||
constructor();
|
||||
}
|
||||
|
||||
export declare class KafkaJSTimeout extends KafkaJSError {
|
||||
constructor();
|
||||
}
|
||||
|
||||
export declare class KafkaJSLockTimeout extends KafkaJSError {
|
||||
constructor();
|
||||
}
|
||||
|
||||
export declare class KafkaJSUnsupportedMagicByteInMessageSet extends KafkaJSError {
|
||||
constructor();
|
||||
}
|
||||
|
||||
export declare class KafkaJSDeleteGroupsError extends KafkaJSError {
|
||||
constructor(e: Error | string, groups?: KafkaJSDeleteGroupsErrorGroups[]);
|
||||
}
|
||||
|
||||
export interface KafkaJSDeleteGroupsErrorGroups {
|
||||
groupId: string;
|
||||
errorCode: number;
|
||||
error: KafkaJSError;
|
||||
}
|
||||
|
||||
export interface KafkaJSErrorMetadata {
|
||||
retriable?: boolean;
|
||||
topic?: string;
|
||||
partitionId?: number;
|
||||
metadata?: PartitionMetadata;
|
||||
}
|
||||
|
||||
export interface KafkaJSOffsetOutOfRangeMetadata {
|
||||
topic: string;
|
||||
partition: number;
|
||||
}
|
||||
|
||||
export interface KafkaJSNumberOfRetriesExceededMetadata {
|
||||
retryCount: number;
|
||||
retryTime: number;
|
||||
}
|
||||
|
||||
export interface KafkaJSConnectionErrorMetadata {
|
||||
broker?: string;
|
||||
code?: string;
|
||||
}
|
||||
|
||||
export interface KafkaJSRequestTimeoutErrorMetadata {
|
||||
broker: string;
|
||||
clientId: string;
|
||||
correlationId: number;
|
||||
createdAt: number;
|
||||
sentAt: number;
|
||||
pendingDuration: number;
|
||||
}
|
||||
|
||||
export interface KafkaJSTopicMetadataNotLoadedMetadata {
|
||||
topic: string;
|
||||
}
|
||||
|
||||
export interface KafkaJSStaleTopicMetadataAssignmentMetadata {
|
||||
topic: string;
|
||||
unknownPartitions: PartitionMetadata[];
|
||||
}
|
||||
|
||||
export interface KafkaJSServerDoesNotSupportApiKeyMetadata {
|
||||
apiKey: number;
|
||||
apiName: string;
|
||||
}
|
||||
672
packages/microservices/external/kafka.interface.ts
vendored
672
packages/microservices/external/kafka.interface.ts
vendored
@@ -1,9 +1,19 @@
|
||||
/**
|
||||
* @see https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/kafkajs/index.d.ts
|
||||
* Do NOT add NestJS logic to this interface. It is meant to ONLY represent the types for the kafkajs package.
|
||||
*
|
||||
* @see https://github.com/tulios/kafkajs/blob/master/types/index.d.ts
|
||||
*/
|
||||
|
||||
/// <reference types="node" />
|
||||
|
||||
import * as net from 'net';
|
||||
import * as tls from 'tls';
|
||||
|
||||
type Without<T, U> = { [P in Exclude<keyof T, keyof U>]?: never };
|
||||
type XOR<T, U> = T | U extends object
|
||||
? (Without<T, U> & U) | (Without<U, T> & T)
|
||||
: T | U;
|
||||
|
||||
export declare class Kafka {
|
||||
constructor(config: KafkaConfig);
|
||||
producer(config?: ProducerConfig): Producer;
|
||||
@@ -19,7 +29,6 @@ export interface KafkaConfig {
|
||||
ssl?: tls.ConnectionOptions | boolean;
|
||||
sasl?: SASLOptions;
|
||||
clientId?: string;
|
||||
clientIdPostfix?: string;
|
||||
connectionTimeout?: number;
|
||||
authenticationTimeout?: number;
|
||||
reauthenticationThreshold?: number;
|
||||
@@ -31,19 +40,40 @@ export interface KafkaConfig {
|
||||
logCreator?: logCreator;
|
||||
}
|
||||
|
||||
export type ISocketFactory = (
|
||||
host: string,
|
||||
port: number,
|
||||
ssl: tls.ConnectionOptions,
|
||||
onConnect: () => void,
|
||||
) => net.Socket;
|
||||
|
||||
export interface SASLOptions {
|
||||
mechanism: 'plain' | 'scram-sha-256' | 'scram-sha-512' | 'aws';
|
||||
username: string;
|
||||
password: string;
|
||||
export interface ISocketFactoryArgs {
|
||||
host: string;
|
||||
port: number;
|
||||
ssl: tls.ConnectionOptions;
|
||||
onConnect: () => void;
|
||||
}
|
||||
|
||||
export type ISocketFactory = (args: ISocketFactoryArgs) => net.Socket;
|
||||
|
||||
export interface OauthbearerProviderResponse {
|
||||
value: string;
|
||||
}
|
||||
|
||||
type SASLMechanismOptionsMap = {
|
||||
plain: { username: string; password: string };
|
||||
'scram-sha-256': { username: string; password: string };
|
||||
'scram-sha-512': { username: string; password: string };
|
||||
aws: {
|
||||
authorizationIdentity: string;
|
||||
accessKeyId: string;
|
||||
secretAccessKey: string;
|
||||
sessionToken?: string;
|
||||
};
|
||||
oauthbearer: {
|
||||
oauthBearerProvider: () => Promise<OauthbearerProviderResponse>;
|
||||
};
|
||||
};
|
||||
|
||||
export type SASLMechanism = keyof SASLMechanismOptionsMap;
|
||||
type SASLMechanismOptions<T> = T extends SASLMechanism
|
||||
? { mechanism: T } & SASLMechanismOptionsMap[T]
|
||||
: never;
|
||||
export type SASLOptions = SASLMechanismOptions<SASLMechanism>;
|
||||
|
||||
export interface ProducerConfig {
|
||||
createPartitioner?: ICustomPartitioner;
|
||||
retry?: RetryOptions;
|
||||
@@ -70,24 +100,25 @@ export interface PartitionerArgs {
|
||||
}
|
||||
|
||||
export type ICustomPartitioner = () => (args: PartitionerArgs) => number;
|
||||
export type DefaultPartitioner = (args: PartitionerArgs) => number;
|
||||
export type JavaCompatiblePartitioner = (args: PartitionerArgs) => number;
|
||||
export type DefaultPartitioner = ICustomPartitioner;
|
||||
export type JavaCompatiblePartitioner = ICustomPartitioner;
|
||||
|
||||
export let Partitioners: {
|
||||
DefaultPartitioner: DefaultPartitioner;
|
||||
JavaCompatiblePartitioner: JavaCompatiblePartitioner;
|
||||
};
|
||||
|
||||
export interface PartitionMetadata {
|
||||
export type PartitionMetadata = {
|
||||
partitionErrorCode: number;
|
||||
partitionId: number;
|
||||
leader: number;
|
||||
replicas: number[];
|
||||
isr: number[];
|
||||
}
|
||||
offlineReplicas?: number[];
|
||||
};
|
||||
|
||||
export interface IHeaders {
|
||||
[key: string]: Buffer;
|
||||
[key: string]: Buffer | string | undefined;
|
||||
}
|
||||
|
||||
export interface ConsumerConfig {
|
||||
@@ -101,15 +132,16 @@ export interface ConsumerConfig {
|
||||
minBytes?: number;
|
||||
maxBytes?: number;
|
||||
maxWaitTimeInMs?: number;
|
||||
retry?: RetryOptions;
|
||||
retry?: RetryOptions & {
|
||||
restartOnFailure?: (err: Error) => Promise<boolean>;
|
||||
};
|
||||
allowAutoTopicCreation?: boolean;
|
||||
maxInFlightRequests?: number;
|
||||
readUncommitted?: boolean;
|
||||
rackId?: string;
|
||||
}
|
||||
|
||||
export interface PartitionAssigner {
|
||||
new (config: { cluster: Cluster }): Assigner;
|
||||
}
|
||||
export type PartitionAssigner = (config: { cluster: Cluster }) => Assigner;
|
||||
|
||||
export interface CoordinatorMetadata {
|
||||
errorCode: number;
|
||||
@@ -120,7 +152,7 @@ export interface CoordinatorMetadata {
|
||||
};
|
||||
}
|
||||
|
||||
export interface Cluster {
|
||||
export type Cluster = {
|
||||
isConnected(): boolean;
|
||||
connect(): Promise<void>;
|
||||
disconnect(): Promise<void>;
|
||||
@@ -140,46 +172,38 @@ export interface Cluster {
|
||||
}): Promise<CoordinatorMetadata>;
|
||||
defaultOffset(config: { fromBeginning: boolean }): number;
|
||||
fetchTopicsOffset(
|
||||
topics: Array<{
|
||||
topic: string;
|
||||
partitions: Array<{ partition: number }>;
|
||||
fromBeginning: boolean;
|
||||
}>,
|
||||
topics: Array<
|
||||
{
|
||||
topic: string;
|
||||
partitions: Array<{ partition: number }>;
|
||||
} & XOR<{ fromBeginning: boolean }, { fromTimestamp: number }>
|
||||
>,
|
||||
): Promise<{
|
||||
topic: string;
|
||||
partitions: Array<{ partition: number; offset: string }>;
|
||||
}>;
|
||||
}
|
||||
};
|
||||
|
||||
export interface Assignment {
|
||||
[topic: string]: number[];
|
||||
}
|
||||
export type Assignment = { [topic: string]: number[] };
|
||||
|
||||
export interface GroupMember {
|
||||
memberId: string;
|
||||
memberMetadata: MemberMetadata;
|
||||
}
|
||||
export type GroupMember = { memberId: string; memberMetadata: Buffer };
|
||||
|
||||
export interface GroupMemberAssignment {
|
||||
export type GroupMemberAssignment = {
|
||||
memberId: string;
|
||||
memberAssignment: Buffer;
|
||||
}
|
||||
};
|
||||
|
||||
export interface GroupState {
|
||||
name: string;
|
||||
metadata: Buffer;
|
||||
}
|
||||
export type GroupState = { name: string; metadata: Buffer };
|
||||
|
||||
export interface Assigner {
|
||||
export type Assigner = {
|
||||
name: string;
|
||||
version: number;
|
||||
assign(group: {
|
||||
members: GroupMember[];
|
||||
topics: string[];
|
||||
userData: Buffer;
|
||||
}): Promise<GroupMemberAssignment[]>;
|
||||
protocol(subscription: { topics: string[]; userData: Buffer }): GroupState;
|
||||
}
|
||||
protocol(subscription: { topics: string[] }): GroupState;
|
||||
};
|
||||
|
||||
export interface RetryOptions {
|
||||
maxRetryTime?: number;
|
||||
@@ -201,12 +225,22 @@ export interface ITopicConfig {
|
||||
configEntries?: object[];
|
||||
}
|
||||
|
||||
export interface ITopicPartitionConfig {
|
||||
topic: string;
|
||||
count: number;
|
||||
assignments?: Array<Array<number>>;
|
||||
}
|
||||
|
||||
export interface ITopicMetadata {
|
||||
name: string;
|
||||
partitions: PartitionMetadata[];
|
||||
}
|
||||
|
||||
export enum ResourceType {
|
||||
/**
|
||||
* @deprecated
|
||||
* Use ConfigResourceTypes or AclResourceTypes
|
||||
*/
|
||||
export enum ResourceTypes {
|
||||
UNKNOWN = 0,
|
||||
ANY = 1,
|
||||
TOPIC = 2,
|
||||
@@ -216,10 +250,58 @@ export enum ResourceType {
|
||||
DELEGATION_TOKEN = 6,
|
||||
}
|
||||
|
||||
export enum AclResourceTypes {
|
||||
UNKNOWN = 0,
|
||||
ANY = 1,
|
||||
TOPIC = 2,
|
||||
GROUP = 3,
|
||||
CLUSTER = 4,
|
||||
TRANSACTIONAL_ID = 5,
|
||||
DELEGATION_TOKEN = 6,
|
||||
}
|
||||
|
||||
export enum ConfigResourceTypes {
|
||||
UNKNOWN = 0,
|
||||
TOPIC = 2,
|
||||
BROKER = 4,
|
||||
BROKER_LOGGER = 8,
|
||||
}
|
||||
|
||||
export enum AclPermissionTypes {
|
||||
UNKNOWN = 0,
|
||||
ANY = 1,
|
||||
DENY = 2,
|
||||
ALLOW = 3,
|
||||
}
|
||||
|
||||
export enum AclOperationTypes {
|
||||
UNKNOWN = 0,
|
||||
ANY = 1,
|
||||
ALL = 2,
|
||||
READ = 3,
|
||||
WRITE = 4,
|
||||
CREATE = 5,
|
||||
DELETE = 6,
|
||||
ALTER = 7,
|
||||
DESCRIBE = 8,
|
||||
CLUSTER_ACTION = 9,
|
||||
DESCRIBE_CONFIGS = 10,
|
||||
ALTER_CONFIGS = 11,
|
||||
IDEMPOTENT_WRITE = 12,
|
||||
}
|
||||
|
||||
export enum ResourcePatternTypes {
|
||||
UNKNOWN = 0,
|
||||
ANY = 1,
|
||||
MATCH = 2,
|
||||
LITERAL = 3,
|
||||
PREFIXED = 4,
|
||||
}
|
||||
|
||||
export interface ResourceConfigQuery {
|
||||
type: ResourceType;
|
||||
type: ResourceTypes | ConfigResourceTypes;
|
||||
name: string;
|
||||
configNames: string[];
|
||||
configNames?: string[];
|
||||
}
|
||||
|
||||
export interface ConfigEntries {
|
||||
@@ -243,26 +325,26 @@ export interface DescribeConfigResponse {
|
||||
errorCode: number;
|
||||
errorMessage: string;
|
||||
resourceName: string;
|
||||
resourceType: ResourceType;
|
||||
resourceType: ResourceTypes | ConfigResourceTypes;
|
||||
}[];
|
||||
throttleTime: number;
|
||||
}
|
||||
|
||||
export interface IResourceConfig {
|
||||
type: ResourceType;
|
||||
type: ResourceTypes | ConfigResourceTypes;
|
||||
name: string;
|
||||
configEntries: { name: string; value: string }[];
|
||||
}
|
||||
|
||||
type ValueOf<T> = T[keyof T];
|
||||
|
||||
export interface AdminEvents {
|
||||
export type AdminEvents = {
|
||||
CONNECT: 'admin.connect';
|
||||
DISCONNECT: 'admin.disconnect';
|
||||
REQUEST: 'admin.network.request';
|
||||
REQUEST_TIMEOUT: 'admin.network.request_timeout';
|
||||
REQUEST_QUEUE_SIZE: 'admin.network.request_queue_size';
|
||||
}
|
||||
};
|
||||
|
||||
export interface InstrumentationEvent<T> {
|
||||
id: string;
|
||||
@@ -271,6 +353,8 @@ export interface InstrumentationEvent<T> {
|
||||
payload: T;
|
||||
}
|
||||
|
||||
export type RemoveInstrumentationEventListener<T> = () => void;
|
||||
|
||||
export type ConnectEvent = InstrumentationEvent<null>;
|
||||
export type DisconnectEvent = InstrumentationEvent<null>;
|
||||
export type RequestEvent = InstrumentationEvent<{
|
||||
@@ -308,9 +392,69 @@ export interface SeekEntry {
|
||||
offset: string;
|
||||
}
|
||||
|
||||
export interface Admin {
|
||||
export interface Acl {
|
||||
principal: string;
|
||||
host: string;
|
||||
operation: AclOperationTypes;
|
||||
permissionType: AclPermissionTypes;
|
||||
}
|
||||
|
||||
export interface AclResource {
|
||||
resourceType: AclResourceTypes;
|
||||
resourceName: string;
|
||||
resourcePatternType: ResourcePatternTypes;
|
||||
}
|
||||
|
||||
export type AclEntry = Acl & AclResource;
|
||||
|
||||
export type DescribeAclResource = AclResource & {
|
||||
acl: Acl[];
|
||||
};
|
||||
|
||||
export interface DescribeAclResponse {
|
||||
throttleTime: number;
|
||||
errorCode: number;
|
||||
errorMessage?: string;
|
||||
resources: DescribeAclResource[];
|
||||
}
|
||||
|
||||
export interface AclFilter {
|
||||
resourceType: AclResourceTypes;
|
||||
resourceName?: string;
|
||||
resourcePatternType: ResourcePatternTypes;
|
||||
principal?: string;
|
||||
host?: string;
|
||||
operation: AclOperationTypes;
|
||||
permissionType: AclPermissionTypes;
|
||||
}
|
||||
|
||||
export interface MatchingAcl {
|
||||
errorCode: number;
|
||||
errorMessage?: string;
|
||||
resourceType: AclResourceTypes;
|
||||
resourceName: string;
|
||||
resourcePatternType: ResourcePatternTypes;
|
||||
principal: string;
|
||||
host: string;
|
||||
operation: AclOperationTypes;
|
||||
permissionType: AclPermissionTypes;
|
||||
}
|
||||
|
||||
export interface DeleteAclFilterResponses {
|
||||
errorCode: number;
|
||||
errorMessage?: string;
|
||||
matchingAcls: MatchingAcl[];
|
||||
}
|
||||
|
||||
export interface DeleteAclResponse {
|
||||
throttleTime: number;
|
||||
filterResponses: DeleteAclFilterResponses[];
|
||||
}
|
||||
|
||||
export type Admin = {
|
||||
connect(): Promise<void>;
|
||||
disconnect(): Promise<void>;
|
||||
listTopics(): Promise<string[]>;
|
||||
createTopics(options: {
|
||||
validateOnly?: boolean;
|
||||
waitForLeaders?: boolean;
|
||||
@@ -318,20 +462,31 @@ export interface Admin {
|
||||
topics: ITopicConfig[];
|
||||
}): Promise<boolean>;
|
||||
deleteTopics(options: { topics: string[]; timeout?: number }): Promise<void>;
|
||||
fetchTopicMetadata(options: {
|
||||
createPartitions(options: {
|
||||
validateOnly?: boolean;
|
||||
timeout?: number;
|
||||
topicPartitions: ITopicPartitionConfig[];
|
||||
}): Promise<boolean>;
|
||||
fetchTopicMetadata(options?: {
|
||||
topics: string[];
|
||||
}): Promise<{ topics: Array<ITopicMetadata> }>;
|
||||
fetchOffsets(options: {
|
||||
groupId: string;
|
||||
topic: string;
|
||||
}): Promise<
|
||||
Array<{ partition: number; offset: string; metadata: string | null }>
|
||||
>;
|
||||
resolveOffsets?: boolean;
|
||||
}): Promise<Array<SeekEntry & { metadata: string | null }>>;
|
||||
fetchTopicOffsets(
|
||||
topic: string,
|
||||
): Promise<
|
||||
Array<{ partition: number; offset: string; high: string; low: string }>
|
||||
>;
|
||||
): Promise<Array<SeekEntry & { high: string; low: string }>>;
|
||||
fetchTopicOffsetsByTimestamp(
|
||||
topic: string,
|
||||
timestamp?: number,
|
||||
): Promise<Array<SeekEntry>>;
|
||||
describeCluster(): Promise<{
|
||||
brokers: Array<{ nodeId: number; host: string; port: number }>;
|
||||
controller: number | null;
|
||||
clusterId: string;
|
||||
}>;
|
||||
setOffsets(options: {
|
||||
groupId: string;
|
||||
topic: string;
|
||||
@@ -350,29 +505,42 @@ export interface Admin {
|
||||
validateOnly: boolean;
|
||||
resources: IResourceConfig[];
|
||||
}): Promise<any>;
|
||||
listGroups(): Promise<{ groups: GroupOverview[] }>;
|
||||
deleteGroups(groupIds: string[]): Promise<DeleteGroupsResult[]>;
|
||||
describeGroups(groupIds: string[]): Promise<GroupDescriptions>;
|
||||
describeAcls(options: AclFilter): Promise<DescribeAclResponse>;
|
||||
deleteAcls(options: { filters: AclFilter[] }): Promise<DeleteAclResponse>;
|
||||
createAcls(options: { acl: AclEntry[] }): Promise<boolean>;
|
||||
deleteTopicRecords(options: {
|
||||
topic: string;
|
||||
partitions: SeekEntry[];
|
||||
}): Promise<void>;
|
||||
logger(): Logger;
|
||||
on(eventName: ValueOf<AdminEvents>, listener: (...args: any[]) => void): void;
|
||||
on(
|
||||
eventName: ValueOf<AdminEvents>,
|
||||
listener: (...args: any[]) => void,
|
||||
): RemoveInstrumentationEventListener<typeof eventName>;
|
||||
events: AdminEvents;
|
||||
}
|
||||
};
|
||||
|
||||
export let PartitionAssigners: { roundRobin: PartitionAssigner };
|
||||
|
||||
export interface ISerializer<T> {
|
||||
encode(value: T): Buffer;
|
||||
decode(buffer: Buffer): T;
|
||||
decode(buffer: Buffer): T | null;
|
||||
}
|
||||
|
||||
export interface MemberMetadata {
|
||||
export type MemberMetadata = {
|
||||
version: number;
|
||||
topics: string[];
|
||||
userData: Buffer;
|
||||
}
|
||||
};
|
||||
|
||||
export interface MemberAssignment {
|
||||
export type MemberAssignment = {
|
||||
version: number;
|
||||
assignment: Assignment;
|
||||
userData: Buffer;
|
||||
}
|
||||
};
|
||||
|
||||
export let AssignerProtocol: {
|
||||
MemberMetadata: ISerializer<MemberMetadata>;
|
||||
@@ -400,11 +568,16 @@ export interface LoggerEntryContent {
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export type Logger = (entry: LogEntry) => void;
|
||||
export type logCreator = (logLevel: logLevel) => (entry: LogEntry) => void;
|
||||
|
||||
export type logCreator = (logLevel: string) => (entry: LogEntry) => void;
|
||||
export type Logger = {
|
||||
info: (message: string, extra?: object) => void;
|
||||
error: (message: string, extra?: object) => void;
|
||||
warn: (message: string, extra?: object) => void;
|
||||
debug: (message: string, extra?: object) => void;
|
||||
};
|
||||
|
||||
export interface Broker {
|
||||
export type Broker = {
|
||||
isConnected(): boolean;
|
||||
connect(): Promise<void>;
|
||||
disconnect(): Promise<void>;
|
||||
@@ -414,7 +587,12 @@ export interface Broker {
|
||||
metadata(
|
||||
topics: string[],
|
||||
): Promise<{
|
||||
brokers: Array<{ nodeId: number; host: string; port: number }>;
|
||||
brokers: Array<{
|
||||
nodeId: number;
|
||||
host: string;
|
||||
port: number;
|
||||
rack?: string;
|
||||
}>;
|
||||
topicMetadata: Array<{
|
||||
topicErrorCode: number;
|
||||
topic: number;
|
||||
@@ -431,17 +609,33 @@ export interface Broker {
|
||||
partitions: Array<{ partition: number; offset: string }>;
|
||||
}>;
|
||||
}): Promise<any>;
|
||||
}
|
||||
fetch(request: {
|
||||
replicaId?: number;
|
||||
isolationLevel?: number;
|
||||
maxWaitTime?: number;
|
||||
minBytes?: number;
|
||||
maxBytes?: number;
|
||||
topics: Array<{
|
||||
topic: string;
|
||||
partitions: Array<{
|
||||
partition: number;
|
||||
fetchOffset: string;
|
||||
maxBytes: number;
|
||||
}>;
|
||||
}>;
|
||||
rackId?: string;
|
||||
}): Promise<any>;
|
||||
};
|
||||
|
||||
export interface KafkaMessage {
|
||||
export type KafkaMessage = {
|
||||
key: Buffer;
|
||||
value: Buffer;
|
||||
value: Buffer | null;
|
||||
timestamp: string;
|
||||
size: number;
|
||||
attributes: number;
|
||||
offset: string;
|
||||
headers?: IHeaders;
|
||||
}
|
||||
};
|
||||
|
||||
export interface ProducerRecord {
|
||||
topic: string;
|
||||
@@ -451,13 +645,16 @@ export interface ProducerRecord {
|
||||
compression?: CompressionTypes;
|
||||
}
|
||||
|
||||
export interface RecordMetadata {
|
||||
export type RecordMetadata = {
|
||||
topicName: string;
|
||||
partition: number;
|
||||
errorCode: number;
|
||||
offset: string;
|
||||
timestamp: string;
|
||||
}
|
||||
offset?: string;
|
||||
timestamp?: string;
|
||||
baseOffset?: string;
|
||||
logAppendTime?: string;
|
||||
logStartOffset?: string;
|
||||
};
|
||||
|
||||
export interface TopicMessages {
|
||||
topic: string;
|
||||
@@ -465,10 +662,10 @@ export interface TopicMessages {
|
||||
}
|
||||
|
||||
export interface ProducerBatch {
|
||||
acks: number;
|
||||
timeout: number;
|
||||
compression: CompressionTypes;
|
||||
topicMessages: TopicMessages[];
|
||||
acks?: number;
|
||||
timeout?: number;
|
||||
compression?: CompressionTypes;
|
||||
topicMessages?: TopicMessages[];
|
||||
}
|
||||
|
||||
export interface PartitionOffset {
|
||||
@@ -485,18 +682,18 @@ export interface Offsets {
|
||||
topics: TopicOffsets[];
|
||||
}
|
||||
|
||||
interface Sender {
|
||||
type Sender = {
|
||||
send(record: ProducerRecord): Promise<RecordMetadata[]>;
|
||||
sendBatch(batch: ProducerBatch): Promise<RecordMetadata[]>;
|
||||
}
|
||||
};
|
||||
|
||||
export interface ProducerEvents {
|
||||
export type ProducerEvents = {
|
||||
CONNECT: 'producer.connect';
|
||||
DISCONNECT: 'producer.disconnect';
|
||||
REQUEST: 'producer.network.request';
|
||||
REQUEST_TIMEOUT: 'producer.network.request_timeout';
|
||||
REQUEST_QUEUE_SIZE: 'producer.network.request_queue_size';
|
||||
}
|
||||
};
|
||||
|
||||
export type Producer = Sender & {
|
||||
connect(): Promise<void>;
|
||||
@@ -506,7 +703,7 @@ export type Producer = Sender & {
|
||||
on(
|
||||
eventName: ValueOf<ProducerEvents>,
|
||||
listener: (...args: any[]) => void,
|
||||
): void;
|
||||
): RemoveInstrumentationEventListener<typeof eventName>;
|
||||
transaction(): Promise<Transaction>;
|
||||
logger(): Logger;
|
||||
};
|
||||
@@ -518,41 +715,54 @@ export type Transaction = Sender & {
|
||||
isActive(): boolean;
|
||||
};
|
||||
|
||||
export interface ConsumerGroup {
|
||||
export type ConsumerGroup = {
|
||||
groupId: string;
|
||||
generationId: number;
|
||||
memberId: string;
|
||||
coordinator: Broker;
|
||||
}
|
||||
};
|
||||
|
||||
export interface MemberDescription {
|
||||
export type MemberDescription = {
|
||||
clientHost: string;
|
||||
clientId: string;
|
||||
memberId: string;
|
||||
memberAssignment: Buffer;
|
||||
memberMetadata: Buffer;
|
||||
}
|
||||
};
|
||||
|
||||
export interface GroupDescription {
|
||||
// See https://github.com/apache/kafka/blob/2.4.0/clients/src/main/java/org/apache/kafka/common/ConsumerGroupState.java#L25
|
||||
export type ConsumerGroupState =
|
||||
| 'Unknown'
|
||||
| 'PreparingRebalance'
|
||||
| 'CompletingRebalance'
|
||||
| 'Stable'
|
||||
| 'Dead'
|
||||
| 'Empty';
|
||||
|
||||
export type GroupDescription = {
|
||||
groupId: string;
|
||||
members: MemberDescription[];
|
||||
protocol: string;
|
||||
protocolType: string;
|
||||
state: string;
|
||||
}
|
||||
state: ConsumerGroupState;
|
||||
};
|
||||
|
||||
export interface TopicPartitions {
|
||||
topic: string;
|
||||
partitions: number[];
|
||||
}
|
||||
export interface TopicPartitionOffsetAndMedata {
|
||||
export type GroupDescriptions = {
|
||||
groups: GroupDescription[];
|
||||
};
|
||||
|
||||
export type TopicPartitions = { topic: string; partitions: number[] };
|
||||
export type TopicPartitionOffsetAndMetadata = {
|
||||
topic: string;
|
||||
partition: number;
|
||||
offset: string;
|
||||
metadata?: string | null;
|
||||
}
|
||||
};
|
||||
|
||||
export interface Batch {
|
||||
// TODO: Remove with 2.x
|
||||
export type TopicPartitionOffsetAndMedata = TopicPartitionOffsetAndMetadata;
|
||||
|
||||
export type Batch = {
|
||||
topic: string;
|
||||
partition: number;
|
||||
highWatermark: string;
|
||||
@@ -562,12 +772,24 @@ export interface Batch {
|
||||
lastOffset(): string;
|
||||
offsetLag(): string;
|
||||
offsetLagLow(): string;
|
||||
}
|
||||
};
|
||||
|
||||
export interface ConsumerEvents {
|
||||
export type GroupOverview = {
|
||||
groupId: string;
|
||||
protocolType: string;
|
||||
};
|
||||
|
||||
export type DeleteGroupsResult = {
|
||||
groupId: string;
|
||||
errorCode?: number;
|
||||
error?: KafkaJSProtocolError;
|
||||
};
|
||||
|
||||
export type ConsumerEvents = {
|
||||
HEARTBEAT: 'consumer.heartbeat';
|
||||
COMMIT_OFFSETS: 'consumer.commit_offsets';
|
||||
GROUP_JOIN: 'consumer.group_join';
|
||||
FETCH_START: 'consumer.fetch_start';
|
||||
FETCH: 'consumer.fetch';
|
||||
START_BATCH_PROCESS: 'consumer.start_batch_process';
|
||||
END_BATCH_PROCESS: 'consumer.end_batch_process';
|
||||
@@ -575,10 +797,11 @@ export interface ConsumerEvents {
|
||||
DISCONNECT: 'consumer.disconnect';
|
||||
STOP: 'consumer.stop';
|
||||
CRASH: 'consumer.crash';
|
||||
RECEIVED_UNSUBSCRIBED_TOPICS: 'consumer.received_unsubscribed_topics';
|
||||
REQUEST: 'consumer.network.request';
|
||||
REQUEST_TIMEOUT: 'consumer.network.request_timeout';
|
||||
REQUEST_QUEUE_SIZE: 'consumer.network.request_queue_size';
|
||||
}
|
||||
};
|
||||
export type ConsumerHeartbeatEvent = InstrumentationEvent<{
|
||||
groupId: string;
|
||||
memberId: string;
|
||||
@@ -622,15 +845,22 @@ interface IBatchProcessEvent {
|
||||
firstOffset: string;
|
||||
lastOffset: string;
|
||||
}
|
||||
export type ConsumerStartBatchProcessEvent = InstrumentationEvent<
|
||||
IBatchProcessEvent
|
||||
>;
|
||||
export type ConsumerStartBatchProcessEvent = InstrumentationEvent<IBatchProcessEvent>;
|
||||
export type ConsumerEndBatchProcessEvent = InstrumentationEvent<
|
||||
IBatchProcessEvent & { duration: number }
|
||||
>;
|
||||
export type ConsumerCrashEvent = InstrumentationEvent<{
|
||||
error: Error;
|
||||
groupId: string;
|
||||
restart: boolean;
|
||||
}>;
|
||||
export type ConsumerReceivedUnsubcribedTopicsEvent = InstrumentationEvent<{
|
||||
groupId: string;
|
||||
generationId: number;
|
||||
memberId: string;
|
||||
assignedTopics: string[];
|
||||
topicsSubscribed: string[];
|
||||
topicsNotSubscribed: string[];
|
||||
}>;
|
||||
|
||||
export interface OffsetsByTopicPartition {
|
||||
@@ -648,7 +878,7 @@ export interface EachBatchPayload {
|
||||
resolveOffset(offset: string): void;
|
||||
heartbeat(): Promise<void>;
|
||||
commitOffsetsIfNecessary(offsets?: Offsets): Promise<void>;
|
||||
uncommittedOffsets(): Promise<OffsetsByTopicPartition>;
|
||||
uncommittedOffsets(): OffsetsByTopicPartition;
|
||||
isRunning(): boolean;
|
||||
isStale(): boolean;
|
||||
}
|
||||
@@ -665,25 +895,29 @@ export type ConsumerEachMessagePayload = EachMessagePayload;
|
||||
*/
|
||||
export type ConsumerEachBatchPayload = EachBatchPayload;
|
||||
|
||||
export interface Consumer {
|
||||
export type ConsumerRunConfig = {
|
||||
autoCommit?: boolean;
|
||||
autoCommitInterval?: number | null;
|
||||
autoCommitThreshold?: number | null;
|
||||
eachBatchAutoResolve?: boolean;
|
||||
partitionsConsumedConcurrently?: number;
|
||||
eachBatch?: (payload: EachBatchPayload) => Promise<void>;
|
||||
eachMessage?: (payload: EachMessagePayload) => Promise<void>;
|
||||
};
|
||||
|
||||
export type ConsumerSubscribeTopic = {
|
||||
topic: string | RegExp;
|
||||
fromBeginning?: boolean;
|
||||
};
|
||||
|
||||
export type Consumer = {
|
||||
connect(): Promise<void>;
|
||||
disconnect(): Promise<void>;
|
||||
subscribe(topic: {
|
||||
topic: string | RegExp;
|
||||
fromBeginning?: boolean;
|
||||
}): Promise<void>;
|
||||
subscribe(topic: ConsumerSubscribeTopic): Promise<void>;
|
||||
stop(): Promise<void>;
|
||||
run(config?: {
|
||||
autoCommit?: boolean;
|
||||
autoCommitInterval?: number | null;
|
||||
autoCommitThreshold?: number | null;
|
||||
eachBatchAutoResolve?: boolean;
|
||||
partitionsConsumedConcurrently?: number;
|
||||
eachBatch?: (payload: EachBatchPayload) => Promise<void>;
|
||||
eachMessage?: (payload: EachMessagePayload) => Promise<void>;
|
||||
}): Promise<void>;
|
||||
run(config?: ConsumerRunConfig): Promise<void>;
|
||||
commitOffsets(
|
||||
topicPartitions: Array<TopicPartitionOffsetAndMedata>,
|
||||
topicPartitions: Array<TopicPartitionOffsetAndMetadata>,
|
||||
): Promise<void>;
|
||||
seek(topicPartition: {
|
||||
topic: string;
|
||||
@@ -692,14 +926,15 @@ export interface Consumer {
|
||||
}): void;
|
||||
describeGroup(): Promise<GroupDescription>;
|
||||
pause(topics: Array<{ topic: string; partitions?: number[] }>): void;
|
||||
paused(): TopicPartitions[];
|
||||
resume(topics: Array<{ topic: string; partitions?: number[] }>): void;
|
||||
on(
|
||||
eventName: ValueOf<ConsumerEvents>,
|
||||
listener: (...args: any[]) => void,
|
||||
): void;
|
||||
): RemoveInstrumentationEventListener<typeof eventName>;
|
||||
logger(): Logger;
|
||||
events: ConsumerEvents;
|
||||
}
|
||||
};
|
||||
|
||||
export enum CompressionTypes {
|
||||
None = 0,
|
||||
@@ -715,3 +950,186 @@ export let CompressionCodecs: {
|
||||
[CompressionTypes.LZ4]: () => any;
|
||||
[CompressionTypes.ZSTD]: () => any;
|
||||
};
|
||||
|
||||
export declare class KafkaJSError extends Error {
|
||||
readonly message: Error['message'];
|
||||
readonly name: string;
|
||||
readonly retriable: boolean;
|
||||
readonly helpUrl?: string;
|
||||
|
||||
constructor(e: Error | string, metadata?: KafkaJSErrorMetadata);
|
||||
}
|
||||
|
||||
export declare class KafkaJSNonRetriableError extends KafkaJSError {
|
||||
constructor(e: Error | string);
|
||||
}
|
||||
|
||||
export declare class KafkaJSProtocolError extends KafkaJSError {
|
||||
readonly code: number;
|
||||
readonly type: string;
|
||||
constructor(e: Error | string);
|
||||
}
|
||||
|
||||
export declare class KafkaJSOffsetOutOfRange extends KafkaJSProtocolError {
|
||||
readonly topic: string;
|
||||
readonly partition: number;
|
||||
constructor(e: Error | string, metadata?: KafkaJSOffsetOutOfRangeMetadata);
|
||||
}
|
||||
|
||||
export declare class KafkaJSNumberOfRetriesExceeded extends KafkaJSNonRetriableError {
|
||||
readonly stack: string;
|
||||
readonly originalError: Error;
|
||||
readonly retryCount: number;
|
||||
readonly retryTime: number;
|
||||
constructor(
|
||||
e: Error | string,
|
||||
metadata?: KafkaJSNumberOfRetriesExceededMetadata,
|
||||
);
|
||||
}
|
||||
|
||||
export declare class KafkaJSConnectionError extends KafkaJSError {
|
||||
readonly broker: string;
|
||||
constructor(e: Error | string, metadata?: KafkaJSConnectionErrorMetadata);
|
||||
}
|
||||
|
||||
export declare class KafkaJSRequestTimeoutError extends KafkaJSError {
|
||||
readonly broker: string;
|
||||
readonly correlationId: number;
|
||||
readonly createdAt: number;
|
||||
readonly sentAt: number;
|
||||
readonly pendingDuration: number;
|
||||
constructor(e: Error | string, metadata?: KafkaJSRequestTimeoutErrorMetadata);
|
||||
}
|
||||
|
||||
export declare class KafkaJSMetadataNotLoaded extends KafkaJSError {
|
||||
constructor();
|
||||
}
|
||||
|
||||
export declare class KafkaJSTopicMetadataNotLoaded extends KafkaJSMetadataNotLoaded {
|
||||
readonly topic: string;
|
||||
constructor(
|
||||
e: Error | string,
|
||||
metadata?: KafkaJSTopicMetadataNotLoadedMetadata,
|
||||
);
|
||||
}
|
||||
|
||||
export declare class KafkaJSStaleTopicMetadataAssignment extends KafkaJSError {
|
||||
readonly topic: string;
|
||||
readonly unknownPartitions: number;
|
||||
constructor(
|
||||
e: Error | string,
|
||||
metadata?: KafkaJSStaleTopicMetadataAssignmentMetadata,
|
||||
);
|
||||
}
|
||||
|
||||
export declare class KafkaJSServerDoesNotSupportApiKey extends KafkaJSNonRetriableError {
|
||||
readonly apiKey: number;
|
||||
readonly apiName: string;
|
||||
constructor(
|
||||
e: Error | string,
|
||||
metadata?: KafkaJSServerDoesNotSupportApiKeyMetadata,
|
||||
);
|
||||
}
|
||||
|
||||
export declare class KafkaJSBrokerNotFound extends KafkaJSError {
|
||||
constructor();
|
||||
}
|
||||
|
||||
export declare class KafkaJSPartialMessageError extends KafkaJSError {
|
||||
constructor();
|
||||
}
|
||||
|
||||
export declare class KafkaJSSASLAuthenticationError extends KafkaJSError {
|
||||
constructor();
|
||||
}
|
||||
|
||||
export declare class KafkaJSGroupCoordinatorNotFound extends KafkaJSError {
|
||||
constructor();
|
||||
}
|
||||
|
||||
export declare class KafkaJSNotImplemented extends KafkaJSError {
|
||||
constructor();
|
||||
}
|
||||
|
||||
export declare class KafkaJSTimeout extends KafkaJSError {
|
||||
constructor();
|
||||
}
|
||||
|
||||
export declare class KafkaJSLockTimeout extends KafkaJSError {
|
||||
constructor();
|
||||
}
|
||||
|
||||
export declare class KafkaJSUnsupportedMagicByteInMessageSet extends KafkaJSError {
|
||||
constructor();
|
||||
}
|
||||
|
||||
export declare class KafkaJSDeleteGroupsError extends KafkaJSError {
|
||||
readonly groups: DeleteGroupsResult[];
|
||||
constructor(e: Error | string, groups?: KafkaJSDeleteGroupsErrorGroups[]);
|
||||
}
|
||||
|
||||
export declare class KafkaJSDeleteTopicRecordsError extends KafkaJSError {
|
||||
constructor(metadata: KafkaJSDeleteTopicRecordsErrorTopic);
|
||||
}
|
||||
|
||||
export interface KafkaJSDeleteGroupsErrorGroups {
|
||||
groupId: string;
|
||||
errorCode: number;
|
||||
error: KafkaJSError;
|
||||
}
|
||||
|
||||
export interface KafkaJSDeleteTopicRecordsErrorTopic {
|
||||
topic: string;
|
||||
partitions: KafkaJSDeleteTopicRecordsErrorPartition[];
|
||||
}
|
||||
|
||||
export interface KafkaJSDeleteTopicRecordsErrorPartition {
|
||||
partition: number;
|
||||
offset: string;
|
||||
error: KafkaJSError;
|
||||
}
|
||||
|
||||
export interface KafkaJSErrorMetadata {
|
||||
retriable?: boolean;
|
||||
topic?: string;
|
||||
partitionId?: number;
|
||||
metadata?: PartitionMetadata;
|
||||
}
|
||||
|
||||
export interface KafkaJSOffsetOutOfRangeMetadata {
|
||||
topic: string;
|
||||
partition: number;
|
||||
}
|
||||
|
||||
export interface KafkaJSNumberOfRetriesExceededMetadata {
|
||||
retryCount: number;
|
||||
retryTime: number;
|
||||
}
|
||||
|
||||
export interface KafkaJSConnectionErrorMetadata {
|
||||
broker?: string;
|
||||
code?: string;
|
||||
}
|
||||
|
||||
export interface KafkaJSRequestTimeoutErrorMetadata {
|
||||
broker: string;
|
||||
clientId: string;
|
||||
correlationId: number;
|
||||
createdAt: number;
|
||||
sentAt: number;
|
||||
pendingDuration: number;
|
||||
}
|
||||
|
||||
export interface KafkaJSTopicMetadataNotLoadedMetadata {
|
||||
topic: string;
|
||||
}
|
||||
|
||||
export interface KafkaJSStaleTopicMetadataAssignmentMetadata {
|
||||
topic: string;
|
||||
unknownPartitions: PartitionMetadata[];
|
||||
}
|
||||
|
||||
export interface KafkaJSServerDoesNotSupportApiKeyMetadata {
|
||||
apiKey: number;
|
||||
apiName: string;
|
||||
}
|
||||
|
||||
@@ -9,3 +9,22 @@ export interface RmqUrl {
|
||||
heartbeat?: number;
|
||||
vhost?: string;
|
||||
}
|
||||
|
||||
export interface AmqpConnectionManagerSocketOptions {
|
||||
reconnectTimeInSeconds?: number;
|
||||
heartbeatIntervalInSeconds?: number;
|
||||
findServers?: () => string | string[];
|
||||
connectionOptions?: any;
|
||||
}
|
||||
|
||||
export interface AmqplibQueueOptions {
|
||||
durable?: boolean;
|
||||
autoDelete?: boolean;
|
||||
arguments?: any;
|
||||
messageTtl?: number;
|
||||
expires?: number;
|
||||
deadLetterExchange?: string;
|
||||
deadLetterRoutingKey?: string;
|
||||
maxLength?: number;
|
||||
maxPriority?: number;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export * from './json-socket';
|
||||
export * from './kafka-logger';
|
||||
export * from './kafka-parser';
|
||||
export * from './kafka-round-robin-partition-assigner';
|
||||
export * from './kafka-reply-partition-assigner';
|
||||
|
||||
202
packages/microservices/helpers/kafka-reply-partition-assigner.ts
Normal file
202
packages/microservices/helpers/kafka-reply-partition-assigner.ts
Normal file
@@ -0,0 +1,202 @@
|
||||
import { loadPackage } from '@nestjs/common/utils/load-package.util';
|
||||
import { isUndefined } from '@nestjs/common/utils/shared.utils';
|
||||
import { ClientKafka } from '../client/client-kafka';
|
||||
import {
|
||||
Cluster,
|
||||
GroupMember,
|
||||
GroupMemberAssignment,
|
||||
GroupState,
|
||||
MemberMetadata,
|
||||
} from '../external/kafka.interface';
|
||||
|
||||
let kafkaPackage: any = {};
|
||||
|
||||
export class KafkaReplyPartitionAssigner {
|
||||
readonly name = 'NestReplyPartitionAssigner';
|
||||
readonly version = 1;
|
||||
|
||||
constructor(
|
||||
private readonly clientKafka: ClientKafka,
|
||||
private readonly config: {
|
||||
cluster: Cluster;
|
||||
},
|
||||
) {
|
||||
kafkaPackage = loadPackage(
|
||||
'kafkajs',
|
||||
KafkaReplyPartitionAssigner.name,
|
||||
() => require('kafkajs'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This process can result in imbalanced assignments
|
||||
* @param {array} members array of members, e.g: [{ memberId: 'test-5f93f5a3' }]
|
||||
* @param {array} topics
|
||||
* @param {Buffer} userData
|
||||
* @returns {array} object partitions per topic per member
|
||||
*/
|
||||
public async assign(group: {
|
||||
members: GroupMember[];
|
||||
topics: string[];
|
||||
}): Promise<GroupMemberAssignment[]> {
|
||||
const assignment = {};
|
||||
const previousAssignment = {};
|
||||
|
||||
const membersCount = group.members.length;
|
||||
const decodedMembers = group.members.map(member =>
|
||||
this.decodeMember(member),
|
||||
);
|
||||
const sortedMemberIds = decodedMembers
|
||||
.map(member => member.memberId)
|
||||
.sort();
|
||||
|
||||
// build the previous assignment and an inverse map of topic > partition > memberId for lookup
|
||||
decodedMembers.forEach(member => {
|
||||
if (
|
||||
!previousAssignment[member.memberId] &&
|
||||
Object.keys(member.previousAssignment).length > 0
|
||||
) {
|
||||
previousAssignment[member.memberId] = member.previousAssignment;
|
||||
}
|
||||
});
|
||||
|
||||
// build a collection of topics and partitions
|
||||
const topicsPartitions = group.topics
|
||||
.map(topic => {
|
||||
const partitionMetadata = this.config.cluster.findTopicPartitionMetadata(
|
||||
topic,
|
||||
);
|
||||
return partitionMetadata.map(m => {
|
||||
return {
|
||||
topic,
|
||||
partitionId: m.partitionId,
|
||||
};
|
||||
});
|
||||
})
|
||||
.reduce((acc, val) => acc.concat(val), []);
|
||||
|
||||
// create the new assignment by populating the members with the first partition of the topics
|
||||
sortedMemberIds.forEach(assignee => {
|
||||
if (!assignment[assignee]) {
|
||||
assignment[assignee] = {};
|
||||
}
|
||||
|
||||
// add topics to each member
|
||||
group.topics.forEach(topic => {
|
||||
if (!assignment[assignee][topic]) {
|
||||
assignment[assignee][topic] = [];
|
||||
}
|
||||
|
||||
// see if the topic and partition belong to a previous assignment
|
||||
if (
|
||||
previousAssignment[assignee] &&
|
||||
!isUndefined(previousAssignment[assignee][topic])
|
||||
) {
|
||||
// take the minimum partition since replies will be sent to the minimum partition
|
||||
const firstPartition = previousAssignment[assignee][topic];
|
||||
|
||||
// create the assignment with the first partition
|
||||
assignment[assignee][topic].push(firstPartition);
|
||||
|
||||
// find and remove this topic and partition from the topicPartitions to be assigned later
|
||||
const topicsPartitionsIndex = topicsPartitions.findIndex(
|
||||
topicPartition => {
|
||||
return (
|
||||
topicPartition.topic === topic &&
|
||||
topicPartition.partitionId === firstPartition
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
// only continue if we found a partition matching this topic
|
||||
if (topicsPartitionsIndex !== -1) {
|
||||
// remove inline
|
||||
topicsPartitions.splice(topicsPartitionsIndex, 1);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// check for member topics that have a partition length of 0
|
||||
sortedMemberIds.forEach(assignee => {
|
||||
group.topics.forEach(topic => {
|
||||
// only continue if there are no partitions for assignee's topic
|
||||
if (assignment[assignee][topic].length === 0) {
|
||||
// find the first partition for this topic
|
||||
const topicsPartitionsIndex = topicsPartitions.findIndex(
|
||||
topicPartition => {
|
||||
return topicPartition.topic === topic;
|
||||
},
|
||||
);
|
||||
|
||||
if (topicsPartitionsIndex !== -1) {
|
||||
// find and set the topic partition
|
||||
const partition =
|
||||
topicsPartitions[topicsPartitionsIndex].partitionId;
|
||||
|
||||
assignment[assignee][topic].push(partition);
|
||||
|
||||
// remove this partition from the topics partitions collection
|
||||
topicsPartitions.splice(topicsPartitionsIndex, 1);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// then balance out the rest of the topic partitions across the members
|
||||
const insertAssignmentsByTopic = (topicPartition, i) => {
|
||||
const assignee = sortedMemberIds[i % membersCount];
|
||||
|
||||
assignment[assignee][topicPartition.topic].push(
|
||||
topicPartition.partitionId,
|
||||
);
|
||||
};
|
||||
|
||||
// build the assignments
|
||||
topicsPartitions.forEach(insertAssignmentsByTopic);
|
||||
|
||||
// encode the end result
|
||||
return Object.keys(assignment).map(memberId => ({
|
||||
memberId,
|
||||
memberAssignment: kafkaPackage.AssignerProtocol.MemberAssignment.encode({
|
||||
version: this.version,
|
||||
assignment: assignment[memberId],
|
||||
}),
|
||||
}));
|
||||
}
|
||||
|
||||
public protocol(subscription: {
|
||||
topics: string[];
|
||||
userData: Buffer;
|
||||
}): GroupState {
|
||||
const stringifiedUserData = JSON.stringify({
|
||||
previousAssignment: this.getPreviousAssignment(),
|
||||
});
|
||||
subscription.userData = Buffer.from(stringifiedUserData);
|
||||
|
||||
return {
|
||||
name: this.name,
|
||||
metadata: kafkaPackage.AssignerProtocol.MemberMetadata.encode({
|
||||
version: this.version,
|
||||
topics: subscription.topics,
|
||||
userData: subscription.userData,
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
public getPreviousAssignment() {
|
||||
return this.clientKafka.getConsumerAssignments();
|
||||
}
|
||||
|
||||
public decodeMember(member: GroupMember) {
|
||||
const memberMetadata = kafkaPackage.AssignerProtocol.MemberMetadata.decode(
|
||||
member.memberMetadata,
|
||||
) as MemberMetadata;
|
||||
const memberUserData = JSON.parse(memberMetadata.userData.toString());
|
||||
|
||||
return {
|
||||
memberId: member.memberId,
|
||||
previousAssignment: memberUserData.previousAssignment,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
import { loadPackage } from '@nestjs/common/utils/load-package.util';
|
||||
import {
|
||||
Cluster,
|
||||
GroupMember,
|
||||
GroupMemberAssignment,
|
||||
GroupState,
|
||||
MemberMetadata,
|
||||
} from '../external/kafka.interface';
|
||||
|
||||
let kafkaPackage: any = {};
|
||||
|
||||
const time = process.hrtime();
|
||||
|
||||
export class KafkaRoundRobinPartitionAssigner {
|
||||
readonly name = 'RoundRobinByTime';
|
||||
readonly version = 1;
|
||||
|
||||
constructor(private readonly config: { cluster: Cluster }) {
|
||||
kafkaPackage = loadPackage(
|
||||
'kafkajs',
|
||||
KafkaRoundRobinPartitionAssigner.name,
|
||||
() => require('kafkajs'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This process can result in imbalanced assignments
|
||||
* @param {array} members array of members, e.g: [{ memberId: 'test-5f93f5a3' }]
|
||||
* @param {array} topics
|
||||
* @param {Buffer} userData
|
||||
* @returns {array} object partitions per topic per member
|
||||
*/
|
||||
public async assign(group: {
|
||||
members: GroupMember[];
|
||||
topics: string[];
|
||||
userData: Buffer;
|
||||
}): Promise<GroupMemberAssignment[]> {
|
||||
const membersCount = group.members.length;
|
||||
const assignment = {};
|
||||
|
||||
const sortedMembers = group.members
|
||||
.map(member => this.mapToTimeAndMemberId(member))
|
||||
.sort((a, b) => this.sortByTime(a, b))
|
||||
.map(member => member.memberId);
|
||||
|
||||
sortedMembers.forEach(memberId => {
|
||||
assignment[memberId] = {};
|
||||
});
|
||||
|
||||
const insertAssignmentsByTopic = (topic: string) => {
|
||||
const partitionMetadata = this.config.cluster.findTopicPartitionMetadata(
|
||||
topic,
|
||||
);
|
||||
const partitions = partitionMetadata.map(m => m.partitionId);
|
||||
sortedMembers.forEach((memberId, i) => {
|
||||
if (!assignment[memberId][topic]) {
|
||||
assignment[memberId][topic] = [];
|
||||
}
|
||||
|
||||
assignment[memberId][topic].push(
|
||||
...partitions.filter(id => id % membersCount === i),
|
||||
);
|
||||
});
|
||||
};
|
||||
group.topics.forEach(insertAssignmentsByTopic);
|
||||
|
||||
return Object.keys(assignment).map(memberId => ({
|
||||
memberId,
|
||||
memberAssignment: kafkaPackage.AssignerProtocol.MemberAssignment.encode({
|
||||
version: this.version,
|
||||
assignment: assignment[memberId],
|
||||
userData: group.userData,
|
||||
}),
|
||||
}));
|
||||
}
|
||||
|
||||
public protocol(subscription: {
|
||||
topics: string[];
|
||||
userData: Buffer;
|
||||
}): GroupState {
|
||||
const stringifiedTimeObject = JSON.stringify({
|
||||
time: this.getTime(),
|
||||
});
|
||||
subscription.userData = Buffer.from(stringifiedTimeObject);
|
||||
return {
|
||||
name: this.name,
|
||||
metadata: kafkaPackage.AssignerProtocol.MemberMetadata.encode({
|
||||
version: this.version,
|
||||
topics: subscription.topics,
|
||||
userData: subscription.userData,
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
public getTime(): [number, number] {
|
||||
return time;
|
||||
}
|
||||
|
||||
public mapToTimeAndMemberId(member: GroupMember) {
|
||||
const memberMetadata = kafkaPackage.AssignerProtocol.MemberMetadata.decode(
|
||||
member.memberMetadata,
|
||||
) as MemberMetadata;
|
||||
const memberUserData = JSON.parse(memberMetadata.userData.toString());
|
||||
|
||||
return {
|
||||
memberId: member.memberId,
|
||||
time: memberUserData.time,
|
||||
};
|
||||
}
|
||||
|
||||
public sortByTime(a: Record<'time', number[]>, b: Record<'time', number[]>) {
|
||||
// if seconds are equal sort by nanoseconds
|
||||
if (a.time[0] === b.time[0]) {
|
||||
return a.time[1] - b.time[1];
|
||||
}
|
||||
// sort by seconds
|
||||
return a.time[0] - b.time[0];
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,20 @@
|
||||
import { Transport } from '../enums/transport.enum';
|
||||
import { ChannelOptions } from '../external/grpc-options.interface';
|
||||
import {
|
||||
CompressionTypes,
|
||||
ConsumerConfig,
|
||||
ConsumerRunConfig,
|
||||
ConsumerSubscribeTopic,
|
||||
KafkaConfig,
|
||||
ProducerConfig,
|
||||
} from '../external/kafka-options.interface';
|
||||
ProducerRecord,
|
||||
} from '../external/kafka.interface';
|
||||
import { MqttClientOptions } from '../external/mqtt-options.interface';
|
||||
import { ClientOpts } from '../external/redis.interface';
|
||||
import { RmqUrl } from '../external/rmq-url.interface';
|
||||
import { Server } from '../server/server';
|
||||
import { CustomTransportStrategy } from './custom-transport-strategy.interface';
|
||||
import { Deserializer } from './deserializer.interface';
|
||||
import { Serializer } from './serializer.interface';
|
||||
import { RmqUrl } from '../external/rmq-url.interface';
|
||||
|
||||
export type MicroserviceOptions =
|
||||
| GrpcOptions
|
||||
@@ -127,8 +129,8 @@ export interface RmqOptions {
|
||||
queue?: string;
|
||||
prefetchCount?: number;
|
||||
isGlobalPrefetchCount?: boolean;
|
||||
queueOptions?: any;
|
||||
socketOptions?: any;
|
||||
queueOptions?: any; // AmqplibQueueOptions;
|
||||
socketOptions?: any; // AmqpConnectionManagerSocketOptions;
|
||||
noAck?: boolean;
|
||||
serializer?: Serializer;
|
||||
deserializer?: Deserializer;
|
||||
@@ -140,24 +142,13 @@ export interface RmqOptions {
|
||||
export interface KafkaOptions {
|
||||
transport?: Transport.KAFKA;
|
||||
options?: {
|
||||
postfixId?: string;
|
||||
client?: KafkaConfig;
|
||||
consumer?: ConsumerConfig;
|
||||
run?: {
|
||||
autoCommit?: boolean;
|
||||
autoCommitInterval?: number | null;
|
||||
autoCommitThreshold?: number | null;
|
||||
eachBatchAutoResolve?: boolean;
|
||||
partitionsConsumedConcurrently?: number;
|
||||
};
|
||||
subscribe?: {
|
||||
fromBeginning?: boolean;
|
||||
};
|
||||
run?: Omit<ConsumerRunConfig, 'eachBatch' | 'eachMessage'>;
|
||||
subscribe?: Omit<ConsumerSubscribeTopic, 'topic'>;
|
||||
producer?: ProducerConfig;
|
||||
send?: {
|
||||
acks?: number;
|
||||
timeout?: number;
|
||||
compression?: CompressionTypes;
|
||||
};
|
||||
send?: Omit<ProducerRecord, 'topics' | 'messages'>;
|
||||
serializer?: Serializer;
|
||||
deserializer?: Deserializer;
|
||||
};
|
||||
|
||||
@@ -123,7 +123,7 @@ export class NestMicroservice
|
||||
!this.isInitialized && (await this.registerModules());
|
||||
|
||||
this.logger.log(MESSAGES.MICROSERVICE_READY);
|
||||
return new Promise(resolve => this.server.listen(resolve));
|
||||
return new Promise<void>(resolve => this.server.listen(resolve));
|
||||
}
|
||||
|
||||
public async close(): Promise<any> {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nestjs/microservices",
|
||||
"version": "7.5.5",
|
||||
"version": "7.6.1",
|
||||
"description": "Nest - modern, fast, powerful node.js web framework (@microservices)",
|
||||
"author": "Kamil Mysliwiec",
|
||||
"license": "MIT",
|
||||
@@ -22,12 +22,51 @@
|
||||
"tslib": "2.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/common": "7.5.5",
|
||||
"@nestjs/core": "7.5.5"
|
||||
"@nestjs/common": "7.6.1",
|
||||
"@nestjs/core": "7.6.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@nestjs/common": "^7.0.0",
|
||||
"@nestjs/core": "^7.0.0",
|
||||
"@nestjs/websockets": "^7.0.0",
|
||||
"amqp-connection-manager": "*",
|
||||
"amqplib": "*",
|
||||
"cache-manager": "*",
|
||||
"grpc": "*",
|
||||
"kafkajs": "*",
|
||||
"mqtt": "*",
|
||||
"nats": "*",
|
||||
"redis": "*",
|
||||
"reflect-metadata": "^0.1.12",
|
||||
"rxjs": "^6.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@nestjs/websockets": {
|
||||
"optional": true
|
||||
},
|
||||
"cache-manager": {
|
||||
"optional": true
|
||||
},
|
||||
"grpc": {
|
||||
"optional": true
|
||||
},
|
||||
"kafkajs": {
|
||||
"optional": true
|
||||
},
|
||||
"mqtt": {
|
||||
"optional": true
|
||||
},
|
||||
"nats": {
|
||||
"optional": true
|
||||
},
|
||||
"redis": {
|
||||
"optional": true
|
||||
},
|
||||
"amqplib": {
|
||||
"optional": true
|
||||
},
|
||||
"amqp-connection-manager": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,17 +50,16 @@ export class ServerKafka extends Server implements CustomTransportStrategy {
|
||||
this.getOptionsProp(this.options, 'client') || ({} as KafkaConfig);
|
||||
const consumerOptions =
|
||||
this.getOptionsProp(this.options, 'consumer') || ({} as ConsumerConfig);
|
||||
const postfixId =
|
||||
this.getOptionsProp(this.options, 'postfixId') || '-server';
|
||||
|
||||
this.brokers = clientOptions.brokers || [KAFKA_DEFAULT_BROKER];
|
||||
|
||||
// append a unique id to the clientId and groupId
|
||||
// so they don't collide with a microservices client
|
||||
this.clientId =
|
||||
(clientOptions.clientId || KAFKA_DEFAULT_CLIENT) +
|
||||
(clientOptions.clientIdPostfix || '-server');
|
||||
this.groupId =
|
||||
(consumerOptions.groupId || KAFKA_DEFAULT_GROUP) +
|
||||
(clientOptions.clientIdPostfix || '-server');
|
||||
(clientOptions.clientId || KAFKA_DEFAULT_CLIENT) + postfixId;
|
||||
this.groupId = (consumerOptions.groupId || KAFKA_DEFAULT_GROUP) + postfixId;
|
||||
|
||||
kafkaPackage = this.loadPackage('kafkajs', ServerKafka.name, () =>
|
||||
require('kafkajs'),
|
||||
@@ -75,9 +74,9 @@ export class ServerKafka extends Server implements CustomTransportStrategy {
|
||||
await this.start(callback);
|
||||
}
|
||||
|
||||
public close(): void {
|
||||
this.consumer && this.consumer.disconnect();
|
||||
this.producer && this.producer.disconnect();
|
||||
public async close(): Promise<void> {
|
||||
this.consumer && (await this.consumer.disconnect());
|
||||
this.producer && (await this.producer.disconnect());
|
||||
this.consumer = null;
|
||||
this.producer = null;
|
||||
this.client = null;
|
||||
|
||||
@@ -18,13 +18,13 @@ import {
|
||||
} from '../constants';
|
||||
import { RmqContext } from '../ctx-host';
|
||||
import { Transport } from '../enums';
|
||||
import { RmqUrl } from '../external/rmq-url.interface';
|
||||
import { CustomTransportStrategy, RmqOptions } from '../interfaces';
|
||||
import {
|
||||
IncomingRequest,
|
||||
OutgoingResponse,
|
||||
} from '../interfaces/packet.interface';
|
||||
import { Server } from './server';
|
||||
import { RmqUrl } from '../external/rmq-url.interface';
|
||||
|
||||
let rqmPackage: any = {};
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ import * as sinon from 'sinon';
|
||||
import { ClientKafka } from '../../client/client-kafka';
|
||||
import { NO_MESSAGE_HANDLER } from '../../constants';
|
||||
import { KafkaHeaders } from '../../enums';
|
||||
import { InvalidKafkaClientTopicPartitionException } from '../../errors/invalid-kafka-client-topic-partition.exception';
|
||||
import { InvalidKafkaClientTopicException } from '../../errors/invalid-kafka-client-topic.exception';
|
||||
import {
|
||||
ConsumerGroupJoinEvent,
|
||||
@@ -269,6 +268,7 @@ describe('ClientKafka', () => {
|
||||
|
||||
expect(createClientStub.calledOnce).to.be.true;
|
||||
expect(producerStub.calledOnce).to.be.true;
|
||||
|
||||
expect(consumerStub.calledOnce).to.be.true;
|
||||
|
||||
expect(on.calledOnce).to.be.true;
|
||||
@@ -314,13 +314,19 @@ describe('ClientKafka', () => {
|
||||
memberId: 'member-1',
|
||||
memberAssignment: {
|
||||
'topic-a': [0, 1, 2],
|
||||
'topic-b': [3, 4, 5],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
client['setConsumerAssignments'](consumerAssignments);
|
||||
|
||||
expect(client['consumerAssignments']).to.deep.eq(
|
||||
consumerAssignments.payload.memberAssignment,
|
||||
// consumerAssignments.payload.memberAssignment,
|
||||
{
|
||||
'topic-a': 0,
|
||||
'topic-b': 3,
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -493,10 +499,22 @@ describe('ClientKafka', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('getConsumerAssignments', () => {
|
||||
it('should get consumer assignments', () => {
|
||||
client['consumerAssignments'] = {
|
||||
[replyTopic]: 0,
|
||||
};
|
||||
|
||||
const result = client.getConsumerAssignments();
|
||||
|
||||
expect(result).to.deep.eq(client['consumerAssignments']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getReplyTopicPartition', () => {
|
||||
it('should get reply partition', () => {
|
||||
client['consumerAssignments'] = {
|
||||
[replyTopic]: [0],
|
||||
[replyTopic]: 0,
|
||||
};
|
||||
|
||||
const result = client['getReplyTopicPartition'](replyTopic);
|
||||
@@ -504,19 +522,17 @@ describe('ClientKafka', () => {
|
||||
expect(result).to.eq('0');
|
||||
});
|
||||
|
||||
it('should throw error when the topic is being consumed but is not assigned partitions', () => {
|
||||
client['consumerAssignments'] = {
|
||||
[replyTopic]: [],
|
||||
};
|
||||
it('should throw error when the topic is not being consumed', () => {
|
||||
client['consumerAssignments'] = {};
|
||||
|
||||
expect(() => client['getReplyTopicPartition'](replyTopic)).to.throw(
|
||||
InvalidKafkaClientTopicPartitionException,
|
||||
InvalidKafkaClientTopicException,
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw error when the topic is not being consumer', () => {
|
||||
it('should throw error when the topic is not being consumed', () => {
|
||||
client['consumerAssignments'] = {
|
||||
[topic]: [],
|
||||
[topic]: undefined,
|
||||
};
|
||||
|
||||
expect(() => client['getReplyTopicPartition'](replyTopic)).to.throw(
|
||||
@@ -568,7 +584,7 @@ describe('ClientKafka', () => {
|
||||
|
||||
// set
|
||||
client['consumerAssignments'] = {
|
||||
[replyTopic]: [parseFloat(replyPartition)],
|
||||
[replyTopic]: parseFloat(replyPartition),
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,286 @@
|
||||
import { expect } from 'chai';
|
||||
import * as sinon from 'sinon';
|
||||
import * as Kafka from 'kafkajs';
|
||||
import { KafkaReplyPartitionAssigner } from '../../helpers/kafka-reply-partition-assigner';
|
||||
import { ClientKafka } from '../../client/client-kafka';
|
||||
|
||||
describe('kafka reply partition assigner', () => {
|
||||
let cluster, topics, metadata, assigner, client;
|
||||
|
||||
let getConsumerAssignments: sinon.SinonSpy;
|
||||
let getPreviousAssignment: sinon.SinonSpy;
|
||||
|
||||
beforeEach(() => {
|
||||
metadata = {};
|
||||
cluster = { findTopicPartitionMetadata: topic => metadata[topic] };
|
||||
client = new ClientKafka({});
|
||||
assigner = new KafkaReplyPartitionAssigner(client, { cluster });
|
||||
topics = ['topic-A', 'topic-B'];
|
||||
|
||||
getConsumerAssignments = sinon.spy(client, 'getConsumerAssignments');
|
||||
getPreviousAssignment = sinon.spy(assigner, 'getPreviousAssignment');
|
||||
|
||||
// reset previous assignments
|
||||
(client as any).consumerAssignments = {};
|
||||
});
|
||||
|
||||
describe('assign', () => {
|
||||
it('assign all partitions evenly', async () => {
|
||||
metadata['topic-A'] = Array(14)
|
||||
.fill(1)
|
||||
.map((_, i) => ({ partitionId: i }));
|
||||
|
||||
metadata['topic-B'] = Array(5)
|
||||
.fill(1)
|
||||
.map((_, i) => ({ partitionId: i }));
|
||||
|
||||
const members = [
|
||||
{
|
||||
memberId: 'member-3',
|
||||
memberMetadata: Kafka.AssignerProtocol.MemberMetadata.encode({
|
||||
version: assigner.version,
|
||||
topics: ['topic-A', 'topic-B'],
|
||||
userData: Buffer.from(
|
||||
JSON.stringify({
|
||||
previousAssignment: {},
|
||||
}),
|
||||
),
|
||||
}),
|
||||
},
|
||||
{
|
||||
memberId: 'member-1',
|
||||
memberMetadata: Kafka.AssignerProtocol.MemberMetadata.encode({
|
||||
version: assigner.version,
|
||||
topics: ['topic-A', 'topic-B'],
|
||||
userData: Buffer.from(
|
||||
JSON.stringify({
|
||||
previousAssignment: {},
|
||||
}),
|
||||
),
|
||||
}),
|
||||
},
|
||||
{
|
||||
memberId: 'member-4',
|
||||
memberMetadata: Kafka.AssignerProtocol.MemberMetadata.encode({
|
||||
version: assigner.version,
|
||||
topics: ['topic-A', 'topic-B'],
|
||||
userData: Buffer.from(
|
||||
JSON.stringify({
|
||||
previousAssignment: {},
|
||||
}),
|
||||
),
|
||||
}),
|
||||
},
|
||||
{
|
||||
memberId: 'member-2',
|
||||
memberMetadata: Kafka.AssignerProtocol.MemberMetadata.encode({
|
||||
version: assigner.version,
|
||||
topics: ['topic-A', 'topic-B'],
|
||||
userData: Buffer.from(
|
||||
JSON.stringify({
|
||||
previousAssignment: {},
|
||||
}),
|
||||
),
|
||||
}),
|
||||
},
|
||||
];
|
||||
|
||||
const assignment = await assigner.assign({ members, topics });
|
||||
|
||||
expect(assignment).to.deep.equal([
|
||||
{
|
||||
memberId: 'member-1',
|
||||
memberAssignment: Kafka.AssignerProtocol.MemberAssignment.encode({
|
||||
version: assigner.version,
|
||||
assignment: {
|
||||
'topic-A': [0, 4, 8, 12],
|
||||
'topic-B': [0],
|
||||
},
|
||||
userData: Buffer.alloc(0),
|
||||
}),
|
||||
},
|
||||
{
|
||||
memberId: 'member-2',
|
||||
memberAssignment: Kafka.AssignerProtocol.MemberAssignment.encode({
|
||||
version: assigner.version,
|
||||
assignment: {
|
||||
'topic-A': [1, 5, 9, 13],
|
||||
'topic-B': [1],
|
||||
},
|
||||
userData: Buffer.alloc(0),
|
||||
}),
|
||||
},
|
||||
{
|
||||
memberId: 'member-3',
|
||||
memberAssignment: Kafka.AssignerProtocol.MemberAssignment.encode({
|
||||
version: assigner.version,
|
||||
assignment: {
|
||||
'topic-A': [2, 6, 10],
|
||||
'topic-B': [2, 4],
|
||||
},
|
||||
userData: Buffer.alloc(0),
|
||||
}),
|
||||
},
|
||||
{
|
||||
memberId: 'member-4',
|
||||
memberAssignment: Kafka.AssignerProtocol.MemberAssignment.encode({
|
||||
version: assigner.version,
|
||||
assignment: {
|
||||
'topic-A': [3, 7, 11],
|
||||
'topic-B': [3],
|
||||
},
|
||||
userData: Buffer.alloc(0),
|
||||
}),
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('re-assign', () => {
|
||||
it('assign all partitions evenly', async () => {
|
||||
metadata['topic-A'] = Array(11)
|
||||
.fill(1)
|
||||
.map((_, i) => ({ partitionId: i }));
|
||||
|
||||
metadata['topic-B'] = Array(7)
|
||||
.fill(1)
|
||||
.map((_, i) => ({ partitionId: i }));
|
||||
|
||||
const members = [
|
||||
{
|
||||
memberId: 'member-3',
|
||||
memberMetadata: Kafka.AssignerProtocol.MemberMetadata.encode({
|
||||
version: assigner.version,
|
||||
topics: ['topic-A', 'topic-B'],
|
||||
userData: Buffer.from(
|
||||
JSON.stringify({
|
||||
previousAssignment: {
|
||||
'topic-A': 0,
|
||||
'topic-B': 0,
|
||||
},
|
||||
}),
|
||||
),
|
||||
}),
|
||||
},
|
||||
{
|
||||
memberId: 'member-1',
|
||||
memberMetadata: Kafka.AssignerProtocol.MemberMetadata.encode({
|
||||
version: assigner.version,
|
||||
topics: ['topic-A', 'topic-B'],
|
||||
userData: Buffer.from(
|
||||
JSON.stringify({
|
||||
previousAssignment: {
|
||||
'topic-A': 1,
|
||||
'topic-B': 1,
|
||||
},
|
||||
}),
|
||||
),
|
||||
}),
|
||||
},
|
||||
{
|
||||
memberId: 'member-4',
|
||||
memberMetadata: Kafka.AssignerProtocol.MemberMetadata.encode({
|
||||
version: assigner.version,
|
||||
topics: ['topic-A', 'topic-B'],
|
||||
userData: Buffer.from(
|
||||
JSON.stringify({
|
||||
previousAssignment: {
|
||||
'topic-A': 2,
|
||||
},
|
||||
}),
|
||||
),
|
||||
}),
|
||||
},
|
||||
{
|
||||
memberId: 'member-2',
|
||||
memberMetadata: Kafka.AssignerProtocol.MemberMetadata.encode({
|
||||
version: assigner.version,
|
||||
topics: ['topic-A', 'topic-B'],
|
||||
userData: Buffer.from(
|
||||
JSON.stringify({
|
||||
previousAssignment: {},
|
||||
}),
|
||||
),
|
||||
}),
|
||||
},
|
||||
];
|
||||
|
||||
const assignment = await assigner.assign({ members, topics });
|
||||
|
||||
expect(assignment).to.deep.equal([
|
||||
{
|
||||
memberId: 'member-1',
|
||||
memberAssignment: Kafka.AssignerProtocol.MemberAssignment.encode({
|
||||
version: assigner.version,
|
||||
assignment: {
|
||||
'topic-A': [1, 4, 8],
|
||||
'topic-B': [1, 5],
|
||||
},
|
||||
userData: Buffer.alloc(0),
|
||||
}),
|
||||
},
|
||||
{
|
||||
memberId: 'member-2',
|
||||
memberAssignment: Kafka.AssignerProtocol.MemberAssignment.encode({
|
||||
version: assigner.version,
|
||||
assignment: {
|
||||
'topic-A': [3, 5, 9],
|
||||
'topic-B': [2, 6],
|
||||
},
|
||||
userData: Buffer.alloc(0),
|
||||
}),
|
||||
},
|
||||
{
|
||||
memberId: 'member-3',
|
||||
memberAssignment: Kafka.AssignerProtocol.MemberAssignment.encode({
|
||||
version: assigner.version,
|
||||
assignment: {
|
||||
'topic-A': [0, 6, 10],
|
||||
'topic-B': [0],
|
||||
},
|
||||
userData: Buffer.alloc(0),
|
||||
}),
|
||||
},
|
||||
{
|
||||
memberId: 'member-4',
|
||||
memberAssignment: Kafka.AssignerProtocol.MemberAssignment.encode({
|
||||
version: assigner.version,
|
||||
assignment: {
|
||||
'topic-A': [2, 7],
|
||||
'topic-B': [3, 4],
|
||||
},
|
||||
userData: Buffer.alloc(0),
|
||||
}),
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('protocol', () => {
|
||||
it('returns the assigner name and metadata', () => {
|
||||
// set previous assignments
|
||||
(client as any).consumerAssignments = {
|
||||
'topic-A': 0,
|
||||
'topic-B': 1,
|
||||
};
|
||||
|
||||
const protocol = assigner.protocol({ topics });
|
||||
|
||||
expect(getPreviousAssignment.calledOnce).to.be.true;
|
||||
expect(getConsumerAssignments.calledOnce).to.be.true;
|
||||
|
||||
expect(protocol).to.deep.equal({
|
||||
name: assigner.name,
|
||||
metadata: Kafka.AssignerProtocol.MemberMetadata.encode({
|
||||
version: assigner.version,
|
||||
topics,
|
||||
userData: Buffer.from(
|
||||
JSON.stringify({
|
||||
previousAssignment: (client as any).consumerAssignments,
|
||||
}),
|
||||
),
|
||||
}),
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,143 +0,0 @@
|
||||
import { expect } from 'chai';
|
||||
import * as Kafka from 'kafkajs';
|
||||
import { KafkaRoundRobinPartitionAssigner } from '../../helpers/kafka-round-robin-partition-assigner';
|
||||
|
||||
describe('kafka round robin by time', () => {
|
||||
let cluster, topics, metadata, assigner;
|
||||
|
||||
beforeEach(() => {
|
||||
metadata = {};
|
||||
cluster = { findTopicPartitionMetadata: topic => metadata[topic] };
|
||||
assigner = new KafkaRoundRobinPartitionAssigner({ cluster });
|
||||
topics = ['topic-A', 'topic-B'];
|
||||
});
|
||||
|
||||
describe('assign', () => {
|
||||
it('assign all partitions evenly', async () => {
|
||||
metadata['topic-A'] = Array(14)
|
||||
.fill(1)
|
||||
.map((_, i) => ({ partitionId: i }));
|
||||
|
||||
metadata['topic-B'] = Array(5)
|
||||
.fill(1)
|
||||
.map((_, i) => ({ partitionId: i }));
|
||||
|
||||
const members = [
|
||||
{
|
||||
memberId: 'member-3',
|
||||
memberMetadata: Kafka.AssignerProtocol.MemberMetadata.encode({
|
||||
version: assigner.version,
|
||||
topics: ['topic-A', 'topic-B'],
|
||||
userData: Buffer.from(
|
||||
JSON.stringify({
|
||||
time: [0, 0], // process.hrtime()
|
||||
}),
|
||||
),
|
||||
}),
|
||||
},
|
||||
{
|
||||
memberId: 'member-1',
|
||||
memberMetadata: Kafka.AssignerProtocol.MemberMetadata.encode({
|
||||
version: assigner.version,
|
||||
topics: ['topic-A', 'topic-B'],
|
||||
userData: Buffer.from(
|
||||
JSON.stringify({
|
||||
time: [0, 1], // process.hrtime()
|
||||
}),
|
||||
),
|
||||
}),
|
||||
},
|
||||
{
|
||||
memberId: 'member-4',
|
||||
memberMetadata: Kafka.AssignerProtocol.MemberMetadata.encode({
|
||||
version: assigner.version,
|
||||
topics: ['topic-A', 'topic-B'],
|
||||
userData: Buffer.from(
|
||||
JSON.stringify({
|
||||
time: [1, 1], // process.hrtime()
|
||||
}),
|
||||
),
|
||||
}),
|
||||
},
|
||||
{
|
||||
memberId: 'member-2',
|
||||
memberMetadata: Kafka.AssignerProtocol.MemberMetadata.encode({
|
||||
version: assigner.version,
|
||||
topics: ['topic-A', 'topic-B'],
|
||||
userData: Buffer.from(
|
||||
JSON.stringify({
|
||||
time: [2, 0], // process.hrtime()
|
||||
}),
|
||||
),
|
||||
}),
|
||||
},
|
||||
];
|
||||
|
||||
const assignment = await assigner.assign({ members, topics });
|
||||
|
||||
expect(assignment).to.deep.equal([
|
||||
{
|
||||
memberId: 'member-3',
|
||||
memberAssignment: Kafka.AssignerProtocol.MemberAssignment.encode({
|
||||
version: assigner.version,
|
||||
assignment: {
|
||||
'topic-A': [0, 4, 8, 12],
|
||||
'topic-B': [0, 4],
|
||||
},
|
||||
userData: Buffer.alloc(0),
|
||||
}),
|
||||
},
|
||||
{
|
||||
memberId: 'member-1',
|
||||
memberAssignment: Kafka.AssignerProtocol.MemberAssignment.encode({
|
||||
version: assigner.version,
|
||||
assignment: {
|
||||
'topic-A': [1, 5, 9, 13],
|
||||
'topic-B': [1],
|
||||
},
|
||||
userData: Buffer.alloc(0),
|
||||
}),
|
||||
},
|
||||
{
|
||||
memberId: 'member-4',
|
||||
memberAssignment: Kafka.AssignerProtocol.MemberAssignment.encode({
|
||||
version: assigner.version,
|
||||
assignment: {
|
||||
'topic-A': [2, 6, 10],
|
||||
'topic-B': [2],
|
||||
},
|
||||
userData: Buffer.alloc(0),
|
||||
}),
|
||||
},
|
||||
{
|
||||
memberId: 'member-2',
|
||||
memberAssignment: Kafka.AssignerProtocol.MemberAssignment.encode({
|
||||
version: assigner.version,
|
||||
assignment: {
|
||||
'topic-A': [3, 7, 11],
|
||||
'topic-B': [3],
|
||||
},
|
||||
userData: Buffer.alloc(0),
|
||||
}),
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('protocol', () => {
|
||||
it('returns the assigner name and metadata', () => {
|
||||
expect(assigner.protocol({ topics })).to.deep.equal({
|
||||
name: assigner.name,
|
||||
metadata: Kafka.AssignerProtocol.MemberMetadata.encode({
|
||||
version: assigner.version,
|
||||
topics,
|
||||
userData: Buffer.from(
|
||||
JSON.stringify({
|
||||
time: assigner.getTime(),
|
||||
}),
|
||||
),
|
||||
}),
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -21,7 +21,7 @@ describe('JsonSocket connection', () => {
|
||||
new Promise(callback => {
|
||||
clientSocket.sendMessage({ type: 'ping' }, callback);
|
||||
}),
|
||||
new Promise(callback => {
|
||||
new Promise<void>(callback => {
|
||||
clientSocket.on(MESSAGE_EVENT, (message: string) => {
|
||||
expect(message).to.deep.equal({ type: 'pong' });
|
||||
callback();
|
||||
@@ -53,16 +53,16 @@ describe('JsonSocket connection', () => {
|
||||
expect(clientSocket['isClosed']).to.equal(false);
|
||||
expect(serverSocket['isClosed']).to.equal(false);
|
||||
Promise.all([
|
||||
new Promise(callback => {
|
||||
new Promise<void>(callback => {
|
||||
clientSocket.sendMessage(longPayload, callback);
|
||||
}),
|
||||
new Promise(callback => {
|
||||
new Promise<void>(callback => {
|
||||
clientSocket.on(MESSAGE_EVENT, (message: { type: 'pong' }) => {
|
||||
expect(message).to.deep.equal({ type: 'pong' });
|
||||
callback();
|
||||
});
|
||||
}),
|
||||
new Promise(callback => {
|
||||
new Promise<void>(callback => {
|
||||
serverSocket.on(MESSAGE_EVENT, (message: { type: 'pong' }) => {
|
||||
expect(message).to.deep.equal(longPayload);
|
||||
serverSocket.sendMessage({ type: 'pong' }, callback);
|
||||
@@ -85,7 +85,7 @@ describe('JsonSocket connection', () => {
|
||||
return done(err);
|
||||
}
|
||||
Promise.all([
|
||||
new Promise(callback =>
|
||||
new Promise<void>(callback =>
|
||||
Promise.all(
|
||||
helpers
|
||||
.range(1, 100)
|
||||
@@ -97,7 +97,7 @@ describe('JsonSocket connection', () => {
|
||||
),
|
||||
).then(_ => callback()),
|
||||
),
|
||||
new Promise(callback => {
|
||||
new Promise<void>(callback => {
|
||||
let lastNumber = 0;
|
||||
serverSocket.on(MESSAGE_EVENT, (message: { number: number }) => {
|
||||
expect(message.number).to.deep.equal(lastNumber + 1);
|
||||
@@ -128,7 +128,7 @@ describe('JsonSocket connection', () => {
|
||||
})
|
||||
.then(
|
||||
() =>
|
||||
new Promise(callback => {
|
||||
new Promise<void>(callback => {
|
||||
expect(clientSocket['isClosed']).to.equal(true);
|
||||
expect(serverSocket['isClosed']).to.equal(true);
|
||||
callback();
|
||||
@@ -154,7 +154,7 @@ describe('JsonSocket connection', () => {
|
||||
})
|
||||
.then(
|
||||
() =>
|
||||
new Promise(callback => {
|
||||
new Promise<void>(callback => {
|
||||
expect(clientSocket['isClosed']).to.equal(true);
|
||||
expect(serverSocket['isClosed']).to.equal(true);
|
||||
callback();
|
||||
|
||||
@@ -135,8 +135,8 @@ describe('ServerKafka', () => {
|
||||
(server as any).consumer = consumer;
|
||||
(server as any).producer = producer;
|
||||
});
|
||||
it('should close server', () => {
|
||||
server.close();
|
||||
it('should close server', async () => {
|
||||
await server.close();
|
||||
|
||||
expect(consumer.disconnect.calledOnce).to.be.true;
|
||||
expect(producer.disconnect.calledOnce).to.be.true;
|
||||
|
||||
@@ -39,7 +39,7 @@ export function AnyFilesInterceptor(
|
||||
): Promise<Observable<any>> {
|
||||
const ctx = context.switchToHttp();
|
||||
|
||||
await new Promise((resolve, reject) =>
|
||||
await new Promise<void>((resolve, reject) =>
|
||||
this.multer.any()(ctx.getRequest(), ctx.getResponse(), (err: any) => {
|
||||
if (err) {
|
||||
const error = transformException(err);
|
||||
|
||||
@@ -43,7 +43,7 @@ export function FileFieldsInterceptor(
|
||||
): Promise<Observable<any>> {
|
||||
const ctx = context.switchToHttp();
|
||||
|
||||
await new Promise((resolve, reject) =>
|
||||
await new Promise<void>((resolve, reject) =>
|
||||
this.multer.fields(uploadFields)(
|
||||
ctx.getRequest(),
|
||||
ctx.getResponse(),
|
||||
|
||||
@@ -40,7 +40,7 @@ export function FileInterceptor(
|
||||
): Promise<Observable<any>> {
|
||||
const ctx = context.switchToHttp();
|
||||
|
||||
await new Promise((resolve, reject) =>
|
||||
await new Promise<void>((resolve, reject) =>
|
||||
this.multer.single(fieldName)(
|
||||
ctx.getRequest(),
|
||||
ctx.getResponse(),
|
||||
|
||||
@@ -41,7 +41,7 @@ export function FilesInterceptor(
|
||||
): Promise<Observable<any>> {
|
||||
const ctx = context.switchToHttp();
|
||||
|
||||
await new Promise((resolve, reject) =>
|
||||
await new Promise<void>((resolve, reject) =>
|
||||
this.multer.array(fieldName, maxCount)(
|
||||
ctx.getRequest(),
|
||||
ctx.getResponse(),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nestjs/platform-express",
|
||||
"version": "7.5.5",
|
||||
"version": "7.6.1",
|
||||
"description": "Nest - modern, fast, powerful node.js web framework (@platform-express)",
|
||||
"author": "Kamil Mysliwiec",
|
||||
"license": "MIT",
|
||||
@@ -24,8 +24,8 @@
|
||||
"tslib": "2.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/common": "7.5.5",
|
||||
"@nestjs/core": "7.5.5"
|
||||
"@nestjs/common": "7.6.1",
|
||||
"@nestjs/core": "7.6.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@nestjs/common": "^7.0.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nestjs/platform-fastify",
|
||||
"version": "7.5.5",
|
||||
"version": "7.6.1",
|
||||
"description": "Nest - modern, fast, powerful node.js web framework (@platform-fastify)",
|
||||
"author": "Kamil Mysliwiec",
|
||||
"license": "MIT",
|
||||
@@ -18,7 +18,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"fastify": "3.9.1",
|
||||
"fastify-cors": "5.0.0",
|
||||
"fastify-cors": "5.1.0",
|
||||
"fastify-formbody": "5.0.0",
|
||||
"light-my-request": "4.3.0",
|
||||
"middie": "5.2.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nestjs/platform-socket.io",
|
||||
"version": "7.5.5",
|
||||
"version": "7.6.1",
|
||||
"description": "Nest - modern, fast, powerful node.js web framework (@platform-socket.io)",
|
||||
"author": "Kamil Mysliwiec",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nestjs/platform-ws",
|
||||
"version": "7.5.5",
|
||||
"version": "7.6.1",
|
||||
"description": "Nest - modern, fast, powerful node.js web framework (@platform-ws)",
|
||||
"author": "Kamil Mysliwiec",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nestjs/testing",
|
||||
"version": "7.5.5",
|
||||
"version": "7.6.1",
|
||||
"description": "Nest - modern, fast, powerful node.js web framework (@testing)",
|
||||
"author": "Kamil Mysliwiec",
|
||||
"license": "MIT",
|
||||
@@ -22,6 +22,16 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@nestjs/common": "^7.0.0",
|
||||
"@nestjs/core": "^7.0.0"
|
||||
"@nestjs/core": "^7.0.0",
|
||||
"@nestjs/microservices": "^7.0.0",
|
||||
"@nestjs/platform-express": "^7.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@nestjs/microservices": {
|
||||
"optional": true
|
||||
},
|
||||
"@nestjs/platform-express": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nestjs/websockets",
|
||||
"version": "7.5.5",
|
||||
"version": "7.6.1",
|
||||
"description": "Nest - modern, fast, powerful node.js web framework (@websockets)",
|
||||
"author": "Kamil Mysliwiec",
|
||||
"license": "MIT",
|
||||
@@ -16,12 +16,13 @@
|
||||
"tslib": "2.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/common": "7.5.5",
|
||||
"@nestjs/core": "7.5.5"
|
||||
"@nestjs/common": "7.6.1",
|
||||
"@nestjs/core": "7.6.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@nestjs/common": "^7.0.0",
|
||||
"@nestjs/core": "^7.0.0",
|
||||
"reflect-metadata": "^0.1.12",
|
||||
"rxjs": "^6.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
8058
sample/01-cats-app/package-lock.json
generated
8058
sample/01-cats-app/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -19,9 +19,9 @@
|
||||
"test:e2e": "jest --config ./e2e/jest-e2e.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/common": "7.4.4",
|
||||
"@nestjs/core": "7.4.4",
|
||||
"@nestjs/platform-express": "7.4.4",
|
||||
"@nestjs/common": "7.5.5",
|
||||
"@nestjs/core": "7.5.5",
|
||||
"@nestjs/platform-express": "7.5.5",
|
||||
"class-transformer": "0.3.1",
|
||||
"class-validator": "0.12.2",
|
||||
"reflect-metadata": "0.1.13",
|
||||
@@ -29,26 +29,26 @@
|
||||
"rxjs": "6.6.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/cli": "7.5.1",
|
||||
"@nestjs/schematics": "7.2.1",
|
||||
"@nestjs/testing": "7.4.4",
|
||||
"@types/express": "4.17.8",
|
||||
"@types/jest": "26.0.15",
|
||||
"@types/node": "10.17.3",
|
||||
"@nestjs/cli": "7.5.3",
|
||||
"@nestjs/schematics": "7.2.5",
|
||||
"@nestjs/testing": "7.5.5",
|
||||
"@types/express": "4.17.9",
|
||||
"@types/jest": "26.0.18",
|
||||
"@types/node": "14.14.11",
|
||||
"@types/supertest": "2.0.10",
|
||||
"jest": "26.6.2",
|
||||
"prettier": "2.1.2",
|
||||
"supertest": "5.0.0",
|
||||
"ts-jest": "26.4.1",
|
||||
"ts-loader": "8.0.7",
|
||||
"ts-node": "9.0.0",
|
||||
"jest": "26.6.3",
|
||||
"prettier": "2.2.1",
|
||||
"supertest": "6.0.1",
|
||||
"ts-jest": "26.4.4",
|
||||
"ts-loader": "8.0.11",
|
||||
"ts-node": "9.1.1",
|
||||
"tsconfig-paths": "3.9.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.5.0",
|
||||
"@typescript-eslint/parser": "4.5.0",
|
||||
"eslint": "7.10.0",
|
||||
"eslint-config-prettier": "6.11.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.9.1",
|
||||
"@typescript-eslint/parser": "4.9.1",
|
||||
"eslint": "7.15.0",
|
||||
"eslint-config-prettier": "7.0.0",
|
||||
"eslint-plugin-import": "2.22.1",
|
||||
"typescript": "4.0.3"
|
||||
"typescript": "4.1.2"
|
||||
},
|
||||
"jest": {
|
||||
"moduleFileExtensions": [
|
||||
|
||||
8460
sample/02-gateways/package-lock.json
generated
8460
sample/02-gateways/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -19,11 +19,11 @@
|
||||
"test:e2e": "echo 'No e2e tests implemented yet.'"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/common": "7.4.4",
|
||||
"@nestjs/core": "7.4.4",
|
||||
"@nestjs/platform-express": "7.4.4",
|
||||
"@nestjs/platform-socket.io": "7.4.4",
|
||||
"@nestjs/websockets": "7.4.4",
|
||||
"@nestjs/common": "7.5.5",
|
||||
"@nestjs/core": "7.5.5",
|
||||
"@nestjs/platform-express": "7.5.5",
|
||||
"@nestjs/platform-socket.io": "7.5.5",
|
||||
"@nestjs/websockets": "7.5.5",
|
||||
"class-transformer": "0.3.1",
|
||||
"class-validator": "0.12.2",
|
||||
"reflect-metadata": "0.1.13",
|
||||
@@ -32,27 +32,27 @@
|
||||
"socket.io-redis": "5.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/socket.io": "2.1.11",
|
||||
"@types/socket.io": "2.1.12",
|
||||
"@types/socket.io-redis": "1.0.26",
|
||||
"@types/ws": "7.2.9",
|
||||
"@nestjs/cli": "7.5.1",
|
||||
"@nestjs/schematics": "7.2.1",
|
||||
"@nestjs/testing": "7.4.4",
|
||||
"@types/express": "4.17.8",
|
||||
"@types/node": "7.10.9",
|
||||
"@types/ws": "7.4.0",
|
||||
"@nestjs/cli": "7.5.3",
|
||||
"@nestjs/schematics": "7.2.5",
|
||||
"@nestjs/testing": "7.5.5",
|
||||
"@types/express": "4.17.9",
|
||||
"@types/node": "14.14.11",
|
||||
"@types/supertest": "2.0.10",
|
||||
"jest": "26.6.2",
|
||||
"prettier": "2.1.2",
|
||||
"supertest": "5.0.0",
|
||||
"ts-jest": "26.4.1",
|
||||
"ts-loader": "8.0.7",
|
||||
"ts-node": "9.0.0",
|
||||
"jest": "26.6.3",
|
||||
"prettier": "2.2.1",
|
||||
"supertest": "6.0.1",
|
||||
"ts-jest": "26.4.4",
|
||||
"ts-loader": "8.0.11",
|
||||
"ts-node": "9.1.1",
|
||||
"tsconfig-paths": "3.9.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.5.0",
|
||||
"@typescript-eslint/parser": "4.5.0",
|
||||
"eslint": "7.10.0",
|
||||
"eslint-config-prettier": "6.11.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.9.1",
|
||||
"@typescript-eslint/parser": "4.9.1",
|
||||
"eslint": "7.15.0",
|
||||
"eslint-config-prettier": "7.0.0",
|
||||
"eslint-plugin-import": "2.22.1",
|
||||
"typescript": "4.0.3"
|
||||
"typescript": "4.1.2"
|
||||
}
|
||||
}
|
||||
|
||||
25581
sample/03-microservices/package-lock.json
generated
25581
sample/03-microservices/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -19,10 +19,10 @@
|
||||
"test:e2e": "echo 'No e2e tests implemented yet.'"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/common": "7.4.4",
|
||||
"@nestjs/core": "7.4.4",
|
||||
"@nestjs/microservices": "7.4.4",
|
||||
"@nestjs/platform-express": "7.4.4",
|
||||
"@nestjs/common": "7.5.5",
|
||||
"@nestjs/core": "7.5.5",
|
||||
"@nestjs/microservices": "7.5.5",
|
||||
"@nestjs/platform-express": "7.5.5",
|
||||
"class-transformer": "0.3.1",
|
||||
"class-validator": "0.12.2",
|
||||
"reflect-metadata": "0.1.13",
|
||||
@@ -30,25 +30,25 @@
|
||||
"rxjs": "6.6.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/cli": "7.5.1",
|
||||
"@nestjs/schematics": "7.2.1",
|
||||
"@nestjs/testing": "7.4.4",
|
||||
"@nestjs/cli": "7.5.3",
|
||||
"@nestjs/schematics": "7.2.5",
|
||||
"@nestjs/testing": "7.5.5",
|
||||
"@types/amqplib": "0.5.16",
|
||||
"@types/express": "4.17.8",
|
||||
"@types/node": "12.12.31",
|
||||
"@types/express": "4.17.9",
|
||||
"@types/node": "14.14.11",
|
||||
"@types/supertest": "2.0.10",
|
||||
"jest": "26.6.2",
|
||||
"prettier": "2.1.2",
|
||||
"supertest": "5.0.0",
|
||||
"ts-jest": "26.4.1",
|
||||
"ts-loader": "8.0.7",
|
||||
"ts-node": "9.0.0",
|
||||
"jest": "26.6.3",
|
||||
"prettier": "2.2.1",
|
||||
"supertest": "6.0.1",
|
||||
"ts-jest": "26.4.4",
|
||||
"ts-loader": "8.0.11",
|
||||
"ts-node": "9.1.1",
|
||||
"tsconfig-paths": "3.9.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.5.0",
|
||||
"@typescript-eslint/parser": "4.5.0",
|
||||
"eslint": "7.10.0",
|
||||
"eslint-config-prettier": "6.11.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.9.1",
|
||||
"@typescript-eslint/parser": "4.9.1",
|
||||
"eslint": "7.15.0",
|
||||
"eslint-config-prettier": "7.0.0",
|
||||
"eslint-plugin-import": "2.22.1",
|
||||
"typescript": "4.0.3"
|
||||
"typescript": "4.1.2"
|
||||
}
|
||||
}
|
||||
|
||||
8122
sample/04-grpc/package-lock.json
generated
8122
sample/04-grpc/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -20,36 +20,36 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@grpc/proto-loader": "0.5.5",
|
||||
"@nestjs/common": "7.4.4",
|
||||
"@nestjs/core": "7.4.4",
|
||||
"@nestjs/microservices": "7.4.4",
|
||||
"@nestjs/common": "7.5.5",
|
||||
"@nestjs/core": "7.5.5",
|
||||
"@nestjs/microservices": "7.5.5",
|
||||
"class-transformer": "0.3.1",
|
||||
"class-validator": "0.12.2",
|
||||
"grpc": "1.24.3",
|
||||
"grpc": "1.24.4",
|
||||
"reflect-metadata": "0.1.13",
|
||||
"rimraf": "3.0.2",
|
||||
"rxjs": "6.6.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/cli": "7.5.1",
|
||||
"@nestjs/schematics": "7.2.1",
|
||||
"@nestjs/testing": "7.4.4",
|
||||
"@types/express": "4.17.8",
|
||||
"@types/node": "10.17.3",
|
||||
"@nestjs/cli": "7.5.3",
|
||||
"@nestjs/schematics": "7.2.5",
|
||||
"@nestjs/testing": "7.5.5",
|
||||
"@types/express": "4.17.9",
|
||||
"@types/node": "14.14.11",
|
||||
"@types/supertest": "2.0.10",
|
||||
"@types/ws": "7.2.9",
|
||||
"jest": "26.6.2",
|
||||
"prettier": "2.1.2",
|
||||
"supertest": "5.0.0",
|
||||
"ts-jest": "26.4.1",
|
||||
"ts-loader": "8.0.7",
|
||||
"ts-node": "9.0.0",
|
||||
"@types/ws": "7.4.0",
|
||||
"jest": "26.6.3",
|
||||
"prettier": "2.2.1",
|
||||
"supertest": "6.0.1",
|
||||
"ts-jest": "26.4.4",
|
||||
"ts-loader": "8.0.11",
|
||||
"ts-node": "9.1.1",
|
||||
"tsconfig-paths": "3.9.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.5.0",
|
||||
"@typescript-eslint/parser": "4.5.0",
|
||||
"eslint": "7.10.0",
|
||||
"eslint-config-prettier": "6.11.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.9.1",
|
||||
"@typescript-eslint/parser": "4.9.1",
|
||||
"eslint": "7.15.0",
|
||||
"eslint-config-prettier": "7.0.0",
|
||||
"eslint-plugin-import": "2.22.1",
|
||||
"typescript": "4.0.3"
|
||||
"typescript": "4.1.2"
|
||||
}
|
||||
}
|
||||
|
||||
8318
sample/05-sql-typeorm/package-lock.json
generated
8318
sample/05-sql-typeorm/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -19,36 +19,36 @@
|
||||
"test:e2e": "echo 'No e2e tests implemented yet.'"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/common": "7.4.4",
|
||||
"@nestjs/core": "7.4.4",
|
||||
"@nestjs/platform-express": "7.4.4",
|
||||
"@nestjs/typeorm": "7.1.4",
|
||||
"@nestjs/common": "7.5.5",
|
||||
"@nestjs/core": "7.5.5",
|
||||
"@nestjs/platform-express": "7.5.5",
|
||||
"@nestjs/typeorm": "7.1.5",
|
||||
"mysql": "2.18.1",
|
||||
"reflect-metadata": "0.1.13",
|
||||
"rimraf": "3.0.2",
|
||||
"rxjs": "6.6.3",
|
||||
"typeorm": "0.2.28"
|
||||
"typeorm": "0.2.29"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/cli": "7.5.1",
|
||||
"@nestjs/schematics": "7.2.1",
|
||||
"@nestjs/testing": "7.4.4",
|
||||
"@types/express": "4.17.8",
|
||||
"@types/node": "7.10.9",
|
||||
"@nestjs/cli": "7.5.3",
|
||||
"@nestjs/schematics": "7.2.5",
|
||||
"@nestjs/testing": "7.5.5",
|
||||
"@types/express": "4.17.9",
|
||||
"@types/node": "14.14.11",
|
||||
"@types/supertest": "2.0.10",
|
||||
"@types/ws": "7.2.9",
|
||||
"jest": "26.6.2",
|
||||
"prettier": "2.1.2",
|
||||
"supertest": "5.0.0",
|
||||
"ts-jest": "26.4.1",
|
||||
"ts-loader": "8.0.7",
|
||||
"ts-node": "9.0.0",
|
||||
"@types/ws": "7.4.0",
|
||||
"jest": "26.6.3",
|
||||
"prettier": "2.2.1",
|
||||
"supertest": "6.0.1",
|
||||
"ts-jest": "26.4.4",
|
||||
"ts-loader": "8.0.11",
|
||||
"ts-node": "9.1.1",
|
||||
"tsconfig-paths": "3.9.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.5.0",
|
||||
"@typescript-eslint/parser": "4.5.0",
|
||||
"eslint": "7.10.0",
|
||||
"eslint-config-prettier": "6.11.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.9.1",
|
||||
"@typescript-eslint/parser": "4.9.1",
|
||||
"eslint": "7.15.0",
|
||||
"eslint-config-prettier": "7.0.0",
|
||||
"eslint-plugin-import": "2.22.1",
|
||||
"typescript": "4.0.3"
|
||||
"typescript": "4.1.2"
|
||||
}
|
||||
}
|
||||
|
||||
8343
sample/06-mongoose/package-lock.json
generated
8343
sample/06-mongoose/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -19,36 +19,36 @@
|
||||
"test:e2e": "echo 'No e2e tests implemented yet.'"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/common": "7.4.4",
|
||||
"@nestjs/core": "7.4.4",
|
||||
"@nestjs/mongoose": "7.0.2",
|
||||
"@nestjs/platform-express": "7.4.4",
|
||||
"mongoose": "5.10.10",
|
||||
"@nestjs/common": "7.5.5",
|
||||
"@nestjs/core": "7.5.5",
|
||||
"@nestjs/mongoose": "7.2.0",
|
||||
"@nestjs/platform-express": "7.5.5",
|
||||
"mongoose": "5.11.6",
|
||||
"reflect-metadata": "0.1.13",
|
||||
"rimraf": "3.0.2",
|
||||
"rxjs": "6.6.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/mongoose": "5.7.36",
|
||||
"@nestjs/cli": "7.5.1",
|
||||
"@nestjs/schematics": "7.2.1",
|
||||
"@nestjs/testing": "7.4.4",
|
||||
"@types/express": "4.17.8",
|
||||
"@types/node": "12.12.31",
|
||||
"@types/mongoose": "5.10.2",
|
||||
"@nestjs/cli": "7.5.3",
|
||||
"@nestjs/schematics": "7.2.5",
|
||||
"@nestjs/testing": "7.5.5",
|
||||
"@types/express": "4.17.9",
|
||||
"@types/node": "14.14.11",
|
||||
"@types/supertest": "2.0.10",
|
||||
"@types/ws": "7.2.9",
|
||||
"jest": "26.6.2",
|
||||
"prettier": "2.1.2",
|
||||
"supertest": "5.0.0",
|
||||
"ts-jest": "26.4.1",
|
||||
"ts-loader": "8.0.7",
|
||||
"ts-node": "9.0.0",
|
||||
"@types/ws": "7.4.0",
|
||||
"jest": "26.6.3",
|
||||
"prettier": "2.2.1",
|
||||
"supertest": "6.0.1",
|
||||
"ts-jest": "26.4.4",
|
||||
"ts-loader": "8.0.11",
|
||||
"ts-node": "9.1.1",
|
||||
"tsconfig-paths": "3.9.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.5.0",
|
||||
"@typescript-eslint/parser": "4.5.0",
|
||||
"eslint": "7.10.0",
|
||||
"eslint-config-prettier": "6.11.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.9.1",
|
||||
"@typescript-eslint/parser": "4.9.1",
|
||||
"eslint": "7.15.0",
|
||||
"eslint-config-prettier": "7.0.0",
|
||||
"eslint-plugin-import": "2.22.1",
|
||||
"typescript": "4.0.3"
|
||||
"typescript": "4.1.2"
|
||||
}
|
||||
}
|
||||
|
||||
8485
sample/07-sequelize/package-lock.json
generated
8485
sample/07-sequelize/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -19,39 +19,39 @@
|
||||
"test:e2e": "echo 'No e2e tests implemented yet.'"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/common": "7.4.4",
|
||||
"@nestjs/core": "7.4.4",
|
||||
"@nestjs/platform-express": "7.4.4",
|
||||
"@nestjs/common": "7.5.5",
|
||||
"@nestjs/core": "7.5.5",
|
||||
"@nestjs/platform-express": "7.5.5",
|
||||
"@nestjs/sequelize": "0.1.1",
|
||||
"mysql2": "2.2.5",
|
||||
"reflect-metadata": "0.1.13",
|
||||
"rimraf": "3.0.2",
|
||||
"rxjs": "6.6.3",
|
||||
"sequelize": "5.22.3",
|
||||
"sequelize": "6.3.5",
|
||||
"sequelize-typescript": "1.1.0",
|
||||
"typescript": "4.0.3"
|
||||
"typescript": "4.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/sequelize": "4.28.9",
|
||||
"@nestjs/cli": "7.5.1",
|
||||
"@nestjs/schematics": "7.2.1",
|
||||
"@nestjs/testing": "7.4.4",
|
||||
"@types/express": "4.17.8",
|
||||
"@types/node": "12.12.31",
|
||||
"@nestjs/cli": "7.5.3",
|
||||
"@nestjs/schematics": "7.2.5",
|
||||
"@nestjs/testing": "7.5.5",
|
||||
"@types/express": "4.17.9",
|
||||
"@types/node": "14.14.11",
|
||||
"@types/supertest": "2.0.10",
|
||||
"@types/ws": "7.2.9",
|
||||
"jest": "26.6.2",
|
||||
"prettier": "2.1.2",
|
||||
"supertest": "5.0.0",
|
||||
"ts-jest": "26.4.1",
|
||||
"ts-loader": "8.0.7",
|
||||
"ts-node": "9.0.0",
|
||||
"@types/ws": "7.4.0",
|
||||
"jest": "26.6.3",
|
||||
"prettier": "2.2.1",
|
||||
"supertest": "6.0.1",
|
||||
"ts-jest": "26.4.4",
|
||||
"ts-loader": "8.0.11",
|
||||
"ts-node": "9.1.1",
|
||||
"tsconfig-paths": "3.9.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.5.0",
|
||||
"@typescript-eslint/parser": "4.5.0",
|
||||
"eslint": "7.10.0",
|
||||
"eslint-config-prettier": "6.11.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.9.1",
|
||||
"@typescript-eslint/parser": "4.9.1",
|
||||
"eslint": "7.15.0",
|
||||
"eslint-config-prettier": "7.0.0",
|
||||
"eslint-plugin-import": "2.22.1",
|
||||
"typescript": "4.0.3"
|
||||
"typescript": "4.1.2"
|
||||
}
|
||||
}
|
||||
|
||||
1068
sample/08-webpack/package-lock.json
generated
1068
sample/08-webpack/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -11,26 +11,26 @@
|
||||
"test:e2e": "echo 'No e2e tests implemented yet.'"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/common": "7.5.1",
|
||||
"@nestjs/core": "7.5.1",
|
||||
"@nestjs/platform-express": "7.5.1",
|
||||
"@nestjs/common": "7.5.5",
|
||||
"@nestjs/core": "7.5.5",
|
||||
"@nestjs/platform-express": "7.5.5",
|
||||
"reflect-metadata": "0.1.13",
|
||||
"rxjs": "6.6.3",
|
||||
"typescript": "4.0.5"
|
||||
"typescript": "4.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/cli": "7.5.2",
|
||||
"@nestjs/schematics": "7.2.1",
|
||||
"@types/node": "14.14.7",
|
||||
"@typescript-eslint/eslint-plugin": "4.6.1",
|
||||
"@typescript-eslint/parser": "4.6.1",
|
||||
"eslint": "7.12.1",
|
||||
"eslint-config-prettier": "6.15.0",
|
||||
"@nestjs/cli": "7.5.3",
|
||||
"@nestjs/schematics": "7.2.5",
|
||||
"@types/node": "14.14.11",
|
||||
"@typescript-eslint/eslint-plugin": "4.9.1",
|
||||
"@typescript-eslint/parser": "4.9.1",
|
||||
"eslint": "7.15.0",
|
||||
"eslint-config-prettier": "7.0.0",
|
||||
"eslint-plugin-import": "2.22.1",
|
||||
"start-server-webpack-plugin": "2.2.5",
|
||||
"ts-loader": "8.0.9",
|
||||
"ts-node": "9.0.0",
|
||||
"webpack": "5.4.0",
|
||||
"ts-loader": "8.0.11",
|
||||
"ts-node": "9.1.1",
|
||||
"webpack": "5.10.0",
|
||||
"webpack-cli": "4.2.0",
|
||||
"webpack-node-externals": "2.5.2"
|
||||
}
|
||||
|
||||
1029
sample/09-babel-example/package-lock.json
generated
1029
sample/09-babel-example/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -13,28 +13,28 @@
|
||||
"test:e2e": "echo 'No e2e tests implemented yet.'"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/common": "7.4.4",
|
||||
"@nestjs/core": "7.4.4",
|
||||
"@nestjs/platform-express": "7.4.4",
|
||||
"@nestjs/microservices": "7.4.4",
|
||||
"@nestjs/websockets": "7.4.4",
|
||||
"@nestjs/common": "7.5.5",
|
||||
"@nestjs/core": "7.5.5",
|
||||
"@nestjs/platform-express": "7.5.5",
|
||||
"@nestjs/microservices": "7.5.5",
|
||||
"@nestjs/websockets": "7.5.5",
|
||||
"reflect-metadata": "0.1.13",
|
||||
"rxjs": "6.6.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "7.12.8",
|
||||
"@babel/core": "7.12.9",
|
||||
"@babel/node": "7.12.6",
|
||||
"@babel/cli": "7.12.10",
|
||||
"@babel/core": "7.12.10",
|
||||
"@babel/node": "7.12.10",
|
||||
"@babel/plugin-proposal-decorators": "7.12.1",
|
||||
"@babel/plugin-transform-runtime": "7.12.1",
|
||||
"@babel/preset-env": "7.12.7",
|
||||
"@babel/register": "7.12.1",
|
||||
"@babel/plugin-transform-runtime": "7.12.10",
|
||||
"@babel/preset-env": "7.12.10",
|
||||
"@babel/register": "7.12.10",
|
||||
"@babel/runtime": "7.12.5",
|
||||
"@nestjs/testing": "7.4.4",
|
||||
"jest": "26.6.2",
|
||||
"@nestjs/testing": "7.5.5",
|
||||
"jest": "26.6.3",
|
||||
"nodemon": "2.0.6",
|
||||
"prettier": "2.1.2",
|
||||
"supertest": "5.0.0"
|
||||
"prettier": "2.2.1",
|
||||
"supertest": "6.0.1"
|
||||
},
|
||||
"jest": {
|
||||
"moduleFileExtensions": [
|
||||
|
||||
8560
sample/10-fastify/package-lock.json
generated
8560
sample/10-fastify/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -19,9 +19,9 @@
|
||||
"test:e2e": "echo 'No e2e tests implemented yet.'"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/common": "7.4.4",
|
||||
"@nestjs/core": "7.4.4",
|
||||
"@nestjs/platform-fastify": "7.4.4",
|
||||
"@nestjs/common": "7.5.5",
|
||||
"@nestjs/core": "7.5.5",
|
||||
"@nestjs/platform-fastify": "7.5.5",
|
||||
"class-transformer": "0.3.1",
|
||||
"class-validator": "0.12.2",
|
||||
"reflect-metadata": "0.1.13",
|
||||
@@ -29,25 +29,25 @@
|
||||
"rxjs": "6.6.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/cli": "7.5.1",
|
||||
"@nestjs/schematics": "7.2.1",
|
||||
"@nestjs/testing": "7.4.4",
|
||||
"@types/express": "4.17.8",
|
||||
"@types/node": "12.12.31",
|
||||
"@nestjs/cli": "7.5.3",
|
||||
"@nestjs/schematics": "7.2.5",
|
||||
"@nestjs/testing": "7.5.5",
|
||||
"@types/express": "4.17.9",
|
||||
"@types/node": "14.14.11",
|
||||
"@types/supertest": "2.0.10",
|
||||
"@types/ws": "7.2.9",
|
||||
"jest": "26.6.2",
|
||||
"prettier": "2.1.2",
|
||||
"supertest": "5.0.0",
|
||||
"ts-jest": "26.4.1",
|
||||
"ts-loader": "8.0.7",
|
||||
"ts-node": "9.0.0",
|
||||
"@types/ws": "7.4.0",
|
||||
"jest": "26.6.3",
|
||||
"prettier": "2.2.1",
|
||||
"supertest": "6.0.1",
|
||||
"ts-jest": "26.4.4",
|
||||
"ts-loader": "8.0.11",
|
||||
"ts-node": "9.1.1",
|
||||
"tsconfig-paths": "3.9.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.5.0",
|
||||
"@typescript-eslint/parser": "4.5.0",
|
||||
"eslint": "7.10.0",
|
||||
"eslint-config-prettier": "6.11.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.9.1",
|
||||
"@typescript-eslint/parser": "4.9.1",
|
||||
"eslint": "7.15.0",
|
||||
"eslint-config-prettier": "7.0.0",
|
||||
"eslint-plugin-import": "2.22.1",
|
||||
"typescript": "4.0.3"
|
||||
"typescript": "4.1.2"
|
||||
}
|
||||
}
|
||||
|
||||
8282
sample/11-swagger/package-lock.json
generated
8282
sample/11-swagger/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -19,36 +19,36 @@
|
||||
"test:e2e": "echo 'No e2e tests implemented yet.'"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/common": "7.4.4",
|
||||
"@nestjs/core": "7.4.4",
|
||||
"@nestjs/platform-express": "7.4.4",
|
||||
"@nestjs/swagger": "4.6.1",
|
||||
"@nestjs/common": "7.5.5",
|
||||
"@nestjs/core": "7.5.5",
|
||||
"@nestjs/platform-express": "7.5.5",
|
||||
"@nestjs/swagger": "4.7.5",
|
||||
"class-transformer": "0.3.1",
|
||||
"class-validator": "0.12.2",
|
||||
"reflect-metadata": "0.1.13",
|
||||
"rimraf": "3.0.2",
|
||||
"rxjs": "6.6.3",
|
||||
"swagger-ui-express": "4.1.4"
|
||||
"swagger-ui-express": "4.1.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/cli": "7.5.1",
|
||||
"@nestjs/schematics": "7.2.1",
|
||||
"@nestjs/testing": "7.4.4",
|
||||
"@types/express": "4.17.8",
|
||||
"@types/node": "10.17.3",
|
||||
"@nestjs/cli": "7.5.3",
|
||||
"@nestjs/schematics": "7.2.5",
|
||||
"@nestjs/testing": "7.5.5",
|
||||
"@types/express": "4.17.9",
|
||||
"@types/node": "14.14.11",
|
||||
"@types/supertest": "2.0.10",
|
||||
"jest": "26.6.2",
|
||||
"prettier": "2.1.2",
|
||||
"supertest": "5.0.0",
|
||||
"ts-jest": "26.4.1",
|
||||
"ts-loader": "8.0.7",
|
||||
"ts-node": "9.0.0",
|
||||
"jest": "26.6.3",
|
||||
"prettier": "2.2.1",
|
||||
"supertest": "6.0.1",
|
||||
"ts-jest": "26.4.4",
|
||||
"ts-loader": "8.0.11",
|
||||
"ts-node": "9.1.1",
|
||||
"tsconfig-paths": "3.9.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.5.0",
|
||||
"@typescript-eslint/parser": "4.5.0",
|
||||
"eslint": "7.10.0",
|
||||
"eslint-config-prettier": "6.11.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.9.1",
|
||||
"@typescript-eslint/parser": "4.9.1",
|
||||
"eslint": "7.15.0",
|
||||
"eslint-config-prettier": "7.0.0",
|
||||
"eslint-plugin-import": "2.22.1",
|
||||
"typescript": "4.0.3"
|
||||
"typescript": "4.1.2"
|
||||
}
|
||||
}
|
||||
|
||||
8893
sample/12-graphql-schema-first/package-lock.json
generated
8893
sample/12-graphql-schema-first/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -19,39 +19,39 @@
|
||||
"test:e2e": "echo 'No e2e tests implemented yet.'"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/common": "7.4.4",
|
||||
"@nestjs/core": "7.4.4",
|
||||
"@nestjs/graphql": "7.7.0",
|
||||
"@nestjs/platform-express": "7.4.4",
|
||||
"@nestjs/common": "7.5.5",
|
||||
"@nestjs/core": "7.5.5",
|
||||
"@nestjs/graphql": "7.9.1",
|
||||
"@nestjs/platform-express": "7.5.5",
|
||||
"apollo-server": "2.19.0",
|
||||
"apollo-server-express": "2.19.0",
|
||||
"class-transformer": "0.3.1",
|
||||
"class-validator": "0.12.2",
|
||||
"graphql": "15.3.0",
|
||||
"graphql": "15.4.0",
|
||||
"graphql-subscriptions": "1.1.0",
|
||||
"reflect-metadata": "0.1.13",
|
||||
"rimraf": "3.0.2",
|
||||
"rxjs": "6.6.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/cli": "7.5.1",
|
||||
"@nestjs/schematics": "7.2.1",
|
||||
"@nestjs/testing": "7.4.4",
|
||||
"@types/express": "4.17.8",
|
||||
"@types/node": "12.12.31",
|
||||
"@nestjs/cli": "7.5.3",
|
||||
"@nestjs/schematics": "7.2.5",
|
||||
"@nestjs/testing": "7.5.5",
|
||||
"@types/express": "4.17.9",
|
||||
"@types/node": "14.14.11",
|
||||
"@types/supertest": "2.0.10",
|
||||
"jest": "26.6.2",
|
||||
"prettier": "2.1.2",
|
||||
"supertest": "5.0.0",
|
||||
"ts-jest": "26.4.1",
|
||||
"ts-loader": "8.0.7",
|
||||
"ts-node": "9.0.0",
|
||||
"jest": "26.6.3",
|
||||
"prettier": "2.2.1",
|
||||
"supertest": "6.0.1",
|
||||
"ts-jest": "26.4.4",
|
||||
"ts-loader": "8.0.11",
|
||||
"ts-node": "9.1.1",
|
||||
"tsconfig-paths": "3.9.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.5.0",
|
||||
"@typescript-eslint/parser": "4.5.0",
|
||||
"eslint": "7.10.0",
|
||||
"eslint-config-prettier": "6.11.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.9.1",
|
||||
"@typescript-eslint/parser": "4.9.1",
|
||||
"eslint": "7.15.0",
|
||||
"eslint-config-prettier": "7.0.0",
|
||||
"eslint-plugin-import": "2.22.1",
|
||||
"typescript": "4.0.3"
|
||||
"typescript": "4.1.2"
|
||||
}
|
||||
}
|
||||
|
||||
8329
sample/13-mongo-typeorm/package-lock.json
generated
8329
sample/13-mongo-typeorm/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -19,35 +19,35 @@
|
||||
"test:e2e": "echo 'No e2e tests implemented yet.'"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/common": "7.4.4",
|
||||
"@nestjs/core": "7.4.4",
|
||||
"@nestjs/platform-express": "7.4.4",
|
||||
"@nestjs/typeorm": "7.1.4",
|
||||
"mongodb": "3.6.2",
|
||||
"@nestjs/common": "7.5.5",
|
||||
"@nestjs/core": "7.5.5",
|
||||
"@nestjs/platform-express": "7.5.5",
|
||||
"@nestjs/typeorm": "7.1.5",
|
||||
"mongodb": "3.6.3",
|
||||
"reflect-metadata": "0.1.13",
|
||||
"rimraf": "3.0.2",
|
||||
"rxjs": "6.6.3",
|
||||
"typeorm": "0.2.28"
|
||||
"typeorm": "0.2.29"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/cli": "7.5.1",
|
||||
"@nestjs/schematics": "7.2.1",
|
||||
"@nestjs/testing": "7.4.4",
|
||||
"@types/express": "4.17.8",
|
||||
"@types/node": "12.12.31",
|
||||
"@nestjs/cli": "7.5.3",
|
||||
"@nestjs/schematics": "7.2.5",
|
||||
"@nestjs/testing": "7.5.5",
|
||||
"@types/express": "4.17.9",
|
||||
"@types/node": "14.14.11",
|
||||
"@types/supertest": "2.0.10",
|
||||
"jest": "26.6.2",
|
||||
"prettier": "2.1.2",
|
||||
"supertest": "5.0.0",
|
||||
"ts-jest": "26.4.1",
|
||||
"ts-loader": "8.0.7",
|
||||
"ts-node": "9.0.0",
|
||||
"jest": "26.6.3",
|
||||
"prettier": "2.2.1",
|
||||
"supertest": "6.0.1",
|
||||
"ts-jest": "26.4.4",
|
||||
"ts-loader": "8.0.11",
|
||||
"ts-node": "9.1.1",
|
||||
"tsconfig-paths": "3.9.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.5.0",
|
||||
"@typescript-eslint/parser": "4.5.0",
|
||||
"eslint": "7.10.0",
|
||||
"eslint-config-prettier": "6.11.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.9.1",
|
||||
"@typescript-eslint/parser": "4.9.1",
|
||||
"eslint": "7.15.0",
|
||||
"eslint-config-prettier": "7.0.0",
|
||||
"eslint-plugin-import": "2.22.1",
|
||||
"typescript": "4.0.3"
|
||||
"typescript": "4.1.2"
|
||||
}
|
||||
}
|
||||
|
||||
8416
sample/14-mongoose-base/package-lock.json
generated
8416
sample/14-mongoose-base/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -19,33 +19,33 @@
|
||||
"test:e2e": "echo 'No e2e tests implemented yet.'"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/common": "7.4.4",
|
||||
"@nestjs/core": "7.4.4",
|
||||
"@nestjs/platform-express": "7.4.4",
|
||||
"mongoose": "5.10.10",
|
||||
"@nestjs/common": "7.5.5",
|
||||
"@nestjs/core": "7.5.5",
|
||||
"@nestjs/platform-express": "7.5.5",
|
||||
"mongoose": "5.11.6",
|
||||
"reflect-metadata": "0.1.13",
|
||||
"rimraf": "3.0.2",
|
||||
"rxjs": "6.6.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/cli": "7.5.1",
|
||||
"@nestjs/schematics": "7.2.1",
|
||||
"@nestjs/testing": "7.4.4",
|
||||
"@types/express": "4.17.8",
|
||||
"@types/node": "7.10.9",
|
||||
"@nestjs/cli": "7.5.3",
|
||||
"@nestjs/schematics": "7.2.5",
|
||||
"@nestjs/testing": "7.5.5",
|
||||
"@types/express": "4.17.9",
|
||||
"@types/node": "14.14.11",
|
||||
"@types/supertest": "2.0.10",
|
||||
"jest": "26.6.2",
|
||||
"prettier": "2.1.2",
|
||||
"supertest": "5.0.0",
|
||||
"ts-jest": "26.4.1",
|
||||
"ts-loader": "8.0.7",
|
||||
"ts-node": "9.0.0",
|
||||
"jest": "26.6.3",
|
||||
"prettier": "2.2.1",
|
||||
"supertest": "6.0.1",
|
||||
"ts-jest": "26.4.4",
|
||||
"ts-loader": "8.0.11",
|
||||
"ts-node": "9.1.1",
|
||||
"tsconfig-paths": "3.9.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.5.0",
|
||||
"@typescript-eslint/parser": "4.5.0",
|
||||
"eslint": "7.10.0",
|
||||
"eslint-config-prettier": "6.11.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.9.1",
|
||||
"@typescript-eslint/parser": "4.9.1",
|
||||
"eslint": "7.15.0",
|
||||
"eslint-config-prettier": "7.0.0",
|
||||
"eslint-plugin-import": "2.22.1",
|
||||
"typescript": "4.0.3"
|
||||
"typescript": "4.1.2"
|
||||
}
|
||||
}
|
||||
|
||||
8738
sample/15-mvc/package-lock.json
generated
8738
sample/15-mvc/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -19,9 +19,9 @@
|
||||
"test:e2e": "echo 'No e2e tests implemented yet.'"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/common": "7.4.4",
|
||||
"@nestjs/core": "7.4.4",
|
||||
"@nestjs/platform-express": "7.4.4",
|
||||
"@nestjs/common": "7.5.5",
|
||||
"@nestjs/core": "7.5.5",
|
||||
"@nestjs/platform-express": "7.5.5",
|
||||
"hbs": "4.1.1",
|
||||
"pug": "3.0.0",
|
||||
"reflect-metadata": "0.1.13",
|
||||
@@ -29,24 +29,24 @@
|
||||
"rxjs": "6.6.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/cli": "7.5.1",
|
||||
"@nestjs/schematics": "7.2.1",
|
||||
"@nestjs/testing": "7.4.4",
|
||||
"@types/express": "4.17.8",
|
||||
"@types/node": "8.10.58",
|
||||
"@nestjs/cli": "7.5.3",
|
||||
"@nestjs/schematics": "7.2.5",
|
||||
"@nestjs/testing": "7.5.5",
|
||||
"@types/express": "4.17.9",
|
||||
"@types/node": "14.14.11",
|
||||
"@types/supertest": "2.0.10",
|
||||
"jest": "26.6.2",
|
||||
"prettier": "2.1.2",
|
||||
"supertest": "5.0.0",
|
||||
"ts-jest": "26.4.1",
|
||||
"ts-loader": "8.0.7",
|
||||
"ts-node": "9.0.0",
|
||||
"jest": "26.6.3",
|
||||
"prettier": "2.2.1",
|
||||
"supertest": "6.0.1",
|
||||
"ts-jest": "26.4.4",
|
||||
"ts-loader": "8.0.11",
|
||||
"ts-node": "9.1.1",
|
||||
"tsconfig-paths": "3.9.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.5.0",
|
||||
"@typescript-eslint/parser": "4.5.0",
|
||||
"eslint": "7.10.0",
|
||||
"eslint-config-prettier": "6.11.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.9.1",
|
||||
"@typescript-eslint/parser": "4.9.1",
|
||||
"eslint": "7.15.0",
|
||||
"eslint-config-prettier": "7.0.0",
|
||||
"eslint-plugin-import": "2.22.1",
|
||||
"typescript": "4.0.3"
|
||||
"typescript": "4.1.2"
|
||||
}
|
||||
}
|
||||
|
||||
8332
sample/16-gateways-ws/package-lock.json
generated
8332
sample/16-gateways-ws/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -19,38 +19,38 @@
|
||||
"test:e2e": "echo 'No e2e tests implemented yet.'"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/common": "7.4.4",
|
||||
"@nestjs/core": "7.4.4",
|
||||
"@nestjs/platform-express": "7.4.4",
|
||||
"@nestjs/platform-ws": "7.4.4",
|
||||
"@nestjs/websockets": "7.4.4",
|
||||
"@nestjs/common": "7.5.5",
|
||||
"@nestjs/core": "7.5.5",
|
||||
"@nestjs/platform-express": "7.5.5",
|
||||
"@nestjs/platform-ws": "7.5.5",
|
||||
"@nestjs/websockets": "7.5.5",
|
||||
"class-transformer": "0.3.1",
|
||||
"class-validator": "0.12.2",
|
||||
"rimraf": "3.0.2",
|
||||
"reflect-metadata": "0.1.13",
|
||||
"rxjs": "6.6.3",
|
||||
"ws": "7.3.1"
|
||||
"ws": "7.4.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/ws": "7.2.9",
|
||||
"@nestjs/cli": "7.5.1",
|
||||
"@nestjs/schematics": "7.2.1",
|
||||
"@nestjs/testing": "7.4.4",
|
||||
"@types/express": "4.17.8",
|
||||
"@types/node": "12.12.31",
|
||||
"@types/ws": "7.4.0",
|
||||
"@nestjs/cli": "7.5.3",
|
||||
"@nestjs/schematics": "7.2.5",
|
||||
"@nestjs/testing": "7.5.5",
|
||||
"@types/express": "4.17.9",
|
||||
"@types/node": "14.14.11",
|
||||
"@types/supertest": "2.0.10",
|
||||
"jest": "26.6.2",
|
||||
"prettier": "2.1.2",
|
||||
"supertest": "5.0.0",
|
||||
"ts-jest": "26.4.1",
|
||||
"ts-loader": "8.0.7",
|
||||
"ts-node": "9.0.0",
|
||||
"jest": "26.6.3",
|
||||
"prettier": "2.2.1",
|
||||
"supertest": "6.0.1",
|
||||
"ts-jest": "26.4.4",
|
||||
"ts-loader": "8.0.11",
|
||||
"ts-node": "9.1.1",
|
||||
"tsconfig-paths": "3.9.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.5.0",
|
||||
"@typescript-eslint/parser": "4.5.0",
|
||||
"eslint": "7.10.0",
|
||||
"eslint-config-prettier": "6.11.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.9.1",
|
||||
"@typescript-eslint/parser": "4.9.1",
|
||||
"eslint": "7.15.0",
|
||||
"eslint-config-prettier": "7.0.0",
|
||||
"eslint-plugin-import": "2.22.1",
|
||||
"typescript": "4.0.3"
|
||||
"typescript": "4.1.2"
|
||||
}
|
||||
}
|
||||
|
||||
8745
sample/17-mvc-fastify/package-lock.json
generated
8745
sample/17-mvc-fastify/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -19,38 +19,38 @@
|
||||
"test:e2e": "echo 'No e2e tests implemented yet.'"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/common": "7.4.4",
|
||||
"@nestjs/core": "7.4.4",
|
||||
"@nestjs/platform-fastify": "7.4.4",
|
||||
"fastify-static": "3.2.1",
|
||||
"@nestjs/common": "7.5.5",
|
||||
"@nestjs/core": "7.5.5",
|
||||
"@nestjs/platform-fastify": "7.5.5",
|
||||
"fastify-static": "3.3.0",
|
||||
"handlebars": "4.7.6",
|
||||
"point-of-view": "4.6.0",
|
||||
"point-of-view": "4.7.0",
|
||||
"reflect-metadata": "0.1.13",
|
||||
"rimraf": "3.0.2",
|
||||
"rxjs": "6.6.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/socket.io": "2.1.11",
|
||||
"@types/socket.io": "2.1.12",
|
||||
"@types/socket.io-redis": "1.0.26",
|
||||
"@types/ws": "7.2.9",
|
||||
"@nestjs/cli": "7.5.1",
|
||||
"@nestjs/schematics": "7.2.1",
|
||||
"@nestjs/testing": "7.4.4",
|
||||
"@types/express": "4.17.8",
|
||||
"@types/node": "8.10.58",
|
||||
"@types/ws": "7.4.0",
|
||||
"@nestjs/cli": "7.5.3",
|
||||
"@nestjs/schematics": "7.2.5",
|
||||
"@nestjs/testing": "7.5.5",
|
||||
"@types/express": "4.17.9",
|
||||
"@types/node": "14.14.11",
|
||||
"@types/supertest": "2.0.10",
|
||||
"jest": "26.6.2",
|
||||
"prettier": "2.1.2",
|
||||
"supertest": "5.0.0",
|
||||
"ts-jest": "26.4.1",
|
||||
"ts-loader": "8.0.7",
|
||||
"ts-node": "9.0.0",
|
||||
"jest": "26.6.3",
|
||||
"prettier": "2.2.1",
|
||||
"supertest": "6.0.1",
|
||||
"ts-jest": "26.4.4",
|
||||
"ts-loader": "8.0.11",
|
||||
"ts-node": "9.1.1",
|
||||
"tsconfig-paths": "3.9.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.5.0",
|
||||
"@typescript-eslint/parser": "4.5.0",
|
||||
"eslint": "7.10.0",
|
||||
"eslint-config-prettier": "6.11.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.9.1",
|
||||
"@typescript-eslint/parser": "4.9.1",
|
||||
"eslint": "7.15.0",
|
||||
"eslint-config-prettier": "7.0.0",
|
||||
"eslint-plugin-import": "2.22.1",
|
||||
"typescript": "4.0.3"
|
||||
"typescript": "4.1.2"
|
||||
}
|
||||
}
|
||||
|
||||
7840
sample/18-context/package-lock.json
generated
7840
sample/18-context/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -19,29 +19,29 @@
|
||||
"test:e2e": "echo 'No e2e tests implemented yet.'"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/common": "7.4.4",
|
||||
"@nestjs/core": "7.4.4",
|
||||
"@nestjs/common": "7.5.5",
|
||||
"@nestjs/core": "7.5.5",
|
||||
"reflect-metadata": "0.1.13",
|
||||
"rimraf": "3.0.2",
|
||||
"rxjs": "6.6.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/cli": "7.5.1",
|
||||
"@nestjs/schematics": "7.2.1",
|
||||
"@types/node": "12.12.31",
|
||||
"@nestjs/cli": "7.5.3",
|
||||
"@nestjs/schematics": "7.2.5",
|
||||
"@types/node": "14.14.11",
|
||||
"@types/supertest": "2.0.10",
|
||||
"jest": "26.6.2",
|
||||
"prettier": "2.1.2",
|
||||
"supertest": "5.0.0",
|
||||
"ts-jest": "26.4.1",
|
||||
"ts-loader": "8.0.7",
|
||||
"ts-node": "9.0.0",
|
||||
"jest": "26.6.3",
|
||||
"prettier": "2.2.1",
|
||||
"supertest": "6.0.1",
|
||||
"ts-jest": "26.4.4",
|
||||
"ts-loader": "8.0.11",
|
||||
"ts-node": "9.1.1",
|
||||
"tsconfig-paths": "3.9.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.5.0",
|
||||
"@typescript-eslint/parser": "4.5.0",
|
||||
"eslint": "7.10.0",
|
||||
"eslint-config-prettier": "6.11.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.9.1",
|
||||
"@typescript-eslint/parser": "4.9.1",
|
||||
"eslint": "7.15.0",
|
||||
"eslint-config-prettier": "7.0.0",
|
||||
"eslint-plugin-import": "2.22.1",
|
||||
"typescript": "4.0.3"
|
||||
"typescript": "4.1.2"
|
||||
}
|
||||
}
|
||||
|
||||
8230
sample/19-auth-jwt/package-lock.json
generated
8230
sample/19-auth-jwt/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -20,11 +20,11 @@
|
||||
"test:e2e": "jest --config ./e2e/jest-e2e.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/common": "7.4.4",
|
||||
"@nestjs/core": "7.4.4",
|
||||
"@nestjs/jwt": "7.1.0",
|
||||
"@nestjs/passport": "7.1.0",
|
||||
"@nestjs/platform-express": "7.4.4",
|
||||
"@nestjs/common": "7.5.5",
|
||||
"@nestjs/core": "7.5.5",
|
||||
"@nestjs/jwt": "7.2.0",
|
||||
"@nestjs/passport": "7.1.5",
|
||||
"@nestjs/platform-express": "7.5.5",
|
||||
"passport": "0.4.1",
|
||||
"passport-jwt": "4.0.0",
|
||||
"passport-local": "1.0.0",
|
||||
@@ -33,26 +33,26 @@
|
||||
"rxjs": "6.6.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/cli": "7.5.1",
|
||||
"@nestjs/schematics": "7.2.1",
|
||||
"@nestjs/testing": "7.4.4",
|
||||
"@types/express": "4.17.8",
|
||||
"@types/jest": "26.0.15",
|
||||
"@types/node": "12.12.31",
|
||||
"@nestjs/cli": "7.5.3",
|
||||
"@nestjs/schematics": "7.2.5",
|
||||
"@nestjs/testing": "7.5.5",
|
||||
"@types/express": "4.17.9",
|
||||
"@types/jest": "26.0.18",
|
||||
"@types/node": "14.14.11",
|
||||
"@types/supertest": "2.0.10",
|
||||
"jest": "26.6.2",
|
||||
"prettier": "2.1.2",
|
||||
"supertest": "5.0.0",
|
||||
"ts-jest": "26.4.1",
|
||||
"ts-loader": "8.0.7",
|
||||
"ts-node": "9.0.0",
|
||||
"jest": "26.6.3",
|
||||
"prettier": "2.2.1",
|
||||
"supertest": "6.0.1",
|
||||
"ts-jest": "26.4.4",
|
||||
"ts-loader": "8.0.11",
|
||||
"ts-node": "9.1.1",
|
||||
"tsconfig-paths": "3.9.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.5.0",
|
||||
"@typescript-eslint/parser": "4.5.0",
|
||||
"eslint": "7.10.0",
|
||||
"eslint-config-prettier": "6.11.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.9.1",
|
||||
"@typescript-eslint/parser": "4.9.1",
|
||||
"eslint": "7.15.0",
|
||||
"eslint-config-prettier": "7.0.0",
|
||||
"eslint-plugin-import": "2.22.1",
|
||||
"typescript": "4.0.3"
|
||||
"typescript": "4.1.2"
|
||||
},
|
||||
"jest": {
|
||||
"moduleFileExtensions": [
|
||||
|
||||
9112
sample/20-cache/package-lock.json
generated
9112
sample/20-cache/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -19,9 +19,9 @@
|
||||
"test:e2e": "echo 'No e2e tests implemented yet.'"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/common": "7.4.4",
|
||||
"@nestjs/core": "7.4.4",
|
||||
"@nestjs/platform-express": "7.4.4",
|
||||
"@nestjs/common": "7.5.5",
|
||||
"@nestjs/core": "7.5.5",
|
||||
"@nestjs/platform-express": "7.5.5",
|
||||
"cache-manager-redis-store": "2.0.0",
|
||||
"class-transformer": "0.3.1",
|
||||
"class-validator": "0.12.2",
|
||||
@@ -29,24 +29,24 @@
|
||||
"rxjs": "6.6.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/cli": "7.5.1",
|
||||
"@nestjs/schematics": "7.2.1",
|
||||
"@nestjs/testing": "7.4.4",
|
||||
"@types/express": "4.17.8",
|
||||
"@types/node": "12.12.31",
|
||||
"@nestjs/cli": "7.5.3",
|
||||
"@nestjs/schematics": "7.2.5",
|
||||
"@nestjs/testing": "7.5.5",
|
||||
"@types/express": "4.17.9",
|
||||
"@types/node": "14.14.11",
|
||||
"@types/supertest": "2.0.10",
|
||||
"jest": "26.6.2",
|
||||
"prettier": "2.1.2",
|
||||
"supertest": "5.0.0",
|
||||
"ts-jest": "26.4.1",
|
||||
"ts-loader": "8.0.7",
|
||||
"ts-node": "9.0.0",
|
||||
"jest": "26.6.3",
|
||||
"prettier": "2.2.1",
|
||||
"supertest": "6.0.1",
|
||||
"ts-jest": "26.4.4",
|
||||
"ts-loader": "8.0.11",
|
||||
"ts-node": "9.1.1",
|
||||
"tsconfig-paths": "3.9.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.5.0",
|
||||
"@typescript-eslint/parser": "4.5.0",
|
||||
"eslint": "7.10.0",
|
||||
"eslint-config-prettier": "6.11.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.9.1",
|
||||
"@typescript-eslint/parser": "4.9.1",
|
||||
"eslint": "7.15.0",
|
||||
"eslint-config-prettier": "7.0.0",
|
||||
"eslint-plugin-import": "2.22.1",
|
||||
"typescript": "4.0.3"
|
||||
"typescript": "4.1.2"
|
||||
}
|
||||
}
|
||||
|
||||
9106
sample/21-serializer/package-lock.json
generated
9106
sample/21-serializer/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -19,33 +19,33 @@
|
||||
"test:e2e": "echo 'No e2e tests implemented yet.'"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/common": "7.4.4",
|
||||
"@nestjs/core": "7.4.4",
|
||||
"@nestjs/platform-express": "7.4.4",
|
||||
"@nestjs/common": "7.5.5",
|
||||
"@nestjs/core": "7.5.5",
|
||||
"@nestjs/platform-express": "7.5.5",
|
||||
"class-transformer": "0.3.1",
|
||||
"reflect-metadata": "0.1.13",
|
||||
"rimraf": "3.0.2",
|
||||
"rxjs": "6.6.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/cli": "7.5.1",
|
||||
"@nestjs/schematics": "7.2.1",
|
||||
"@nestjs/testing": "7.4.4",
|
||||
"@types/express": "4.17.8",
|
||||
"@types/node": "12.12.31",
|
||||
"@nestjs/cli": "7.5.3",
|
||||
"@nestjs/schematics": "7.2.5",
|
||||
"@nestjs/testing": "7.5.5",
|
||||
"@types/express": "4.17.9",
|
||||
"@types/node": "14.14.11",
|
||||
"@types/supertest": "2.0.10",
|
||||
"jest": "26.6.2",
|
||||
"prettier": "2.1.2",
|
||||
"supertest": "5.0.0",
|
||||
"ts-jest": "26.4.1",
|
||||
"ts-loader": "8.0.7",
|
||||
"ts-node": "9.0.0",
|
||||
"jest": "26.6.3",
|
||||
"prettier": "2.2.1",
|
||||
"supertest": "6.0.1",
|
||||
"ts-jest": "26.4.4",
|
||||
"ts-loader": "8.0.11",
|
||||
"ts-node": "9.1.1",
|
||||
"tsconfig-paths": "3.9.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.5.0",
|
||||
"@typescript-eslint/parser": "4.5.0",
|
||||
"eslint": "7.10.0",
|
||||
"eslint-config-prettier": "6.11.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.9.1",
|
||||
"@typescript-eslint/parser": "4.9.1",
|
||||
"eslint": "7.15.0",
|
||||
"eslint-config-prettier": "7.0.0",
|
||||
"eslint-plugin-import": "2.22.1",
|
||||
"typescript": "4.0.3"
|
||||
"typescript": "4.1.2"
|
||||
}
|
||||
}
|
||||
|
||||
10850
sample/22-graphql-prisma/package-lock.json
generated
10850
sample/22-graphql-prisma/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -19,37 +19,37 @@
|
||||
"test:e2e": "echo 'No e2e tests implemented yet.'"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/common": "7.4.4",
|
||||
"@nestjs/core": "7.4.4",
|
||||
"@nestjs/graphql": "7.7.0",
|
||||
"@nestjs/platform-express": "7.4.4",
|
||||
"@nestjs/common": "7.5.5",
|
||||
"@nestjs/core": "7.5.5",
|
||||
"@nestjs/graphql": "7.9.1",
|
||||
"@nestjs/platform-express": "7.5.5",
|
||||
"apollo-server-express": "2.19.0",
|
||||
"graphql": "15.3.0",
|
||||
"graphql-tools": "6.2.4",
|
||||
"graphql": "15.4.0",
|
||||
"graphql-tools": "7.0.2",
|
||||
"prisma-binding": "2.3.16",
|
||||
"reflect-metadata": "0.1.13",
|
||||
"rimraf": "3.0.2",
|
||||
"rxjs": "6.6.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/cli": "7.5.1",
|
||||
"@nestjs/schematics": "7.2.1",
|
||||
"@nestjs/testing": "7.4.4",
|
||||
"@types/express": "4.17.8",
|
||||
"@types/node": "12.12.31",
|
||||
"@nestjs/cli": "7.5.3",
|
||||
"@nestjs/schematics": "7.2.5",
|
||||
"@nestjs/testing": "7.5.5",
|
||||
"@types/express": "4.17.9",
|
||||
"@types/node": "14.14.11",
|
||||
"@types/supertest": "2.0.10",
|
||||
"jest": "26.6.2",
|
||||
"prettier": "2.1.2",
|
||||
"supertest": "5.0.0",
|
||||
"ts-jest": "26.4.1",
|
||||
"ts-loader": "8.0.7",
|
||||
"ts-node": "9.0.0",
|
||||
"jest": "26.6.3",
|
||||
"prettier": "2.2.1",
|
||||
"supertest": "6.0.1",
|
||||
"ts-jest": "26.4.4",
|
||||
"ts-loader": "8.0.11",
|
||||
"ts-node": "9.1.1",
|
||||
"tsconfig-paths": "3.9.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.5.0",
|
||||
"@typescript-eslint/parser": "4.5.0",
|
||||
"eslint": "7.10.0",
|
||||
"eslint-config-prettier": "6.11.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.9.1",
|
||||
"@typescript-eslint/parser": "4.9.1",
|
||||
"eslint": "7.15.0",
|
||||
"eslint-config-prettier": "7.0.0",
|
||||
"eslint-plugin-import": "2.22.1",
|
||||
"typescript": "4.0.3"
|
||||
"typescript": "4.1.2"
|
||||
}
|
||||
}
|
||||
|
||||
8464
sample/23-graphql-code-first/package-lock.json
generated
8464
sample/23-graphql-code-first/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user